1 /* $OpenBSD: src/sbin/dhclient/dispatch.c,v 1.59 2012/10/11 08:05:05 sthen Exp $ */ 2 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. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 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. 20 * 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. 34 * 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''. 40 */ 41 42 #include <sys/ioctl.h> 43 44 #include <net/if_media.h> 45 46 #include <ifaddrs.h> 47 #include <poll.h> 48 49 #include "dhcpd.h" 50 51 struct timeout timeout; 52 53 /* 54 * Use getifaddrs() to get a list of all the attached interfaces. Find 55 * our interface on the list and store the interesting information about it. 56 */ 57 void 58 discover_interface(void) 59 { 60 struct ifaddrs *ifap, *ifa; 61 struct ifreq *tif; 62 int len = IFNAMSIZ + sizeof(struct sockaddr_storage); 63 64 if (getifaddrs(&ifap) != 0) 65 error("getifaddrs failed"); 66 67 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 68 if ((ifa->ifa_flags & IFF_LOOPBACK) || 69 (ifa->ifa_flags & IFF_POINTOPOINT) || 70 (!(ifa->ifa_flags & IFF_UP))) 71 continue; 72 73 if (strcmp(ifi->name, ifa->ifa_name)) 74 continue; 75 76 /* 77 * If we have the capability, extract & save link information. 78 */ 79 if (ifa->ifa_addr->sa_family == AF_LINK) { 80 struct sockaddr_dl *foo = 81 (struct sockaddr_dl *)ifa->ifa_addr; 82 83 ifi->index = foo->sdl_index; 84 ifi->hw_address.hlen = foo->sdl_alen; 85 ifi->hw_address.htype = HTYPE_ETHER; /* XXX */ 86 memcpy(ifi->hw_address.haddr, 87 LLADDR(foo), foo->sdl_alen); 88 } 89 if (!ifi->ifp) { 90 if ((tif = malloc(len)) == NULL) 91 error("no space to remember ifp"); 92 strlcpy(tif->ifr_name, ifa->ifa_name, IFNAMSIZ); 93 ifi->ifp = tif; 94 } 95 } 96 97 if (!ifi->ifp) 98 error("%s: not found", ifi->name); 99 100 /* Register the interface... */ 101 if_register_receive(); 102 if_register_send(); 103 freeifaddrs(ifap); 104 } 105 106 /* 107 * Loop waiting for packets, timeouts or routing messages. 108 */ 109 void 110 dispatch(void) 111 { 112 int count, to_msec; 113 struct pollfd fds[2]; 114 time_t cur_time, howlong; 115 void (*func)(void); 116 117 do { 118 /* 119 * Call expired timeout, and then if there's still 120 * a timeout registered, time out the select call then. 121 */ 122 another: 123 if (!ifi) 124 error("No interfaces available"); 125 126 if (timeout.func) { 127 time(&cur_time); 128 if (timeout.when <= cur_time) { 129 func = timeout.func; 130 cancel_timeout(); 131 (*(func))(); 132 goto another; 133 } 134 /* 135 * Figure timeout in milliseconds, and check for 136 * potential overflow, so we can cram into an 137 * int for poll, while not polling with a 138 * negative timeout and blocking indefinitely. 139 */ 140 howlong = timeout.when - cur_time; 141 if (howlong > INT_MAX / 1000) 142 howlong = INT_MAX / 1000; 143 to_msec = howlong * 1000; 144 } else 145 to_msec = -1; 146 147 /* Set up the descriptors to be polled. */ 148 if (!ifi || ifi->rfdesc == -1) 149 error("No live interface to poll on"); 150 151 fds[0].fd = ifi->rfdesc; 152 fds[1].fd = routefd; /* Could be -1, which will be ignored. */ 153 fds[0].events = fds[1].events = POLLIN; 154 155 /* Wait for a packet or a timeout... XXX */ 156 count = poll(fds, 2, to_msec); 157 158 /* Not likely to be transitory... */ 159 if (count == -1) { 160 if (errno == EAGAIN || errno == EINTR) { 161 continue; 162 } else 163 error("poll: %m"); 164 } 165 166 if ((fds[0].revents & (POLLIN | POLLHUP))) { 167 if (ifi && ifi->linkstat && ifi->rfdesc != -1) 168 got_one(); 169 } 170 if ((fds[1].revents & (POLLIN | POLLHUP))) { 171 if (ifi) 172 routehandler(); 173 } 174 } while (1); 175 } 176 177 void 178 got_one(void) 179 { 180 struct sockaddr_in from; 181 struct hardware hfrom; 182 struct iaddr ifrom; 183 ssize_t result; 184 185 if ((result = receive_packet(&from, &hfrom)) == -1) { 186 warning("receive_packet failed on %s: %s", ifi->name, 187 strerror(errno)); 188 ifi->errors++; 189 if ((!interface_status(ifi->name)) || 190 (ifi->noifmedia && ifi->errors > 20)) { 191 /* our interface has gone away. */ 192 error("Interface %s no longer appears valid.", 193 ifi->name); 194 } 195 return; 196 } 197 if (result == 0) 198 return; 199 200 ifrom.len = 4; 201 memcpy(ifrom.iabuf, &from.sin_addr, ifrom.len); 202 203 do_packet(result, from.sin_port, ifrom, &hfrom); 204 } 205 206 /* 207 * Normally its ok to force the interface link up, but don't do it 208 * if it is an 80211 interface. 209 */ 210 int 211 interface_link_forceup(char *ifname) 212 { 213 struct ifreq ifr; 214 struct ifmediareq ifmr; 215 int sock; 216 217 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 218 error("Can't create socket"); 219 220 memset(&ifr, 0, sizeof(ifr)); 221 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 222 if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)&ifr) == -1) { 223 close(sock); 224 return (-1); 225 } 226 memset(&ifmr, 0, sizeof(ifmr)); 227 strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); 228 if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) != -1) { 229 if (IFM_TYPE(ifmr.ifm_active) == IFM_IEEE80211) { 230 return 0; 231 } 232 } 233 234 if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 235 ifr.ifr_flags |= IFF_UP; 236 if (ioctl(sock, SIOCSIFFLAGS, (caddr_t)&ifr) == -1) { 237 close(sock); 238 return (-1); 239 } 240 close(sock); 241 return (0); 242 } 243 close(sock); 244 return (1); 245 } 246 247 int 248 interface_status(char *ifname) 249 { 250 struct ifreq ifr; 251 struct ifmediareq ifmr; 252 int sock; 253 254 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 255 error("Can't create socket"); 256 257 /* get interface flags */ 258 memset(&ifr, 0, sizeof(ifr)); 259 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 260 if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) { 261 error("ioctl(SIOCGIFFLAGS) on %s: %m", ifname); 262 } 263 264 /* 265 * if one of UP and RUNNING flags is dropped, 266 * the interface is not active. 267 */ 268 if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 269 goto inactive; 270 271 /* Next, check carrier on the interface, if possible */ 272 if (ifi->noifmedia) 273 goto active; 274 memset(&ifmr, 0, sizeof(ifmr)); 275 strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); 276 if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) { 277 /* 278 * EINVAL or ENOTTY simply means that the interface 279 * does not support the SIOCGIFMEDIA ioctl. We regard it alive. 280 */ 281 #ifdef DEBUG 282 if (errno != EINVAL && errno != ENOTTY) 283 debug("ioctl(SIOCGIFMEDIA) on %s: %m", ifname); 284 #endif 285 ifi->noifmedia = 1; 286 goto active; 287 } 288 if (ifmr.ifm_status & IFM_AVALID) { 289 if (ifmr.ifm_status & IFM_ACTIVE) 290 goto active; 291 else 292 goto inactive; 293 } 294 295 /* Assume 'active' if IFM_AVALID is not set. */ 296 297 active: 298 close(sock); 299 return (1); 300 inactive: 301 close(sock); 302 return (0); 303 } 304 305 void 306 set_timeout(time_t when, void (*where)(void)) 307 { 308 timeout.when = when; 309 timeout.func = where; 310 } 311 312 void 313 set_timeout_interval(time_t secs, void (*where)(void)) 314 { 315 timeout.when = time(NULL) + secs; 316 timeout.func = where; 317 } 318 319 void 320 cancel_timeout(void) 321 { 322 timeout.when = 0; 323 timeout.func = NULL; 324 } 325 326 int 327 subnet_exists(struct client_lease *l) 328 { 329 struct ifaddrs *ifap, *ifa; 330 in_addr_t mymask, myaddr, mynet, hismask, hisaddr, hisnet; 331 332 bcopy(l->options[DHO_SUBNET_MASK].data, &mymask, 4); 333 bcopy(l->address.iabuf, &myaddr, 4); 334 mynet = mymask & myaddr; 335 336 if (getifaddrs(&ifap) != 0) 337 error("getifaddrs failed"); 338 339 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 340 if (strcmp(ifi->name, ifa->ifa_name) == 0) 341 continue; 342 343 if (ifa->ifa_addr->sa_family != AF_INET) 344 continue; 345 346 hismask = ((struct sockaddr_in *)ifa->ifa_netmask)-> 347 sin_addr.s_addr; 348 hisaddr = ((struct sockaddr_in *)ifa->ifa_addr)-> 349 sin_addr.s_addr; 350 hisnet = hisaddr & hismask; 351 352 if (hisnet == 0) 353 continue; 354 355 /* Would his packets go out *my* interface? */ 356 if (mynet == (hisaddr & mymask)) { 357 note("interface %s already has the offered subnet!", 358 ifa->ifa_name); 359 return (1); 360 } 361 362 /* Would my packets go out *his* interface? */ 363 if (hisnet == (myaddr & hismask)) { 364 note("interface %s already has the offered subnet!", 365 ifa->ifa_name); 366 return (1); 367 } 368 } 369 370 freeifaddrs(ifap); 371 372 return (0); 373 } 374