147c08596SBrooks Davis /* $OpenBSD: dispatch.c,v 1.31 2004/09/21 04:07:03 david Exp $ */ 247c08596SBrooks Davis 38a16b7a1SPedro F. Giffuni /*- 48a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 58a16b7a1SPedro F. Giffuni * 647c08596SBrooks Davis * Copyright 2004 Henning Brauer <henning@openbsd.org> 747c08596SBrooks Davis * Copyright (c) 1995, 1996, 1997, 1998, 1999 847c08596SBrooks Davis * The Internet Software Consortium. All rights reserved. 947c08596SBrooks Davis * 1047c08596SBrooks Davis * Redistribution and use in source and binary forms, with or without 1147c08596SBrooks Davis * modification, are permitted provided that the following conditions 1247c08596SBrooks Davis * are met: 1347c08596SBrooks Davis * 1447c08596SBrooks Davis * 1. Redistributions of source code must retain the above copyright 1547c08596SBrooks Davis * notice, this list of conditions and the following disclaimer. 1647c08596SBrooks Davis * 2. Redistributions in binary form must reproduce the above copyright 1747c08596SBrooks Davis * notice, this list of conditions and the following disclaimer in the 1847c08596SBrooks Davis * documentation and/or other materials provided with the distribution. 1947c08596SBrooks Davis * 3. Neither the name of The Internet Software Consortium nor the names 2047c08596SBrooks Davis * of its contributors may be used to endorse or promote products derived 2147c08596SBrooks Davis * from this software without specific prior written permission. 2247c08596SBrooks Davis * 2347c08596SBrooks Davis * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND 2447c08596SBrooks Davis * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 2547c08596SBrooks Davis * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 2647c08596SBrooks Davis * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 2747c08596SBrooks Davis * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR 2847c08596SBrooks Davis * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2947c08596SBrooks Davis * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3047c08596SBrooks Davis * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 3147c08596SBrooks Davis * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 3247c08596SBrooks Davis * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 3347c08596SBrooks Davis * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 3447c08596SBrooks Davis * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3547c08596SBrooks Davis * SUCH DAMAGE. 3647c08596SBrooks Davis * 3747c08596SBrooks Davis * This software has been written for the Internet Software Consortium 3847c08596SBrooks Davis * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie 3947c08596SBrooks Davis * Enterprises. To learn more about the Internet Software Consortium, 4047c08596SBrooks Davis * see ``http://www.vix.com/isc''. To learn more about Vixie 4147c08596SBrooks Davis * Enterprises, see ``http://www.vix.com''. 4247c08596SBrooks Davis */ 4347c08596SBrooks Davis 448794fdbbSBrooks Davis #include <sys/cdefs.h> 4547c08596SBrooks Davis #include "dhcpd.h" 46387016a5SConrad Meyer #include "privsep.h" 4747c08596SBrooks Davis 4847c08596SBrooks Davis #include <sys/ioctl.h> 4947c08596SBrooks Davis 5079a1d195SAlan Somers #include <assert.h> 5147c08596SBrooks Davis #include <net/if_media.h> 5247c08596SBrooks Davis #include <ifaddrs.h> 5347c08596SBrooks Davis #include <poll.h> 5447c08596SBrooks Davis 5579a1d195SAlan Somers /* Assert that pointer p is aligned to at least align bytes */ 5679a1d195SAlan Somers #define assert_aligned(p, align) assert((((uintptr_t)p) & ((align) - 1)) == 0) 5779a1d195SAlan Somers 5871c6c44dSEitan Adler static struct protocol *protocols; 59*f0a38976SIsaac Cilia Attard static const struct timespec timespec_intmax_ms = { 60*f0a38976SIsaac Cilia Attard .tv_sec = INT_MAX / 1000, 61*f0a38976SIsaac Cilia Attard .tv_nsec = (INT_MAX % 1000) * 1000000 62*f0a38976SIsaac Cilia Attard }; 6371c6c44dSEitan Adler static struct timeout *timeouts; 6447c08596SBrooks Davis static struct timeout *free_timeouts; 6547c08596SBrooks Davis static int interfaces_invalidated; 6647c08596SBrooks Davis void (*bootp_packet_handler)(struct interface_info *, 6747c08596SBrooks Davis struct dhcp_packet *, int, unsigned int, 6847c08596SBrooks Davis struct iaddr, struct hardware *); 6947c08596SBrooks Davis 7047c08596SBrooks Davis static int interface_status(struct interface_info *ifinfo); 7147c08596SBrooks Davis 7247c08596SBrooks Davis /* 7347c08596SBrooks Davis * Use getifaddrs() to get a list of all the attached interfaces. For 7447c08596SBrooks Davis * each interface that's of type INET and not the loopback interface, 7547c08596SBrooks Davis * register that interface with the network I/O software, figure out 7647c08596SBrooks Davis * what subnet it's on, and add it to the list of interfaces. 7747c08596SBrooks Davis */ 7847c08596SBrooks Davis void 7947c08596SBrooks Davis discover_interfaces(struct interface_info *iface) 8047c08596SBrooks Davis { 8147c08596SBrooks Davis struct ifaddrs *ifap, *ifa; 8247c08596SBrooks Davis struct ifreq *tif; 8347c08596SBrooks Davis 8447c08596SBrooks Davis if (getifaddrs(&ifap) != 0) 8547c08596SBrooks Davis error("getifaddrs failed"); 8647c08596SBrooks Davis 8747c08596SBrooks Davis for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 8847c08596SBrooks Davis if ((ifa->ifa_flags & IFF_LOOPBACK) || 8947c08596SBrooks Davis (ifa->ifa_flags & IFF_POINTOPOINT) || 9047c08596SBrooks Davis (!(ifa->ifa_flags & IFF_UP))) 9147c08596SBrooks Davis continue; 9247c08596SBrooks Davis 9347c08596SBrooks Davis if (strcmp(iface->name, ifa->ifa_name)) 9447c08596SBrooks Davis continue; 9547c08596SBrooks Davis 9647c08596SBrooks Davis /* 9747c08596SBrooks Davis * If we have the capability, extract link information 9847c08596SBrooks Davis * and record it in a linked list. 9947c08596SBrooks Davis */ 10047c08596SBrooks Davis if (ifa->ifa_addr->sa_family == AF_LINK) { 10179a1d195SAlan Somers struct sockaddr_dl *foo; 10279a1d195SAlan Somers 10379a1d195SAlan Somers /* 10479a1d195SAlan Somers * The implementation of getifaddrs should guarantee 10579a1d195SAlan Somers * this alignment 10679a1d195SAlan Somers */ 10779a1d195SAlan Somers assert_aligned(ifa->ifa_addr, 10879a1d195SAlan Somers _Alignof(struct sockaddr_dl)); 10979a1d195SAlan Somers #ifdef __clang__ 11079a1d195SAlan Somers #pragma clang diagnostic push 11179a1d195SAlan Somers #pragma clang diagnostic ignored "-Wcast-align" 11279a1d195SAlan Somers #endif 11379a1d195SAlan Somers foo = (struct sockaddr_dl *)ifa->ifa_addr; 11479a1d195SAlan Somers #ifdef __clang__ 11579a1d195SAlan Somers #pragma clang diagnostic pop 11679a1d195SAlan Somers #endif 11747c08596SBrooks Davis 11847c08596SBrooks Davis iface->index = foo->sdl_index; 11947c08596SBrooks Davis iface->hw_address.hlen = foo->sdl_alen; 12047c08596SBrooks Davis iface->hw_address.htype = HTYPE_ETHER; /* XXX */ 12147c08596SBrooks Davis memcpy(iface->hw_address.haddr, 12247c08596SBrooks Davis LLADDR(foo), foo->sdl_alen); 123e2dc8d78SAlexander V. Chernikov } 12447c08596SBrooks Davis if (!iface->ifp) { 125a2e65d45SBrooks Davis if ((tif = calloc(1, sizeof(struct ifreq))) == NULL) 12647c08596SBrooks Davis error("no space to remember ifp"); 12747c08596SBrooks Davis strlcpy(tif->ifr_name, ifa->ifa_name, IFNAMSIZ); 12847c08596SBrooks Davis iface->ifp = tif; 12947c08596SBrooks Davis } 130e2dc8d78SAlexander V. Chernikov 13147c08596SBrooks Davis } 13247c08596SBrooks Davis 13347c08596SBrooks Davis if (!iface->ifp) 13447c08596SBrooks Davis error("%s: not found", iface->name); 13547c08596SBrooks Davis 13647c08596SBrooks Davis /* Register the interface... */ 13747c08596SBrooks Davis if_register_receive(iface); 13847c08596SBrooks Davis if_register_send(iface); 13947c08596SBrooks Davis add_protocol(iface->name, iface->rfdesc, got_one, iface); 14047c08596SBrooks Davis freeifaddrs(ifap); 14147c08596SBrooks Davis } 14247c08596SBrooks Davis 14347c08596SBrooks Davis void 14447c08596SBrooks Davis reinitialize_interfaces(void) 14547c08596SBrooks Davis { 14647c08596SBrooks Davis interfaces_invalidated = 1; 14747c08596SBrooks Davis } 14847c08596SBrooks Davis 14947c08596SBrooks Davis /* 15047c08596SBrooks Davis * Wait for packets to come in using poll(). When a packet comes in, 15147c08596SBrooks Davis * call receive_packet to receive the packet and possibly strip hardware 15247c08596SBrooks Davis * addressing information from it, and then call through the 15347c08596SBrooks Davis * bootp_packet_handler hook to try to do something with it. 15447c08596SBrooks Davis */ 15547c08596SBrooks Davis void 15647c08596SBrooks Davis dispatch(void) 15747c08596SBrooks Davis { 158f8c44adaSSam Leffler int count, live_interfaces, i, to_msec, nfds = 0; 15947c08596SBrooks Davis struct protocol *l; 16047c08596SBrooks Davis struct pollfd *fds; 16116a235f2SIsaac Cilia Attard struct timespec howlong; 16276e0ffd9SIsaac Cilia Attard time_now.tv_sec = cur_time; 16376e0ffd9SIsaac Cilia Attard time_now.tv_nsec = 0; 16447c08596SBrooks Davis 16547c08596SBrooks Davis for (l = protocols; l; l = l->next) 16647c08596SBrooks Davis nfds++; 16747c08596SBrooks Davis 16847c08596SBrooks Davis fds = malloc(nfds * sizeof(struct pollfd)); 16947c08596SBrooks Davis if (fds == NULL) 17047c08596SBrooks Davis error("Can't allocate poll structures."); 17147c08596SBrooks Davis 17247c08596SBrooks Davis do { 17347c08596SBrooks Davis /* 17447c08596SBrooks Davis * Call any expired timeouts, and then if there's still 17547c08596SBrooks Davis * a timeout registered, time out the select call then. 17647c08596SBrooks Davis */ 17747c08596SBrooks Davis another: 17847c08596SBrooks Davis if (timeouts) { 17947c08596SBrooks Davis struct timeout *t; 18047c08596SBrooks Davis 18116a235f2SIsaac Cilia Attard if (timespeccmp(&timeouts->when, &time_now, <=)) { 18247c08596SBrooks Davis t = timeouts; 18347c08596SBrooks Davis timeouts = timeouts->next; 18447c08596SBrooks Davis (*(t->func))(t->what); 18547c08596SBrooks Davis t->next = free_timeouts; 18647c08596SBrooks Davis free_timeouts = t; 18747c08596SBrooks Davis goto another; 18847c08596SBrooks Davis } 18947c08596SBrooks Davis 19047c08596SBrooks Davis /* 19147c08596SBrooks Davis * Figure timeout in milliseconds, and check for 19247c08596SBrooks Davis * potential overflow, so we can cram into an 19347c08596SBrooks Davis * int for poll, while not polling with a 19447c08596SBrooks Davis * negative timeout and blocking indefinitely. 19547c08596SBrooks Davis */ 19616a235f2SIsaac Cilia Attard timespecsub(&timeouts->when, &time_now, &howlong); 197*f0a38976SIsaac Cilia Attard if (timespeccmp(&howlong, ×pec_intmax_ms, >)) 198*f0a38976SIsaac Cilia Attard howlong = timespec_intmax_ms; 199*f0a38976SIsaac Cilia Attard to_msec = howlong.tv_sec * 1000 + howlong.tv_nsec / 1000000; 20047c08596SBrooks Davis } else 20147c08596SBrooks Davis to_msec = -1; 20247c08596SBrooks Davis 20347c08596SBrooks Davis /* Set up the descriptors to be polled. */ 204f8c44adaSSam Leffler live_interfaces = 0; 20547c08596SBrooks Davis for (i = 0, l = protocols; l; l = l->next) { 20647c08596SBrooks Davis struct interface_info *ip = l->local; 20747c08596SBrooks Davis 208f8c44adaSSam Leffler if (ip == NULL || ip->dead) 209f8c44adaSSam Leffler continue; 21047c08596SBrooks Davis fds[i].fd = l->fd; 21147c08596SBrooks Davis fds[i].events = POLLIN; 21247c08596SBrooks Davis fds[i].revents = 0; 21347c08596SBrooks Davis i++; 214f8c44adaSSam Leffler if (l->handler == got_one) 215f8c44adaSSam Leffler live_interfaces++; 21647c08596SBrooks Davis } 217f8c44adaSSam Leffler if (live_interfaces == 0) 21847c08596SBrooks Davis error("No live interfaces to poll on - exiting."); 21947c08596SBrooks Davis 22047c08596SBrooks Davis /* Wait for a packet or a timeout... XXX */ 22147c08596SBrooks Davis count = poll(fds, nfds, to_msec); 22247c08596SBrooks Davis 22347c08596SBrooks Davis /* Not likely to be transitory... */ 22447c08596SBrooks Davis if (count == -1) { 22547c08596SBrooks Davis if (errno == EAGAIN || errno == EINTR) { 226*f0a38976SIsaac Cilia Attard clock_gettime(CLOCK_MONOTONIC, &time_now); 227*f0a38976SIsaac Cilia Attard cur_time = time_now.tv_sec; 22847c08596SBrooks Davis continue; 22947c08596SBrooks Davis } else 23047c08596SBrooks Davis error("poll: %m"); 23147c08596SBrooks Davis } 23247c08596SBrooks Davis 23347c08596SBrooks Davis /* Get the current time... */ 234*f0a38976SIsaac Cilia Attard clock_gettime(CLOCK_MONOTONIC, &time_now); 235*f0a38976SIsaac Cilia Attard cur_time = time_now.tv_sec; 23647c08596SBrooks Davis 23747c08596SBrooks Davis i = 0; 23847c08596SBrooks Davis for (l = protocols; l; l = l->next) { 23947c08596SBrooks Davis struct interface_info *ip; 24047c08596SBrooks Davis ip = l->local; 24147c08596SBrooks Davis if ((fds[i].revents & (POLLIN | POLLHUP))) { 24247c08596SBrooks Davis fds[i].revents = 0; 24347c08596SBrooks Davis if (ip && (l->handler != got_one || 24447c08596SBrooks Davis !ip->dead)) 24547c08596SBrooks Davis (*(l->handler))(l); 24647c08596SBrooks Davis if (interfaces_invalidated) 24747c08596SBrooks Davis break; 24847c08596SBrooks Davis } 24947c08596SBrooks Davis i++; 25047c08596SBrooks Davis } 25147c08596SBrooks Davis interfaces_invalidated = 0; 25247c08596SBrooks Davis } while (1); 25347c08596SBrooks Davis } 25447c08596SBrooks Davis 25547c08596SBrooks Davis 25647c08596SBrooks Davis void 25747c08596SBrooks Davis got_one(struct protocol *l) 25847c08596SBrooks Davis { 25947c08596SBrooks Davis struct sockaddr_in from; 26047c08596SBrooks Davis struct hardware hfrom; 26147c08596SBrooks Davis struct iaddr ifrom; 26247c08596SBrooks Davis ssize_t result; 26347c08596SBrooks Davis union { 26447c08596SBrooks Davis /* 26547c08596SBrooks Davis * Packet input buffer. Must be as large as largest 26647c08596SBrooks Davis * possible MTU. 26747c08596SBrooks Davis */ 26847c08596SBrooks Davis unsigned char packbuf[4095]; 26947c08596SBrooks Davis struct dhcp_packet packet; 27047c08596SBrooks Davis } u; 27147c08596SBrooks Davis struct interface_info *ip = l->local; 27247c08596SBrooks Davis 27347c08596SBrooks Davis if ((result = receive_packet(ip, u.packbuf, sizeof(u), &from, 27447c08596SBrooks Davis &hfrom)) == -1) { 27547c08596SBrooks Davis warning("receive_packet failed on %s: %s", ip->name, 27647c08596SBrooks Davis strerror(errno)); 27747c08596SBrooks Davis ip->errors++; 27847c08596SBrooks Davis if ((!interface_status(ip)) || 27947c08596SBrooks Davis (ip->noifmedia && ip->errors > 20)) { 28047c08596SBrooks Davis /* our interface has gone away. */ 28147c08596SBrooks Davis warning("Interface %s no longer appears valid.", 28247c08596SBrooks Davis ip->name); 28347c08596SBrooks Davis ip->dead = 1; 28447c08596SBrooks Davis interfaces_invalidated = 1; 28547c08596SBrooks Davis close(l->fd); 28647c08596SBrooks Davis remove_protocol(l); 28747c08596SBrooks Davis free(ip); 28847c08596SBrooks Davis } 28947c08596SBrooks Davis return; 29047c08596SBrooks Davis } 29147c08596SBrooks Davis if (result == 0) 29247c08596SBrooks Davis return; 29347c08596SBrooks Davis 29447c08596SBrooks Davis if (bootp_packet_handler) { 29547c08596SBrooks Davis ifrom.len = 4; 29647c08596SBrooks Davis memcpy(ifrom.iabuf, &from.sin_addr, ifrom.len); 29747c08596SBrooks Davis 29847c08596SBrooks Davis (*bootp_packet_handler)(ip, &u.packet, result, 29947c08596SBrooks Davis from.sin_port, ifrom, &hfrom); 30047c08596SBrooks Davis } 30147c08596SBrooks Davis } 30247c08596SBrooks Davis 30347c08596SBrooks Davis int 30447c08596SBrooks Davis interface_status(struct interface_info *ifinfo) 30547c08596SBrooks Davis { 30647c08596SBrooks Davis char *ifname = ifinfo->name; 30747c08596SBrooks Davis int ifsock = ifinfo->rfdesc; 30847c08596SBrooks Davis struct ifreq ifr; 30947c08596SBrooks Davis struct ifmediareq ifmr; 31047c08596SBrooks Davis 31147c08596SBrooks Davis /* get interface flags */ 31247c08596SBrooks Davis memset(&ifr, 0, sizeof(ifr)); 31347c08596SBrooks Davis strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 31447c08596SBrooks Davis if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) { 315cb003dd9SMariusz Zaborski cap_syslog(capsyslog, LOG_ERR, "ioctl(SIOCGIFFLAGS) on %s: %m", 316cb003dd9SMariusz Zaborski ifname); 31747c08596SBrooks Davis goto inactive; 31847c08596SBrooks Davis } 31947c08596SBrooks Davis 32047c08596SBrooks Davis /* 32147c08596SBrooks Davis * if one of UP and RUNNING flags is dropped, 32247c08596SBrooks Davis * the interface is not active. 32347c08596SBrooks Davis */ 32447c08596SBrooks Davis if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 32547c08596SBrooks Davis goto inactive; 32647c08596SBrooks Davis 32747c08596SBrooks Davis /* Next, check carrier on the interface, if possible */ 32847c08596SBrooks Davis if (ifinfo->noifmedia) 32947c08596SBrooks Davis goto active; 33047c08596SBrooks Davis memset(&ifmr, 0, sizeof(ifmr)); 33147c08596SBrooks Davis strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); 33247c08596SBrooks Davis if (ioctl(ifsock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { 33347c08596SBrooks Davis if (errno != EINVAL) { 334cb003dd9SMariusz Zaborski cap_syslog(capsyslog, LOG_DEBUG, 335cb003dd9SMariusz Zaborski "ioctl(SIOCGIFMEDIA) on %s: %m", ifname); 33647c08596SBrooks Davis ifinfo->noifmedia = 1; 33747c08596SBrooks Davis goto active; 33847c08596SBrooks Davis } 33947c08596SBrooks Davis /* 34047c08596SBrooks Davis * EINVAL (or ENOTTY) simply means that the interface 34147c08596SBrooks Davis * does not support the SIOCGIFMEDIA ioctl. We regard it alive. 34247c08596SBrooks Davis */ 34347c08596SBrooks Davis ifinfo->noifmedia = 1; 34447c08596SBrooks Davis goto active; 34547c08596SBrooks Davis } 34647c08596SBrooks Davis if (ifmr.ifm_status & IFM_AVALID) { 34747c08596SBrooks Davis switch (ifmr.ifm_active & IFM_NMASK) { 34847c08596SBrooks Davis case IFM_ETHER: 349cd765a65SJung-uk Kim case IFM_IEEE80211: 35047c08596SBrooks Davis if (ifmr.ifm_status & IFM_ACTIVE) 35147c08596SBrooks Davis goto active; 35247c08596SBrooks Davis else 35347c08596SBrooks Davis goto inactive; 35447c08596SBrooks Davis break; 35547c08596SBrooks Davis default: 35647c08596SBrooks Davis goto inactive; 35747c08596SBrooks Davis } 35847c08596SBrooks Davis } 35947c08596SBrooks Davis inactive: 36047c08596SBrooks Davis return (0); 36147c08596SBrooks Davis active: 36247c08596SBrooks Davis return (1); 36347c08596SBrooks Davis } 36447c08596SBrooks Davis 36547c08596SBrooks Davis void 36616a235f2SIsaac Cilia Attard add_timeout(time_t when_s, void (*where)(void *), void *what) 36716a235f2SIsaac Cilia Attard { 36816a235f2SIsaac Cilia Attard struct timespec when = { .tv_sec = when_s, .tv_nsec = 0 }; 36916a235f2SIsaac Cilia Attard add_timeout_timespec(when, where, what); 37016a235f2SIsaac Cilia Attard } 37116a235f2SIsaac Cilia Attard 37216a235f2SIsaac Cilia Attard void 37316a235f2SIsaac Cilia Attard add_timeout_timespec(struct timespec when, void (*where)(void *), void *what) 37447c08596SBrooks Davis { 37547c08596SBrooks Davis struct timeout *t, *q; 37647c08596SBrooks Davis 37747c08596SBrooks Davis /* See if this timeout supersedes an existing timeout. */ 37847c08596SBrooks Davis t = NULL; 37947c08596SBrooks Davis for (q = timeouts; q; q = q->next) { 38047c08596SBrooks Davis if (q->func == where && q->what == what) { 38147c08596SBrooks Davis if (t) 38247c08596SBrooks Davis t->next = q->next; 38347c08596SBrooks Davis else 38447c08596SBrooks Davis timeouts = q->next; 38547c08596SBrooks Davis break; 38647c08596SBrooks Davis } 38747c08596SBrooks Davis t = q; 38847c08596SBrooks Davis } 38947c08596SBrooks Davis 39047c08596SBrooks Davis /* If we didn't supersede a timeout, allocate a timeout 39147c08596SBrooks Davis structure now. */ 39247c08596SBrooks Davis if (!q) { 39347c08596SBrooks Davis if (free_timeouts) { 39447c08596SBrooks Davis q = free_timeouts; 39547c08596SBrooks Davis free_timeouts = q->next; 39647c08596SBrooks Davis q->func = where; 39747c08596SBrooks Davis q->what = what; 39847c08596SBrooks Davis } else { 39947c08596SBrooks Davis q = malloc(sizeof(struct timeout)); 40047c08596SBrooks Davis if (!q) 40147c08596SBrooks Davis error("Can't allocate timeout structure!"); 40247c08596SBrooks Davis q->func = where; 40347c08596SBrooks Davis q->what = what; 40447c08596SBrooks Davis } 40547c08596SBrooks Davis } 40647c08596SBrooks Davis 40747c08596SBrooks Davis q->when = when; 40847c08596SBrooks Davis 40947c08596SBrooks Davis /* Now sort this timeout into the timeout list. */ 41047c08596SBrooks Davis 41147c08596SBrooks Davis /* Beginning of list? */ 41216a235f2SIsaac Cilia Attard if (!timeouts || timespeccmp(&timeouts->when, &q->when, >)) { 41347c08596SBrooks Davis q->next = timeouts; 41447c08596SBrooks Davis timeouts = q; 41547c08596SBrooks Davis return; 41647c08596SBrooks Davis } 41747c08596SBrooks Davis 41847c08596SBrooks Davis /* Middle of list? */ 41947c08596SBrooks Davis for (t = timeouts; t->next; t = t->next) { 42016a235f2SIsaac Cilia Attard if (timespeccmp(&t->next->when, &q->when, >)) { 42147c08596SBrooks Davis q->next = t->next; 42247c08596SBrooks Davis t->next = q; 42347c08596SBrooks Davis return; 42447c08596SBrooks Davis } 42547c08596SBrooks Davis } 42647c08596SBrooks Davis 42747c08596SBrooks Davis /* End of list. */ 42847c08596SBrooks Davis t->next = q; 42947c08596SBrooks Davis q->next = NULL; 43047c08596SBrooks Davis } 43147c08596SBrooks Davis 43247c08596SBrooks Davis void 43347c08596SBrooks Davis cancel_timeout(void (*where)(void *), void *what) 43447c08596SBrooks Davis { 43547c08596SBrooks Davis struct timeout *t, *q; 43647c08596SBrooks Davis 43747c08596SBrooks Davis /* Look for this timeout on the list, and unlink it if we find it. */ 43847c08596SBrooks Davis t = NULL; 43947c08596SBrooks Davis for (q = timeouts; q; q = q->next) { 44047c08596SBrooks Davis if (q->func == where && q->what == what) { 44147c08596SBrooks Davis if (t) 44247c08596SBrooks Davis t->next = q->next; 44347c08596SBrooks Davis else 44447c08596SBrooks Davis timeouts = q->next; 44547c08596SBrooks Davis break; 44647c08596SBrooks Davis } 44747c08596SBrooks Davis t = q; 44847c08596SBrooks Davis } 44947c08596SBrooks Davis 45047c08596SBrooks Davis /* If we found the timeout, put it on the free list. */ 45147c08596SBrooks Davis if (q) { 45247c08596SBrooks Davis q->next = free_timeouts; 45347c08596SBrooks Davis free_timeouts = q; 45447c08596SBrooks Davis } 45547c08596SBrooks Davis } 45647c08596SBrooks Davis 45747c08596SBrooks Davis /* Add a protocol to the list of protocols... */ 45847c08596SBrooks Davis void 45979a1d195SAlan Somers add_protocol(const char *name, int fd, void (*handler)(struct protocol *), 46047c08596SBrooks Davis void *local) 46147c08596SBrooks Davis { 46247c08596SBrooks Davis struct protocol *p; 46347c08596SBrooks Davis 46447c08596SBrooks Davis p = malloc(sizeof(*p)); 46547c08596SBrooks Davis if (!p) 46647c08596SBrooks Davis error("can't allocate protocol struct for %s", name); 46747c08596SBrooks Davis 46847c08596SBrooks Davis p->fd = fd; 46947c08596SBrooks Davis p->handler = handler; 47047c08596SBrooks Davis p->local = local; 47147c08596SBrooks Davis p->next = protocols; 47247c08596SBrooks Davis protocols = p; 47347c08596SBrooks Davis } 47447c08596SBrooks Davis 47547c08596SBrooks Davis void 47647c08596SBrooks Davis remove_protocol(struct protocol *proto) 47747c08596SBrooks Davis { 47800060820SMark Johnston struct protocol *p, *prev; 47947c08596SBrooks Davis 48000060820SMark Johnston for (p = protocols, prev = NULL; p != NULL; prev = p, p = p->next) { 48147c08596SBrooks Davis if (p == proto) { 48200060820SMark Johnston if (prev == NULL) 48347c08596SBrooks Davis protocols = p->next; 48400060820SMark Johnston else 48500060820SMark Johnston prev->next = p->next; 48647c08596SBrooks Davis free(p); 48700060820SMark Johnston break; 48847c08596SBrooks Davis } 48947c08596SBrooks Davis } 49047c08596SBrooks Davis } 49147c08596SBrooks Davis 49247c08596SBrooks Davis int 49347c08596SBrooks Davis interface_link_status(char *ifname) 49447c08596SBrooks Davis { 49547c08596SBrooks Davis struct ifmediareq ifmr; 49647c08596SBrooks Davis int sock; 49747c08596SBrooks Davis 49847c08596SBrooks Davis if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 49947c08596SBrooks Davis error("Can't create socket"); 50047c08596SBrooks Davis 50147c08596SBrooks Davis memset(&ifmr, 0, sizeof(ifmr)); 50247c08596SBrooks Davis strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); 50347c08596SBrooks Davis if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) { 50447c08596SBrooks Davis /* EINVAL -> link state unknown. treat as active */ 50547c08596SBrooks Davis if (errno != EINVAL) 506cb003dd9SMariusz Zaborski cap_syslog(capsyslog, LOG_DEBUG, 507cb003dd9SMariusz Zaborski "ioctl(SIOCGIFMEDIA) on %s: %m", ifname); 50847c08596SBrooks Davis close(sock); 50947c08596SBrooks Davis return (1); 51047c08596SBrooks Davis } 51147c08596SBrooks Davis close(sock); 51247c08596SBrooks Davis 51347c08596SBrooks Davis if (ifmr.ifm_status & IFM_AVALID) { 514cd765a65SJung-uk Kim switch (ifmr.ifm_active & IFM_NMASK) { 515cd765a65SJung-uk Kim case IFM_ETHER: 516cd765a65SJung-uk Kim case IFM_IEEE80211: 51747c08596SBrooks Davis if (ifmr.ifm_status & IFM_ACTIVE) 51847c08596SBrooks Davis return (1); 51947c08596SBrooks Davis else 52047c08596SBrooks Davis return (0); 52147c08596SBrooks Davis } 52247c08596SBrooks Davis } 52347c08596SBrooks Davis return (1); 52447c08596SBrooks Davis } 525387016a5SConrad Meyer 526387016a5SConrad Meyer void 527387016a5SConrad Meyer interface_set_mtu_unpriv(int privfd, u_int16_t mtu) 528387016a5SConrad Meyer { 529387016a5SConrad Meyer struct imsg_hdr hdr; 530387016a5SConrad Meyer struct buf *buf; 531387016a5SConrad Meyer int errs = 0; 532387016a5SConrad Meyer 533387016a5SConrad Meyer hdr.code = IMSG_SET_INTERFACE_MTU; 534387016a5SConrad Meyer hdr.len = sizeof(hdr) + 535387016a5SConrad Meyer sizeof(u_int16_t); 536387016a5SConrad Meyer 537387016a5SConrad Meyer if ((buf = buf_open(hdr.len)) == NULL) 538387016a5SConrad Meyer error("buf_open: %m"); 539387016a5SConrad Meyer 540387016a5SConrad Meyer errs += buf_add(buf, &hdr, sizeof(hdr)); 541387016a5SConrad Meyer errs += buf_add(buf, &mtu, sizeof(mtu)); 542387016a5SConrad Meyer if (errs) 543387016a5SConrad Meyer error("buf_add: %m"); 544387016a5SConrad Meyer 545387016a5SConrad Meyer if (buf_close(privfd, buf) == -1) 546387016a5SConrad Meyer error("buf_close: %m"); 547387016a5SConrad Meyer } 548387016a5SConrad Meyer 549387016a5SConrad Meyer void 550387016a5SConrad Meyer interface_set_mtu_priv(char *ifname, u_int16_t mtu) 551387016a5SConrad Meyer { 552387016a5SConrad Meyer struct ifreq ifr; 553387016a5SConrad Meyer int sock; 55435b930ccSEugene Grosbein u_int16_t old_mtu; 555387016a5SConrad Meyer 556387016a5SConrad Meyer if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 557387016a5SConrad Meyer error("Can't create socket"); 558387016a5SConrad Meyer 559387016a5SConrad Meyer memset(&ifr, 0, sizeof(ifr)); 56035b930ccSEugene Grosbein old_mtu = 0; 561387016a5SConrad Meyer 562387016a5SConrad Meyer strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 56335b930ccSEugene Grosbein 56435b930ccSEugene Grosbein if (ioctl(sock, SIOCGIFMTU, (caddr_t)&ifr) == -1) 56535b930ccSEugene Grosbein warning("SIOCGIFMTU failed (%s): %s", ifname, 56635b930ccSEugene Grosbein strerror(errno)); 56735b930ccSEugene Grosbein else 56835b930ccSEugene Grosbein old_mtu = ifr.ifr_mtu; 56935b930ccSEugene Grosbein 57035b930ccSEugene Grosbein if (mtu != old_mtu) { 571387016a5SConrad Meyer ifr.ifr_mtu = mtu; 572387016a5SConrad Meyer 573387016a5SConrad Meyer if (ioctl(sock, SIOCSIFMTU, &ifr) == -1) 574387016a5SConrad Meyer warning("SIOCSIFMTU failed (%d): %s", mtu, 575387016a5SConrad Meyer strerror(errno)); 57635b930ccSEugene Grosbein } 57735b930ccSEugene Grosbein 578387016a5SConrad Meyer close(sock); 579387016a5SConrad Meyer } 580