1147072Sbrooks/* $OpenBSD: dispatch.c,v 1.31 2004/09/21 04:07:03 david Exp $ */ 2147072Sbrooks 3147072Sbrooks/* 4147072Sbrooks * Copyright 2004 Henning Brauer <henning@openbsd.org> 5147072Sbrooks * Copyright (c) 1995, 1996, 1997, 1998, 1999 6147072Sbrooks * The Internet Software Consortium. All rights reserved. 7147072Sbrooks * 8147072Sbrooks * Redistribution and use in source and binary forms, with or without 9147072Sbrooks * modification, are permitted provided that the following conditions 10147072Sbrooks * are met: 11147072Sbrooks * 12147072Sbrooks * 1. Redistributions of source code must retain the above copyright 13147072Sbrooks * notice, this list of conditions and the following disclaimer. 14147072Sbrooks * 2. Redistributions in binary form must reproduce the above copyright 15147072Sbrooks * notice, this list of conditions and the following disclaimer in the 16147072Sbrooks * documentation and/or other materials provided with the distribution. 17147072Sbrooks * 3. Neither the name of The Internet Software Consortium nor the names 18147072Sbrooks * of its contributors may be used to endorse or promote products derived 19147072Sbrooks * from this software without specific prior written permission. 20147072Sbrooks * 21147072Sbrooks * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND 22147072Sbrooks * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 23147072Sbrooks * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 24147072Sbrooks * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25147072Sbrooks * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR 26147072Sbrooks * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27147072Sbrooks * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28147072Sbrooks * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 29147072Sbrooks * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30147072Sbrooks * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31147072Sbrooks * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 32147072Sbrooks * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33147072Sbrooks * SUCH DAMAGE. 34147072Sbrooks * 35147072Sbrooks * This software has been written for the Internet Software Consortium 36147072Sbrooks * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie 37147072Sbrooks * Enterprises. To learn more about the Internet Software Consortium, 38147072Sbrooks * see ``http://www.vix.com/isc''. To learn more about Vixie 39147072Sbrooks * Enterprises, see ``http://www.vix.com''. 40147072Sbrooks */ 41147072Sbrooks 42149399Sbrooks#include <sys/cdefs.h> 43149399Sbrooks__FBSDID("$FreeBSD: stable/10/sbin/dhclient/dispatch.c 313103 2017-02-02 19:50:28Z asomers $"); 44149399Sbrooks 45147072Sbrooks#include "dhcpd.h" 46147072Sbrooks 47147072Sbrooks#include <sys/ioctl.h> 48147072Sbrooks 49147072Sbrooks#include <net/if_media.h> 50147072Sbrooks#include <ifaddrs.h> 51147072Sbrooks#include <poll.h> 52147072Sbrooks 53147072Sbrooksstruct protocol *protocols; 54147072Sbrooksstruct timeout *timeouts; 55147072Sbrooksstatic struct timeout *free_timeouts; 56147072Sbrooksstatic int interfaces_invalidated; 57147072Sbrooksvoid (*bootp_packet_handler)(struct interface_info *, 58147072Sbrooks struct dhcp_packet *, int, unsigned int, 59147072Sbrooks struct iaddr, struct hardware *); 60147072Sbrooks 61147072Sbrooksstatic int interface_status(struct interface_info *ifinfo); 62147072Sbrooks 63147072Sbrooks/* 64147072Sbrooks * Use getifaddrs() to get a list of all the attached interfaces. For 65147072Sbrooks * each interface that's of type INET and not the loopback interface, 66147072Sbrooks * register that interface with the network I/O software, figure out 67147072Sbrooks * what subnet it's on, and add it to the list of interfaces. 68147072Sbrooks */ 69147072Sbrooksvoid 70147072Sbrooksdiscover_interfaces(struct interface_info *iface) 71147072Sbrooks{ 72147072Sbrooks struct ifaddrs *ifap, *ifa; 73147072Sbrooks struct sockaddr_in foo; 74147072Sbrooks struct ifreq *tif; 75147072Sbrooks 76147072Sbrooks if (getifaddrs(&ifap) != 0) 77147072Sbrooks error("getifaddrs failed"); 78147072Sbrooks 79147072Sbrooks for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 80147072Sbrooks if ((ifa->ifa_flags & IFF_LOOPBACK) || 81147072Sbrooks (ifa->ifa_flags & IFF_POINTOPOINT) || 82147072Sbrooks (!(ifa->ifa_flags & IFF_UP))) 83147072Sbrooks continue; 84147072Sbrooks 85147072Sbrooks if (strcmp(iface->name, ifa->ifa_name)) 86147072Sbrooks continue; 87147072Sbrooks 88147072Sbrooks /* 89147072Sbrooks * If we have the capability, extract link information 90147072Sbrooks * and record it in a linked list. 91147072Sbrooks */ 92147072Sbrooks if (ifa->ifa_addr->sa_family == AF_LINK) { 93147072Sbrooks struct sockaddr_dl *foo = 94147072Sbrooks (struct sockaddr_dl *)ifa->ifa_addr; 95147072Sbrooks 96147072Sbrooks iface->index = foo->sdl_index; 97147072Sbrooks iface->hw_address.hlen = foo->sdl_alen; 98147072Sbrooks iface->hw_address.htype = HTYPE_ETHER; /* XXX */ 99147072Sbrooks memcpy(iface->hw_address.haddr, 100147072Sbrooks LLADDR(foo), foo->sdl_alen); 101147072Sbrooks } else if (ifa->ifa_addr->sa_family == AF_INET) { 102147072Sbrooks struct iaddr addr; 103147072Sbrooks 104147072Sbrooks memcpy(&foo, ifa->ifa_addr, sizeof(foo)); 105147072Sbrooks if (foo.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) 106147072Sbrooks continue; 107147072Sbrooks if (!iface->ifp) { 108309304Sbrooks if ((tif = calloc(1, sizeof(struct ifreq))) 109309304Sbrooks == NULL) 110147072Sbrooks error("no space to remember ifp"); 111147072Sbrooks strlcpy(tif->ifr_name, ifa->ifa_name, IFNAMSIZ); 112147072Sbrooks memcpy(&tif->ifr_addr, ifa->ifa_addr, 113147072Sbrooks ifa->ifa_addr->sa_len); 114147072Sbrooks iface->ifp = tif; 115147072Sbrooks iface->primary_address = foo.sin_addr; 116147072Sbrooks } 117147072Sbrooks addr.len = 4; 118147072Sbrooks memcpy(addr.iabuf, &foo.sin_addr.s_addr, addr.len); 119147072Sbrooks } 120147072Sbrooks } 121147072Sbrooks 122147072Sbrooks if (!iface->ifp) 123147072Sbrooks error("%s: not found", iface->name); 124147072Sbrooks 125147072Sbrooks /* Register the interface... */ 126147072Sbrooks if_register_receive(iface); 127147072Sbrooks if_register_send(iface); 128147072Sbrooks add_protocol(iface->name, iface->rfdesc, got_one, iface); 129147072Sbrooks freeifaddrs(ifap); 130147072Sbrooks} 131147072Sbrooks 132147072Sbrooksvoid 133147072Sbrooksreinitialize_interfaces(void) 134147072Sbrooks{ 135147072Sbrooks interfaces_invalidated = 1; 136147072Sbrooks} 137147072Sbrooks 138147072Sbrooks/* 139147072Sbrooks * Wait for packets to come in using poll(). When a packet comes in, 140147072Sbrooks * call receive_packet to receive the packet and possibly strip hardware 141147072Sbrooks * addressing information from it, and then call through the 142147072Sbrooks * bootp_packet_handler hook to try to do something with it. 143147072Sbrooks */ 144147072Sbrooksvoid 145147072Sbrooksdispatch(void) 146147072Sbrooks{ 147195805Ssam int count, live_interfaces, i, to_msec, nfds = 0; 148147072Sbrooks struct protocol *l; 149147072Sbrooks struct pollfd *fds; 150147072Sbrooks time_t howlong; 151147072Sbrooks 152147072Sbrooks for (l = protocols; l; l = l->next) 153147072Sbrooks nfds++; 154147072Sbrooks 155147072Sbrooks fds = malloc(nfds * sizeof(struct pollfd)); 156147072Sbrooks if (fds == NULL) 157147072Sbrooks error("Can't allocate poll structures."); 158147072Sbrooks 159147072Sbrooks do { 160147072Sbrooks /* 161147072Sbrooks * Call any expired timeouts, and then if there's still 162147072Sbrooks * a timeout registered, time out the select call then. 163147072Sbrooks */ 164147072Sbrooksanother: 165147072Sbrooks if (timeouts) { 166147072Sbrooks struct timeout *t; 167147072Sbrooks 168147072Sbrooks if (timeouts->when <= cur_time) { 169147072Sbrooks t = timeouts; 170147072Sbrooks timeouts = timeouts->next; 171147072Sbrooks (*(t->func))(t->what); 172147072Sbrooks t->next = free_timeouts; 173147072Sbrooks free_timeouts = t; 174147072Sbrooks goto another; 175147072Sbrooks } 176147072Sbrooks 177147072Sbrooks /* 178147072Sbrooks * Figure timeout in milliseconds, and check for 179147072Sbrooks * potential overflow, so we can cram into an 180147072Sbrooks * int for poll, while not polling with a 181147072Sbrooks * negative timeout and blocking indefinitely. 182147072Sbrooks */ 183147072Sbrooks howlong = timeouts->when - cur_time; 184147072Sbrooks if (howlong > INT_MAX / 1000) 185147072Sbrooks howlong = INT_MAX / 1000; 186147072Sbrooks to_msec = howlong * 1000; 187147072Sbrooks } else 188147072Sbrooks to_msec = -1; 189147072Sbrooks 190147072Sbrooks /* Set up the descriptors to be polled. */ 191195805Ssam live_interfaces = 0; 192147072Sbrooks for (i = 0, l = protocols; l; l = l->next) { 193147072Sbrooks struct interface_info *ip = l->local; 194147072Sbrooks 195195805Ssam if (ip == NULL || ip->dead) 196195805Ssam continue; 197195805Ssam fds[i].fd = l->fd; 198195805Ssam fds[i].events = POLLIN; 199195805Ssam fds[i].revents = 0; 200195805Ssam i++; 201195805Ssam if (l->handler == got_one) 202195805Ssam live_interfaces++; 203147072Sbrooks } 204195805Ssam if (live_interfaces == 0) 205147072Sbrooks error("No live interfaces to poll on - exiting."); 206147072Sbrooks 207147072Sbrooks /* Wait for a packet or a timeout... XXX */ 208147072Sbrooks count = poll(fds, nfds, to_msec); 209147072Sbrooks 210147072Sbrooks /* Not likely to be transitory... */ 211147072Sbrooks if (count == -1) { 212147072Sbrooks if (errno == EAGAIN || errno == EINTR) { 213147072Sbrooks time(&cur_time); 214147072Sbrooks continue; 215147072Sbrooks } else 216147072Sbrooks error("poll: %m"); 217147072Sbrooks } 218147072Sbrooks 219147072Sbrooks /* Get the current time... */ 220147072Sbrooks time(&cur_time); 221147072Sbrooks 222147072Sbrooks i = 0; 223147072Sbrooks for (l = protocols; l; l = l->next) { 224147072Sbrooks struct interface_info *ip; 225147072Sbrooks ip = l->local; 226147072Sbrooks if ((fds[i].revents & (POLLIN | POLLHUP))) { 227147072Sbrooks fds[i].revents = 0; 228147072Sbrooks if (ip && (l->handler != got_one || 229147072Sbrooks !ip->dead)) 230147072Sbrooks (*(l->handler))(l); 231147072Sbrooks if (interfaces_invalidated) 232147072Sbrooks break; 233147072Sbrooks } 234147072Sbrooks i++; 235147072Sbrooks } 236147072Sbrooks interfaces_invalidated = 0; 237147072Sbrooks } while (1); 238147072Sbrooks} 239147072Sbrooks 240147072Sbrooks 241147072Sbrooksvoid 242147072Sbrooksgot_one(struct protocol *l) 243147072Sbrooks{ 244147072Sbrooks struct sockaddr_in from; 245147072Sbrooks struct hardware hfrom; 246147072Sbrooks struct iaddr ifrom; 247147072Sbrooks ssize_t result; 248147072Sbrooks union { 249147072Sbrooks /* 250147072Sbrooks * Packet input buffer. Must be as large as largest 251147072Sbrooks * possible MTU. 252147072Sbrooks */ 253147072Sbrooks unsigned char packbuf[4095]; 254147072Sbrooks struct dhcp_packet packet; 255147072Sbrooks } u; 256147072Sbrooks struct interface_info *ip = l->local; 257147072Sbrooks 258147072Sbrooks if ((result = receive_packet(ip, u.packbuf, sizeof(u), &from, 259147072Sbrooks &hfrom)) == -1) { 260147072Sbrooks warning("receive_packet failed on %s: %s", ip->name, 261147072Sbrooks strerror(errno)); 262147072Sbrooks ip->errors++; 263147072Sbrooks if ((!interface_status(ip)) || 264147072Sbrooks (ip->noifmedia && ip->errors > 20)) { 265147072Sbrooks /* our interface has gone away. */ 266147072Sbrooks warning("Interface %s no longer appears valid.", 267147072Sbrooks ip->name); 268147072Sbrooks ip->dead = 1; 269147072Sbrooks interfaces_invalidated = 1; 270147072Sbrooks close(l->fd); 271147072Sbrooks remove_protocol(l); 272147072Sbrooks free(ip); 273147072Sbrooks } 274147072Sbrooks return; 275147072Sbrooks } 276147072Sbrooks if (result == 0) 277147072Sbrooks return; 278147072Sbrooks 279147072Sbrooks if (bootp_packet_handler) { 280147072Sbrooks ifrom.len = 4; 281147072Sbrooks memcpy(ifrom.iabuf, &from.sin_addr, ifrom.len); 282147072Sbrooks 283147072Sbrooks (*bootp_packet_handler)(ip, &u.packet, result, 284147072Sbrooks from.sin_port, ifrom, &hfrom); 285147072Sbrooks } 286147072Sbrooks} 287147072Sbrooks 288147072Sbrooksint 289147072Sbrooksinterface_status(struct interface_info *ifinfo) 290147072Sbrooks{ 291147072Sbrooks char *ifname = ifinfo->name; 292147072Sbrooks int ifsock = ifinfo->rfdesc; 293147072Sbrooks struct ifreq ifr; 294147072Sbrooks struct ifmediareq ifmr; 295147072Sbrooks 296147072Sbrooks /* get interface flags */ 297147072Sbrooks memset(&ifr, 0, sizeof(ifr)); 298147072Sbrooks strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 299147072Sbrooks if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) { 300147072Sbrooks syslog(LOG_ERR, "ioctl(SIOCGIFFLAGS) on %s: %m", ifname); 301147072Sbrooks goto inactive; 302147072Sbrooks } 303147072Sbrooks 304147072Sbrooks /* 305147072Sbrooks * if one of UP and RUNNING flags is dropped, 306147072Sbrooks * the interface is not active. 307147072Sbrooks */ 308147072Sbrooks if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 309147072Sbrooks goto inactive; 310147072Sbrooks 311147072Sbrooks /* Next, check carrier on the interface, if possible */ 312147072Sbrooks if (ifinfo->noifmedia) 313147072Sbrooks goto active; 314147072Sbrooks memset(&ifmr, 0, sizeof(ifmr)); 315147072Sbrooks strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); 316147072Sbrooks if (ioctl(ifsock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { 317147072Sbrooks if (errno != EINVAL) { 318147072Sbrooks syslog(LOG_DEBUG, "ioctl(SIOCGIFMEDIA) on %s: %m", 319147072Sbrooks ifname); 320147072Sbrooks 321147072Sbrooks ifinfo->noifmedia = 1; 322147072Sbrooks goto active; 323147072Sbrooks } 324147072Sbrooks /* 325147072Sbrooks * EINVAL (or ENOTTY) simply means that the interface 326147072Sbrooks * does not support the SIOCGIFMEDIA ioctl. We regard it alive. 327147072Sbrooks */ 328147072Sbrooks ifinfo->noifmedia = 1; 329147072Sbrooks goto active; 330147072Sbrooks } 331147072Sbrooks if (ifmr.ifm_status & IFM_AVALID) { 332147072Sbrooks switch (ifmr.ifm_active & IFM_NMASK) { 333147072Sbrooks case IFM_ETHER: 334174314Sjkim case IFM_IEEE80211: 335147072Sbrooks if (ifmr.ifm_status & IFM_ACTIVE) 336147072Sbrooks goto active; 337147072Sbrooks else 338147072Sbrooks goto inactive; 339147072Sbrooks break; 340147072Sbrooks default: 341147072Sbrooks goto inactive; 342147072Sbrooks } 343147072Sbrooks } 344147072Sbrooksinactive: 345147072Sbrooks return (0); 346147072Sbrooksactive: 347147072Sbrooks return (1); 348147072Sbrooks} 349147072Sbrooks 350147072Sbrooksvoid 351147072Sbrooksadd_timeout(time_t when, void (*where)(void *), void *what) 352147072Sbrooks{ 353147072Sbrooks struct timeout *t, *q; 354147072Sbrooks 355147072Sbrooks /* See if this timeout supersedes an existing timeout. */ 356147072Sbrooks t = NULL; 357147072Sbrooks for (q = timeouts; q; q = q->next) { 358147072Sbrooks if (q->func == where && q->what == what) { 359147072Sbrooks if (t) 360147072Sbrooks t->next = q->next; 361147072Sbrooks else 362147072Sbrooks timeouts = q->next; 363147072Sbrooks break; 364147072Sbrooks } 365147072Sbrooks t = q; 366147072Sbrooks } 367147072Sbrooks 368147072Sbrooks /* If we didn't supersede a timeout, allocate a timeout 369147072Sbrooks structure now. */ 370147072Sbrooks if (!q) { 371147072Sbrooks if (free_timeouts) { 372147072Sbrooks q = free_timeouts; 373147072Sbrooks free_timeouts = q->next; 374147072Sbrooks q->func = where; 375147072Sbrooks q->what = what; 376147072Sbrooks } else { 377147072Sbrooks q = malloc(sizeof(struct timeout)); 378147072Sbrooks if (!q) 379147072Sbrooks error("Can't allocate timeout structure!"); 380147072Sbrooks q->func = where; 381147072Sbrooks q->what = what; 382147072Sbrooks } 383147072Sbrooks } 384147072Sbrooks 385147072Sbrooks q->when = when; 386147072Sbrooks 387147072Sbrooks /* Now sort this timeout into the timeout list. */ 388147072Sbrooks 389147072Sbrooks /* Beginning of list? */ 390147072Sbrooks if (!timeouts || timeouts->when > q->when) { 391147072Sbrooks q->next = timeouts; 392147072Sbrooks timeouts = q; 393147072Sbrooks return; 394147072Sbrooks } 395147072Sbrooks 396147072Sbrooks /* Middle of list? */ 397147072Sbrooks for (t = timeouts; t->next; t = t->next) { 398147072Sbrooks if (t->next->when > q->when) { 399147072Sbrooks q->next = t->next; 400147072Sbrooks t->next = q; 401147072Sbrooks return; 402147072Sbrooks } 403147072Sbrooks } 404147072Sbrooks 405147072Sbrooks /* End of list. */ 406147072Sbrooks t->next = q; 407147072Sbrooks q->next = NULL; 408147072Sbrooks} 409147072Sbrooks 410147072Sbrooksvoid 411147072Sbrookscancel_timeout(void (*where)(void *), void *what) 412147072Sbrooks{ 413147072Sbrooks struct timeout *t, *q; 414147072Sbrooks 415147072Sbrooks /* Look for this timeout on the list, and unlink it if we find it. */ 416147072Sbrooks t = NULL; 417147072Sbrooks for (q = timeouts; q; q = q->next) { 418147072Sbrooks if (q->func == where && q->what == what) { 419147072Sbrooks if (t) 420147072Sbrooks t->next = q->next; 421147072Sbrooks else 422147072Sbrooks timeouts = q->next; 423147072Sbrooks break; 424147072Sbrooks } 425147072Sbrooks t = q; 426147072Sbrooks } 427147072Sbrooks 428147072Sbrooks /* If we found the timeout, put it on the free list. */ 429147072Sbrooks if (q) { 430147072Sbrooks q->next = free_timeouts; 431147072Sbrooks free_timeouts = q; 432147072Sbrooks } 433147072Sbrooks} 434147072Sbrooks 435147072Sbrooks/* Add a protocol to the list of protocols... */ 436147072Sbrooksvoid 437147072Sbrooksadd_protocol(char *name, int fd, void (*handler)(struct protocol *), 438147072Sbrooks void *local) 439147072Sbrooks{ 440147072Sbrooks struct protocol *p; 441147072Sbrooks 442147072Sbrooks p = malloc(sizeof(*p)); 443147072Sbrooks if (!p) 444147072Sbrooks error("can't allocate protocol struct for %s", name); 445147072Sbrooks 446147072Sbrooks p->fd = fd; 447147072Sbrooks p->handler = handler; 448147072Sbrooks p->local = local; 449147072Sbrooks p->next = protocols; 450147072Sbrooks protocols = p; 451147072Sbrooks} 452147072Sbrooks 453147072Sbrooksvoid 454147072Sbrooksremove_protocol(struct protocol *proto) 455147072Sbrooks{ 456313103Sasomers struct protocol *p, *next; 457147072Sbrooks 458147072Sbrooks for (p = protocols; p; p = next) { 459147072Sbrooks next = p->next; 460147072Sbrooks if (p == proto) { 461313103Sasomers protocols = p->next; 462147072Sbrooks free(p); 463147072Sbrooks } 464147072Sbrooks } 465147072Sbrooks} 466147072Sbrooks 467147072Sbrooksint 468147072Sbrooksinterface_link_status(char *ifname) 469147072Sbrooks{ 470147072Sbrooks struct ifmediareq ifmr; 471147072Sbrooks int sock; 472147072Sbrooks 473147072Sbrooks if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 474147072Sbrooks error("Can't create socket"); 475147072Sbrooks 476147072Sbrooks memset(&ifmr, 0, sizeof(ifmr)); 477147072Sbrooks strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); 478147072Sbrooks if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) { 479147072Sbrooks /* EINVAL -> link state unknown. treat as active */ 480147072Sbrooks if (errno != EINVAL) 481147072Sbrooks syslog(LOG_DEBUG, "ioctl(SIOCGIFMEDIA) on %s: %m", 482147072Sbrooks ifname); 483147072Sbrooks close(sock); 484147072Sbrooks return (1); 485147072Sbrooks } 486147072Sbrooks close(sock); 487147072Sbrooks 488147072Sbrooks if (ifmr.ifm_status & IFM_AVALID) { 489174314Sjkim switch (ifmr.ifm_active & IFM_NMASK) { 490174314Sjkim case IFM_ETHER: 491174314Sjkim case IFM_IEEE80211: 492147072Sbrooks if (ifmr.ifm_status & IFM_ACTIVE) 493147072Sbrooks return (1); 494147072Sbrooks else 495147072Sbrooks return (0); 496147072Sbrooks } 497147072Sbrooks } 498147072Sbrooks return (1); 499147072Sbrooks} 500