1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * This file contains routines to retrieve events from the system and package 29 * them for high level processing. 30 * 31 * struct np_event is the basic event structure. The np_event structure and 32 * its npe_name member are allocated using malloc(3c). free_event() frees both 33 * the npe_name member and the associated np_event structure. 34 * 35 * np_queue_add_event() and np_queue_get_event() provide functionality for 36 * adding events to a queue and blocking on that queue for an event. 37 * 38 * Functions of the form addevent_*() provide the mechanism to cook down a 39 * higher level event into an np_event and put it on the queue. 40 * 41 * hotplug_handler() is called for EC_DEV_ADD and EC_DEV_REMOVE hotplug events 42 * of class ESC_NETWORK - i.e. hotplug insertion/removal of network card - 43 * and plumbs/unplumbs the interface, adding/removing it from running 44 * configuration (the interface and llp lists). 45 * 46 * routing_events() reads routing messages off of an IPv4 routing socket and 47 * by calling addevent_*() functions places appropriate events on the queue. 48 * 49 * start_event_collection() creates a thread to run routing_events() and one 50 * to run periodic_wireless_scan() in. Finally it does an initial collection 51 * of information from each interface currently known. 52 */ 53 54 #include <arpa/inet.h> 55 #include <errno.h> 56 #include <libsysevent.h> 57 #include <sys/sysevent/eventdefs.h> 58 #include <sys/sysevent/dev.h> 59 #include <libnvpair.h> 60 #include <net/if.h> 61 #include <net/route.h> 62 #include <pthread.h> 63 #include <stdlib.h> 64 #include <string.h> 65 #include <sys/fcntl.h> 66 #include <syslog.h> 67 #include <unistd.h> 68 69 #include "defines.h" 70 #include "structures.h" 71 #include "functions.h" 72 #include "variables.h" 73 74 struct np_event *equeue; 75 static struct np_event *equeue_end; 76 77 pthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER; 78 pthread_cond_t queue_cond = PTHREAD_COND_INITIALIZER; 79 pthread_t routing, scan; 80 81 static sysevent_handle_t *sysevent_handle; 82 83 static void hotplug_handler(sysevent_t *ev); 84 static void printaddrs(int mask, void *address); 85 static char *printaddr(void **address); 86 static void *getaddr(int addrid, int mask, void *address); 87 88 union rtm_buf 89 { 90 /* Routing information. */ 91 struct 92 { 93 struct rt_msghdr rtm; 94 struct sockaddr_storage addr[RTAX_MAX]; 95 } r; 96 97 /* Interface information. */ 98 struct 99 { 100 struct if_msghdr ifm; 101 struct sockaddr_storage addr[RTAX_MAX]; 102 } im; 103 104 /* Interface address information. */ 105 struct 106 { 107 struct ifa_msghdr ifa; 108 struct sockaddr_storage addr[RTAX_MAX]; 109 } ia; 110 }; 111 112 void 113 free_event(struct np_event *npe) 114 { 115 free(npe); 116 } 117 118 boolean_t 119 np_queue_add_event(enum np_event_type evt, const char *ifname) 120 { 121 struct np_event *npe; 122 size_t slen; 123 124 slen = ifname == NULL ? 0 : (strlen(ifname) + 1); 125 if ((npe = calloc(1, sizeof (*npe) + slen)) == NULL) { 126 syslog(LOG_ERR, "event %s alloc for %s failed", 127 npe_type_str(evt), STRING(ifname)); 128 return (B_FALSE); 129 } 130 if (ifname != NULL) 131 npe->npe_name = strcpy((char *)(npe + 1), ifname); 132 npe->npe_type = evt; 133 134 (void) pthread_mutex_lock(&queue_mutex); 135 dprintf("adding event type %s name %s to queue", 136 npe_type_str(evt), STRING(ifname)); 137 if (equeue_end != NULL) { 138 equeue_end->npe_next = npe; 139 equeue_end = npe; 140 } else { 141 equeue = equeue_end = npe; 142 } 143 equeue_end->npe_next = NULL; 144 (void) pthread_cond_signal(&queue_cond); 145 (void) pthread_mutex_unlock(&queue_mutex); 146 return (B_TRUE); 147 } 148 149 /* 150 * Blocking getevent. This routine will block until there is an event for 151 * it to return. 152 */ 153 struct np_event * 154 np_queue_get_event(void) 155 { 156 struct np_event *rv = NULL; 157 158 (void) pthread_mutex_lock(&queue_mutex); 159 160 while (equeue == NULL) 161 (void) pthread_cond_wait(&queue_cond, &queue_mutex); 162 163 rv = equeue; 164 equeue = equeue->npe_next; 165 if (equeue == NULL) 166 equeue_end = NULL; 167 168 (void) pthread_mutex_unlock(&queue_mutex); 169 170 rv->npe_next = NULL; 171 return (rv); 172 } 173 174 const char * 175 npe_type_str(enum np_event_type type) 176 { 177 switch (type) { 178 case EV_LINKDROP: 179 return ("LINKDROP"); 180 case EV_LINKUP: 181 return ("LINKUP"); 182 case EV_LINKFADE: 183 return ("LINKFADE"); 184 case EV_LINKDISC: 185 return ("LINKDISC"); 186 case EV_NEWAP: 187 return ("NEWAP"); 188 case EV_USER: 189 return ("USER"); 190 case EV_TIMER: 191 return ("TIMER"); 192 case EV_SHUTDOWN: 193 return ("SHUTDOWN"); 194 case EV_NEWADDR: 195 return ("NEWADDR"); 196 case EV_RESELECT: 197 return ("RESELECT"); 198 case EV_DOOR_TIME: 199 return ("DOOR_TIME"); 200 case EV_ADDIF: 201 return ("ADDIF"); 202 case EV_REMIF: 203 return ("REMIF"); 204 case EV_TAKEDOWN: 205 return ("TAKEDOWN"); 206 default: 207 return ("unknown"); 208 } 209 } 210 211 static const char * 212 rtmtype_str(int type) 213 { 214 static char typestr[12]; /* strlen("type ") + enough for an int */ 215 216 switch (type) { 217 case RTM_ADD: 218 return ("ADD"); 219 case RTM_DELETE: 220 return ("DELETE"); 221 case RTM_NEWADDR: 222 return ("NEWADDR"); 223 case RTM_DELADDR: 224 return ("DELADDR"); 225 case RTM_IFINFO: 226 return ("IFINFO"); 227 default: 228 (void) snprintf(typestr, sizeof (typestr), "type %d", 229 type); 230 return (typestr); 231 } 232 } 233 234 /* 235 * At present, we only handle EC_DEV_ADD/EC_DEV_REMOVE sysevents of 236 * subclass ESC_NETWORK. These signify hotplug addition/removal. 237 * 238 * The sysevents are converted into NWAM events so that we can process them in 239 * the main loop. If we didn't do this, we'd either have bad pointer 240 * references or need to have reference counts on everything. Serializing 241 * through the event mechanism is much simpler. 242 */ 243 static void 244 hotplug_handler(sysevent_t *ev) 245 { 246 int32_t instance; 247 char *driver; 248 char ifname[LIFNAMSIZ]; 249 nvlist_t *attr_list; 250 char *event_class = sysevent_get_class_name(ev); 251 char *event_subclass = sysevent_get_subclass_name(ev); 252 int retv; 253 254 dprintf("hotplug_handler: event %s/%s", event_class, 255 event_subclass); 256 257 /* Make sure sysevent is of expected class/subclass */ 258 if ((strcmp(event_class, EC_DEV_ADD) != 0 && 259 strcmp(event_class, EC_DEV_REMOVE) != 0) || 260 strcmp(event_subclass, ESC_NETWORK) != 0) { 261 syslog(LOG_ERR, "hotplug_handler: unexpected sysevent " 262 "class/subclass %s/%s", event_class, event_subclass); 263 return; 264 } 265 266 /* 267 * Retrieve driver name and instance attributes, and combine to 268 * get interface name. 269 */ 270 if (sysevent_get_attr_list(ev, &attr_list) != 0) { 271 syslog(LOG_ERR, "hotplug_handler: sysevent_get_attr_list: %m"); 272 return; 273 } 274 retv = nvlist_lookup_string(attr_list, DEV_DRIVER_NAME, &driver); 275 if (retv == 0) 276 retv = nvlist_lookup_int32(attr_list, DEV_INSTANCE, &instance); 277 if (retv != 0) { 278 syslog(LOG_ERR, "handle_hotplug_interface: nvlist_lookup " 279 "of attributes failed: %s", strerror(retv)); 280 } else { 281 (void) snprintf(ifname, LIFNAMSIZ, "%s%d", driver, instance); 282 (void) np_queue_add_event(strcmp(event_class, EC_DEV_ADD) == 0 ? 283 EV_ADDIF : EV_REMIF, ifname); 284 } 285 nvlist_free(attr_list); 286 } 287 288 static void 289 hotplug_events_unregister(void) 290 { 291 /* Unsubscribe to sysevents */ 292 sysevent_unbind_handle(sysevent_handle); 293 sysevent_handle = NULL; 294 } 295 296 static void 297 hotplug_events_register(void) 298 { 299 const char *subclass = ESC_NETWORK; 300 301 sysevent_handle = sysevent_bind_handle(hotplug_handler); 302 if (sysevent_handle == NULL) { 303 syslog(LOG_ERR, "sysevent_bind_handle: %s", strerror(errno)); 304 return; 305 } 306 /* 307 * Subscribe to ESC_NETWORK subclass of EC_DEV_ADD and EC_DEV_REMOVE 308 * events. As a result, we get sysevent notification of hotplug 309 * add/remove events, which we handle above in hotplug_event_handler(). 310 */ 311 if (sysevent_subscribe_event(sysevent_handle, EC_DEV_ADD, &subclass, 1) 312 != 0 || sysevent_subscribe_event(sysevent_handle, EC_DEV_REMOVE, 313 &subclass, 1) != 0) { 314 syslog(LOG_ERR, "sysevent_subscribe_event: %s", 315 strerror(errno)); 316 hotplug_events_unregister(); 317 } 318 } 319 320 /* 321 * This thread reads routing socket events and sends them to the main state 322 * machine. We must be careful with access to interface data structures here, 323 * as we're not the main thread, which may delete things. Holding a pointer is 324 * not allowed. 325 */ 326 /* ARGSUSED */ 327 static void * 328 routing_events(void *arg) 329 { 330 int rtsock; 331 int n; 332 union rtm_buf buffer; 333 struct rt_msghdr *rtm; 334 struct ifa_msghdr *ifa; 335 struct if_msghdr *ifm; 336 337 /* 338 * We use v4 interfaces as proxies for links so those are the only 339 * routing messages we need to listen to. Look at the comments in 340 * structures.h for more information about the split between the 341 * llp and interfaces. 342 */ 343 rtsock = socket(AF_ROUTE, SOCK_RAW, AF_INET); 344 if (rtsock == -1) { 345 syslog(LOG_ERR, "failed to open routing socket: %m"); 346 exit(EXIT_FAILURE); 347 } 348 349 dprintf("routing socket %d", rtsock); 350 351 for (;;) { 352 char *addrs; 353 struct sockaddr_dl *addr_dl; 354 struct sockaddr_in *addr_in; 355 356 rtm = &buffer.r.rtm; 357 n = read(rtsock, &buffer, sizeof (buffer)); 358 if (n == -1 && errno == EAGAIN) { 359 continue; 360 } else if (n == -1) { 361 syslog(LOG_ERR, "error reading routing socket " 362 "%d: %m", rtsock); 363 /* Low likelihood. What's recovery path? */ 364 continue; 365 } 366 367 if (rtm->rtm_msglen < n) { 368 syslog(LOG_ERR, "only read %d bytes from " 369 "routing socket but message claims to be " 370 "of length %d", rtm->rtm_msglen); 371 continue; 372 } 373 374 if (rtm->rtm_version != RTM_VERSION) { 375 syslog(LOG_ERR, "tossing routing message of " 376 "version %d type %d", rtm->rtm_version, 377 rtm->rtm_type); 378 continue; 379 } 380 381 if (rtm->rtm_msglen != n) { 382 dprintf("routing message of %d size came from " 383 "read of %d on socket %d", rtm->rtm_msglen, 384 n, rtsock); 385 } 386 387 switch (rtm->rtm_type) { 388 case RTM_DELADDR: { 389 uint64_t ifflags; 390 391 /* 392 * Check for failure due to CR 6745448: if we get a 393 * report that an address has been deleted, then check 394 * for interface up, datalink down, and actual address 395 * non-zero. If that combination is seen, then this is 396 * a DHCP cached lease, and we need to remove it from 397 * the system, or it'll louse up the kernel routes 398 * (which aren't smart enough to avoid dead 399 * interfaces). 400 */ 401 ifa = (void *)rtm; 402 addrs = (char *)ifa + sizeof (*ifa); 403 404 dprintf("routing message DELADDR: index %d flags %x", 405 ifa->ifam_index, ifa->ifam_flags); 406 printaddrs(ifa->ifam_addrs, addrs); 407 408 if (ifa->ifam_index == 0) { 409 /* what is this? */ 410 dprintf("tossing index 0 routing event"); 411 break; 412 } 413 414 addr_in = getaddr(RTA_IFA, ifa->ifam_addrs, addrs); 415 if (addr_in == NULL) { 416 dprintf("no RTA_IFA in RTM_DELADDR message"); 417 break; 418 } 419 420 addr_dl = getaddr(RTA_IFP, ifa->ifam_addrs, addrs); 421 if (addr_dl == NULL) { 422 dprintf("no RTA_IFP in RTM_DELADDR message"); 423 break; 424 } 425 426 addr_dl->sdl_data[addr_dl->sdl_nlen] = 0; 427 428 if (addr_in->sin_addr.s_addr == INADDR_ANY) { 429 ifflags = get_ifflags(addr_dl->sdl_data, 430 AF_INET); 431 if ((ifflags & IFF_UP) && 432 !(ifflags & IFF_RUNNING)) 433 zero_out_v4addr(addr_dl->sdl_data); 434 } 435 break; 436 } 437 438 case RTM_NEWADDR: 439 ifa = (void *)rtm; 440 addrs = (char *)ifa + sizeof (*ifa); 441 442 dprintf("routing message NEWADDR: index %d flags %x", 443 ifa->ifam_index, ifa->ifam_flags); 444 printaddrs(ifa->ifam_addrs, addrs); 445 446 if (ifa->ifam_index == 0) { 447 /* what is this? */ 448 dprintf("tossing index 0 routing event"); 449 break; 450 } 451 452 addr_in = getaddr(RTA_IFA, ifa->ifam_addrs, addrs); 453 if (addr_in == NULL) { 454 dprintf("no RTA_IFA in RTM_NEWADDR message"); 455 break; 456 } 457 458 addr_dl = getaddr(RTA_IFP, ifa->ifam_addrs, addrs); 459 if (addr_dl == NULL) { 460 dprintf("no RTA_IFP in RTM_NEWADDR message"); 461 break; 462 } 463 464 /* 465 * We don't use the lladdr in this structure so we can 466 * run over it. 467 */ 468 addr_dl->sdl_data[addr_dl->sdl_nlen] = 0; 469 470 update_interface_v4_address(addr_dl->sdl_data, 471 addr_in->sin_addr.s_addr); 472 break; 473 474 case RTM_IFINFO: 475 ifm = (void *)rtm; 476 addrs = (char *)ifm + sizeof (*ifm); 477 dprintf("routing message IFINFO: index %d flags %x", 478 ifm->ifm_index, ifm->ifm_flags); 479 printaddrs(ifm->ifm_addrs, addrs); 480 481 if (ifm->ifm_index == 0) { 482 dprintf("tossing index 0 routing event"); 483 break; 484 } 485 486 addr_dl = getaddr(RTA_IFP, ifm->ifm_addrs, addrs); 487 if (addr_dl == NULL) { 488 dprintf("no RTA_IFP in RTM_IFINFO message"); 489 break; 490 } 491 492 /* 493 * We don't use the lladdr in this structure so we can 494 * run over it. 495 */ 496 addr_dl->sdl_data[addr_dl->sdl_nlen] = 0; 497 498 update_interface_flags(addr_dl->sdl_data, 499 ifm->ifm_flags); 500 break; 501 502 default: 503 dprintf("routing message %s socket %d discarded", 504 rtmtype_str(rtm->rtm_type), rtsock); 505 break; 506 } 507 } 508 /* NOTREACHED */ 509 return (NULL); 510 } 511 512 static char * 513 printaddr(void **address) 514 { 515 static char buffer[80]; 516 sa_family_t family = *(sa_family_t *)*address; 517 struct sockaddr_in *s4 = *address; 518 struct sockaddr_in6 *s6 = *address; 519 struct sockaddr_dl *dl = *address; 520 521 switch (family) { 522 case AF_UNSPEC: 523 (void) inet_ntop(AF_UNSPEC, &s4->sin_addr, buffer, 524 sizeof (buffer)); 525 *address = (char *)*address + sizeof (*s4); 526 break; 527 case AF_INET: 528 (void) inet_ntop(AF_INET, &s4->sin_addr, buffer, 529 sizeof (buffer)); 530 *address = (char *)*address + sizeof (*s4); 531 break; 532 case AF_INET6: 533 (void) inet_ntop(AF_INET6, &s6->sin6_addr, buffer, 534 sizeof (buffer)); 535 *address = (char *)*address + sizeof (*s6); 536 break; 537 case AF_LINK: 538 (void) snprintf(buffer, sizeof (buffer), "link %.*s", 539 dl->sdl_nlen, dl->sdl_data); 540 *address = (char *)*address + sizeof (*dl); 541 break; 542 default: 543 /* 544 * We can't reliably update the size of this thing 545 * because we don't know what its type is. So bump 546 * it by a sockaddr_in and see what happens. The 547 * caller should really make sure this never happens. 548 */ 549 *address = (char *)*address + sizeof (*s4); 550 (void) snprintf(buffer, sizeof (buffer), 551 "unknown address family %d", family); 552 break; 553 } 554 return (buffer); 555 } 556 557 static void 558 printaddrs(int mask, void *address) 559 { 560 if (mask == 0) 561 return; 562 if (mask & RTA_DST) 563 dprintf("destination address: %s", printaddr(&address)); 564 if (mask & RTA_GATEWAY) 565 dprintf("gateway address: %s", printaddr(&address)); 566 if (mask & RTA_NETMASK) 567 dprintf("netmask: %s", printaddr(&address)); 568 if (mask & RTA_GENMASK) 569 dprintf("cloning mask: %s", printaddr(&address)); 570 if (mask & RTA_IFP) 571 dprintf("interface name: %s", printaddr(&address)); 572 if (mask & RTA_IFA) 573 dprintf("interface address: %s", printaddr(&address)); 574 if (mask & RTA_AUTHOR) 575 dprintf("author: %s", printaddr(&address)); 576 if (mask & RTA_BRD) 577 dprintf("broadcast address: %s", printaddr(&address)); 578 } 579 580 static void 581 nextaddr(void **address) 582 { 583 sa_family_t family = *(sa_family_t *)*address; 584 585 switch (family) { 586 case AF_UNSPEC: 587 case AF_INET: 588 *address = (char *)*address + sizeof (struct sockaddr_in); 589 break; 590 case AF_INET6: 591 *address = (char *)*address + sizeof (struct sockaddr_in6); 592 break; 593 case AF_LINK: 594 *address = (char *)*address + sizeof (struct sockaddr_dl); 595 break; 596 default: 597 syslog(LOG_ERR, "unknown af (%d) while parsing rtm", family); 598 break; 599 } 600 } 601 602 static void * 603 getaddr(int addrid, int mask, void *address) 604 { 605 int i; 606 void *p = address; 607 608 if ((mask & addrid) == 0) 609 return (NULL); 610 611 for (i = 1; i < addrid; i <<= 1) { 612 if (i & mask) 613 nextaddr(&p); 614 } 615 return (p); 616 } 617 618 boolean_t 619 start_event_collection(void) 620 { 621 int err; 622 623 /* 624 * if these are ever created/destroyed repetitively then we will 625 * have to change this. 626 */ 627 628 if (err = pthread_create(&routing, NULL, routing_events, NULL)) { 629 syslog(LOG_ERR, "pthread_create routing: %s", strerror(err)); 630 exit(EXIT_FAILURE); 631 } else { 632 dprintf("routing thread: %d", routing); 633 } 634 635 if (err = pthread_create(&scan, NULL, periodic_wireless_scan, NULL)) { 636 syslog(LOG_ERR, "pthread_create wireless scan: %s", 637 strerror(err)); 638 exit(EXIT_FAILURE); 639 } else { 640 dprintf("scan thread: %d", scan); 641 } 642 643 /* 644 * This function registers a callback which will get a dedicated thread 645 * for handling of hotplug sysevents when they occur. 646 */ 647 hotplug_events_register(); 648 649 dprintf("initial interface scan"); 650 walk_interface(start_if_info_collect, "check"); 651 652 return (B_TRUE); 653 } 654