dhclient - Nuke 'interfaces_invalidated' global variable.
[dragonfly.git] / sbin / dhclient / dispatch.c
blob044aedfefef7b3ad80503b73848453d06ee114bb
1 /* $OpenBSD: src/sbin/dhclient/dispatch.c,v 1.56 2012/09/01 19:02:27 krw Exp $ */
3 /*
4 * Copyright 2004 Henning Brauer <henning@openbsd.org>
5 * Copyright (c) 1995, 1996, 1997, 1998, 1999
6 * The Internet Software Consortium. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of The Internet Software Consortium nor the names
18 * of its contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
22 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
26 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
29 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
35 * This software has been written for the Internet Software Consortium
36 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
37 * Enterprises. To learn more about the Internet Software Consortium,
38 * see ``http://www.vix.com/isc''. To learn more about Vixie
39 * Enterprises, see ``http://www.vix.com''.
42 #include <sys/ioctl.h>
44 #include <net/if_media.h>
46 #include <ifaddrs.h>
47 #include <poll.h>
49 #include "dhcpd.h"
51 struct timeout timeout;
54 * Use getifaddrs() to get a list of all the attached interfaces. For
55 * each interface that's of type INET and not the loopback interface,
56 * register that interface with the network I/O software, figure out
57 * what subnet it's on, and add it to the list of interfaces.
59 void
60 discover_interface(void)
62 struct ifaddrs *ifap, *ifa;
63 struct ifreq *tif;
64 int len = IFNAMSIZ + sizeof(struct sockaddr_storage);
66 if (getifaddrs(&ifap) != 0)
67 error("getifaddrs failed");
69 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
70 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
71 (ifa->ifa_flags & IFF_POINTOPOINT) ||
72 (!(ifa->ifa_flags & IFF_UP)))
73 continue;
75 if (strcmp(ifi->name, ifa->ifa_name))
76 continue;
79 * If we have the capability, extract link information
80 * and record it in a linked list.
82 if (ifa->ifa_addr->sa_family == AF_LINK) {
83 struct sockaddr_dl *foo =
84 (struct sockaddr_dl *)ifa->ifa_addr;
86 ifi->index = foo->sdl_index;
87 ifi->hw_address.hlen = foo->sdl_alen;
88 ifi->hw_address.htype = HTYPE_ETHER; /* XXX */
89 memcpy(ifi->hw_address.haddr,
90 LLADDR(foo), foo->sdl_alen);
92 if (!ifi->ifp) {
93 if ((tif = malloc(len)) == NULL)
94 error("no space to remember ifp");
95 strlcpy(tif->ifr_name, ifa->ifa_name, IFNAMSIZ);
96 ifi->ifp = tif;
100 if (!ifi->ifp)
101 error("%s: not found", ifi->name);
103 /* Register the interface... */
104 if_register_receive();
105 if_register_send();
106 freeifaddrs(ifap);
110 * Wait for packets to come in using poll(). When a packet comes in, call
111 * receive_packet to receive the packet and possibly strip hardware addressing
112 * information from it, and then call do_packet to try to do something with it.
114 void
115 dispatch(void)
117 int count, to_msec;
118 struct pollfd fds[2];
119 time_t cur_time, howlong;
120 void (*func)(void);
122 do {
124 * Call expired timeout, and then if there's still
125 * a timeout registered, time out the select call then.
127 another:
128 if (!ifi)
129 error("No interfaces available");
131 ifi->linkstat = interface_status(ifi->name);
133 if (timeout.func) {
134 time(&cur_time);
135 if (timeout.when <= cur_time) {
136 func = timeout.func;
137 cancel_timeout();
138 (*(func))();
139 goto another;
142 * Figure timeout in milliseconds, and check for
143 * potential overflow, so we can cram into an
144 * int for poll, while not polling with a
145 * negative timeout and blocking indefinitely.
147 howlong = timeout.when - cur_time;
148 if (howlong > INT_MAX / 1000)
149 howlong = INT_MAX / 1000;
150 to_msec = howlong * 1000;
151 } else
152 to_msec = -1;
154 /* Set up the descriptors to be polled. */
155 if (!ifi || ifi->rfdesc == -1)
156 error("No live interface to poll on");
158 fds[0].fd = ifi->rfdesc;
159 fds[1].fd = routefd; /* Could be -1, which will be ignored. */
160 fds[0].events = fds[1].events = POLLIN;
162 /* Wait for a packet or a timeout... XXX */
163 count = poll(fds, 2, to_msec);
165 /* Not likely to be transitory... */
166 if (count == -1) {
167 if (errno == EAGAIN || errno == EINTR) {
168 continue;
169 } else
170 error("poll: %m");
173 if ((fds[0].revents & (POLLIN | POLLHUP))) {
174 if (ifi && ifi->linkstat && ifi->rfdesc != -1)
175 got_one();
177 if ((fds[1].revents & (POLLIN | POLLHUP))) {
178 if (ifi)
179 routehandler();
181 } while (1);
184 void
185 got_one(void)
187 struct sockaddr_in from;
188 struct hardware hfrom;
189 struct iaddr ifrom;
190 ssize_t result;
192 if ((result = receive_packet(&from, &hfrom)) == -1) {
193 warning("receive_packet failed on %s: %s", ifi->name,
194 strerror(errno));
195 ifi->errors++;
196 if ((!interface_status(ifi->name)) ||
197 (ifi->noifmedia && ifi->errors > 20)) {
198 /* our interface has gone away. */
199 error("Interface %s no longer appears valid.",
200 ifi->name);
202 return;
204 if (result == 0)
205 return;
207 ifrom.len = 4;
208 memcpy(ifrom.iabuf, &from.sin_addr, ifrom.len);
210 do_packet(result, from.sin_port, ifrom, &hfrom);
214 interface_link_forceup(char *ifname)
216 struct ifreq ifr;
217 int sock;
219 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
220 error("Can't create socket");
222 memset(&ifr, 0, sizeof(ifr));
223 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
224 if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)&ifr) == -1) {
225 close(sock);
226 return (-1);
229 if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
230 ifr.ifr_flags |= IFF_UP;
231 if (ioctl(sock, SIOCSIFFLAGS, (caddr_t)&ifr) == -1) {
232 close(sock);
233 return (-1);
235 close(sock);
236 return (0);
238 close(sock);
239 return (1);
243 interface_status(char *ifname)
245 struct ifreq ifr;
246 struct ifmediareq ifmr;
247 int sock;
249 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
250 error("Can't create socket");
252 /* get interface flags */
253 memset(&ifr, 0, sizeof(ifr));
254 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
255 if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) {
256 error("ioctl(SIOCGIFFLAGS) on %s: %m", ifname);
260 * if one of UP and RUNNING flags is dropped,
261 * the interface is not active.
263 if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
264 goto inactive;
266 /* Next, check carrier on the interface, if possible */
267 if (ifi->noifmedia)
268 goto active;
269 memset(&ifmr, 0, sizeof(ifmr));
270 strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
271 if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) {
273 * EINVAL or ENOTTY simply means that the interface
274 * does not support the SIOCGIFMEDIA ioctl. We regard it alive.
276 #ifdef DEBUG
277 if (errno != EINVAL && errno != ENOTTY)
278 debug("ioctl(SIOCGIFMEDIA) on %s: %m", ifname);
279 #endif
280 ifi->noifmedia = 1;
281 goto active;
283 if (ifmr.ifm_status & IFM_AVALID) {
284 if (ifmr.ifm_status & IFM_ACTIVE)
285 goto active;
286 else
287 goto inactive;
290 /* Assume 'active' if IFM_AVALID is not set. */
292 active:
293 close(sock);
294 return (1);
295 inactive:
296 close(sock);
297 return (0);
300 void
301 set_timeout(time_t when, void (*where)(void))
303 timeout.when = when;
304 timeout.func = where;
307 void
308 set_timeout_interval(time_t secs, void (*where)(void))
310 timeout.when = time(NULL) + secs;
311 timeout.func = where;
314 void
315 cancel_timeout(void)
317 timeout.when = 0;
318 timeout.func = NULL;