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 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * This file contains routines to retrieve events from the system and package 31 * them for high level processing. 32 * 33 * struct np_event is the basic event structure. The np_event structure and 34 * its npe_name member are allocated using malloc(3c). free_event() frees both 35 * the npe_name member and the associated np_event structure. 36 * 37 * np_queue_add_event() and np_queue_get_event() provide functionality for 38 * adding events to a queue and blocking on that queue for an event. 39 * 40 * Functions of the form addevent_*() provide the mechanism to cook down a 41 * higher level event into an np_event and put it on the queue. 42 * 43 * routing_events() reads routing messages off of an IPv4 routing socket and 44 * by calling addevent_*() functions places appropriate events on the queue. 45 * 46 * start_event_collection() creates a thread to run routing_events() and one 47 * to run periodic_wireless_scan() in. Finally it does an initial collection 48 * of information from each interface currently known. 49 */ 50 51 #include <arpa/inet.h> 52 #include <assert.h> 53 #include <errno.h> 54 #include <libsysevent.h> 55 #include <net/if.h> 56 #include <net/route.h> 57 #include <pthread.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include <sys/fcntl.h> 61 #include <sys/sysevent/eventdefs.h> 62 #include <syslog.h> 63 #include <unistd.h> 64 #include <fcntl.h> 65 66 #include "defines.h" 67 #include "structures.h" 68 #include "functions.h" 69 #include "variables.h" 70 71 struct np_event *equeue = NULL; 72 static struct np_event *equeue_end = NULL; 73 74 pthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER; 75 pthread_cond_t queue_cond = PTHREAD_COND_INITIALIZER; 76 pthread_t routing, scan; 77 78 static void printaddrs(int mask, void *address); 79 static char *printaddr(void **address); 80 static struct sockaddr *dupsockaddr(struct sockaddr *); 81 static boolean_t cmpsockaddr(struct sockaddr *, struct sockaddr *); 82 static void *getaddr(int addrid, int mask, void *address); 83 84 union rtm_buf 85 { 86 /* Routing information. */ 87 struct 88 { 89 struct rt_msghdr rtm; 90 struct sockaddr_storage addr[RTAX_MAX]; 91 } r; 92 93 /* Interface information. */ 94 struct 95 { 96 struct if_msghdr ifm; 97 struct sockaddr_storage addr[RTAX_MAX]; 98 } im; 99 100 /* Interface address information. */ 101 struct 102 { 103 struct ifa_msghdr ifa; 104 struct sockaddr_storage addr[RTAX_MAX]; 105 } ia; 106 }; 107 108 void 109 free_event(struct np_event *e) 110 { 111 free(e->npe_name); 112 free(e); 113 } 114 115 void 116 np_queue_add_event(struct np_event *e) 117 { 118 (void) pthread_mutex_lock(&queue_mutex); 119 if (equeue_end != NULL) { 120 equeue_end->npe_next = e; 121 equeue_end = e; 122 } else { 123 equeue = equeue_end = e; 124 } 125 equeue_end->npe_next = NULL; 126 (void) pthread_cond_signal(&queue_cond); 127 (void) pthread_mutex_unlock(&queue_mutex); 128 } 129 130 /* 131 * Blocking getevent. This routine will block until there is an event for 132 * it to return. 133 */ 134 struct np_event * 135 np_queue_get_event(void) 136 { 137 struct np_event *rv = NULL; 138 139 (void) pthread_mutex_lock(&queue_mutex); 140 141 while (equeue == NULL) 142 (void) pthread_cond_wait(&queue_cond, &queue_mutex); 143 144 rv = equeue; 145 equeue = equeue->npe_next; 146 if (equeue == NULL) 147 equeue_end = NULL; 148 149 (void) pthread_mutex_unlock(&queue_mutex); 150 151 rv->npe_next = NULL; 152 return (rv); 153 } 154 155 const char * 156 npe_type_str(enum np_event_type type) 157 { 158 switch (type) { 159 case EV_ROUTING: 160 return ("ROUTING"); 161 case EV_SYS: 162 return ("SYS"); 163 case EV_TIMER: 164 return ("TIMER"); 165 case EV_SHUTDOWN: 166 return ("SHUTDOWN"); 167 case EV_NEWADDR: 168 return ("NEWADDR"); 169 default: 170 return ("unknown"); 171 } 172 } 173 174 static void 175 addevent_routing_ifa(struct ifa_msghdr *ifa, const char *name) 176 { 177 struct np_event *e; 178 179 dprintf("addevent_routing_ifa"); 180 if (ifa->ifam_index == 0) { 181 /* what is this? */ 182 dprintf("tossing index 0 routing event"); 183 return; 184 } 185 186 e = calloc(1, sizeof (*e)); 187 if (e == NULL) { 188 syslog(LOG_ERR, "calloc failed"); 189 return; 190 } 191 192 switch (ifa->ifam_type) { 193 case RTM_NEWADDR: 194 assert(name != NULL); 195 e->npe_type = EV_NEWADDR; 196 if ((e->npe_name = strdup(name)) == NULL) { 197 syslog(LOG_ERR, "strdup failed"); 198 free(e); 199 return; 200 } 201 dprintf("adding event type %s name %s to queue", 202 npe_type_str(e->npe_type), STRING(e->npe_name)); 203 np_queue_add_event(e); 204 break; 205 206 default: 207 free(e); 208 dprintf("unhandled type in addevent_routing_ifa %d", 209 ifa->ifam_type); 210 break; 211 } 212 } 213 214 static void 215 addevent_routing_msghdr(struct if_msghdr *ifm, const char *name) 216 { 217 struct np_event *e; 218 219 dprintf("addevent_routing_msghdr"); 220 if (ifm->ifm_index == 0) { 221 /* what is this? */ 222 dprintf("tossing index 0 routing event"); 223 return; 224 } 225 226 switch (ifm->ifm_type) { 227 case RTM_IFINFO: 228 assert(name != NULL); 229 e = calloc(1, sizeof (*e)); 230 if (e == NULL) { 231 syslog(LOG_ERR, "calloc failed"); 232 return; 233 } 234 235 e->npe_type = EV_ROUTING; 236 if ((e->npe_name = strdup(name)) == NULL) { 237 syslog(LOG_ERR, "strdup failed"); 238 free(e); 239 return; 240 } 241 dprintf("flags = %x, IFF_RUNNING = %x", ifm->ifm_flags, 242 IFF_RUNNING); 243 dprintf("adding event type %s name %s to queue", 244 npe_type_str(e->npe_type), STRING(e->npe_name)); 245 np_queue_add_event(e); 246 break; 247 248 default: 249 dprintf("unhandled type in addevent_routing_msghdr %d", 250 ifm->ifm_type); 251 break; 252 } 253 } 254 255 static const char * 256 rtmtype_str(int type) 257 { 258 static char typestr[12]; /* strlen("type ") + enough for an int */ 259 260 switch (type) { 261 case RTM_ADD: 262 return ("ADD"); 263 case RTM_DELETE: 264 return ("DELETE"); 265 case RTM_NEWADDR: 266 return ("NEWADDR"); 267 case RTM_DELADDR: 268 return ("DELADDR"); 269 case RTM_IFINFO: 270 return ("IFINFO"); 271 default: 272 (void) snprintf(typestr, sizeof (typestr), "type %d", 273 type); 274 return (typestr); 275 } 276 } 277 278 /* ARGSUSED */ 279 static void * 280 routing_events(void *arg) 281 { 282 int rtsock; 283 int n; 284 union rtm_buf buffer; 285 struct rt_msghdr *rtm; 286 struct ifa_msghdr *ifa; 287 struct if_msghdr *ifm; 288 289 /* 290 * We use v4 interfaces as proxies for links so those are the only 291 * routing messages we need to listen to. Look at the comments in 292 * structures.h for more information about the split between the 293 * llp and interfaces. 294 */ 295 rtsock = socket(AF_ROUTE, SOCK_RAW, AF_INET); 296 if (rtsock == -1) { 297 syslog(LOG_ERR, "failed to open routing socket: %m"); 298 exit(EXIT_FAILURE); 299 } 300 301 dprintf("routing socket %d", rtsock); 302 303 for (;;) { 304 struct interface *ifp; 305 char *addrs, *if_name; 306 struct sockaddr_dl *addr_dl; 307 struct sockaddr *addr; 308 309 rtm = &buffer.r.rtm; 310 n = read(rtsock, &buffer, sizeof (buffer)); 311 if (n == -1 && errno == EAGAIN) { 312 continue; 313 } else if (n == -1) { 314 syslog(LOG_ERR, "error reading routing socket " 315 "%d: %m", rtsock); 316 /* Low likelihood. What's recovery path? */ 317 continue; 318 } 319 320 if (rtm->rtm_msglen < n) { 321 syslog(LOG_ERR, "only read %d bytes from " 322 "routing socket but message claims to be " 323 "of length %d", rtm->rtm_msglen); 324 continue; 325 } 326 327 if (rtm->rtm_version != RTM_VERSION) { 328 syslog(LOG_ERR, "tossing routing message of " 329 "version %d type %d", rtm->rtm_version, 330 rtm->rtm_type); 331 continue; 332 } 333 334 if (rtm->rtm_msglen != n) { 335 dprintf("routing message of %d size came from " 336 "read of %d on socket %d", rtm->rtm_msglen, 337 n, rtsock); 338 } 339 340 switch (rtm->rtm_type) { 341 case RTM_NEWADDR: 342 ifa = (void *)rtm; 343 addrs = (char *)ifa + sizeof (*ifa); 344 345 dprintf("routing message NEWADDR: index %d flags %x", 346 ifa->ifam_index, ifa->ifam_flags); 347 printaddrs(ifa->ifam_addrs, addrs); 348 349 if ((addr = (struct sockaddr *)getaddr(RTA_IFA, 350 ifa->ifam_addrs, addrs)) == NULL) 351 break; 352 353 if ((addr_dl = (struct sockaddr_dl *)getaddr 354 (RTA_IFP, ifa->ifam_addrs, addrs)) == NULL) 355 break; 356 /* 357 * We don't use the lladdr in this structure so we can 358 * run over it. 359 */ 360 addr_dl->sdl_data[addr_dl->sdl_nlen] = 0; 361 if_name = addr_dl->sdl_data; 362 ifp = get_interface(if_name); 363 if (ifp == NULL) { 364 dprintf("no interface struct for %s; ignoring " 365 "message", STRING(if_name)); 366 break; 367 } 368 369 /* if no cached address, cache it */ 370 if (ifp->if_ipaddr == NULL) { 371 ifp->if_ipaddr = dupsockaddr(addr); 372 dprintf("cached address %s for link %s", 373 printaddr((void **)&addr), if_name); 374 addevent_routing_ifa(ifa, if_name); 375 } else if (!cmpsockaddr(addr, ifp->if_ipaddr)) { 376 free(ifp->if_ipaddr); 377 ifp->if_ipaddr = dupsockaddr(addr); 378 addevent_routing_ifa(ifa, if_name); 379 } 380 break; 381 case RTM_IFINFO: 382 { 383 boolean_t plugged_in; 384 385 ifm = (void *)rtm; 386 addrs = (char *)ifm + sizeof (*ifm); 387 dprintf("routing message IFINFO: index %d flags %x", 388 ifm->ifm_index, ifm->ifm_flags); 389 printaddrs(ifm->ifm_addrs, addrs); 390 391 if ((addr_dl = (struct sockaddr_dl *)getaddr(RTA_IFP, 392 ifm->ifm_addrs, addrs)) == NULL) 393 break; 394 /* 395 * We don't use the lladdr in this structure so we can 396 * run over it. 397 */ 398 addr_dl->sdl_data[addr_dl->sdl_nlen] = 0; 399 if_name = addr_dl->sdl_data; 400 ifp = get_interface(if_name); 401 if (ifp == NULL) { 402 dprintf("no interface struct for %s; ignoring " 403 "message", STRING(if_name)); 404 break; 405 } 406 407 /* 408 * Check for toggling of the IFF_RUNNING 409 * flag. 410 * 411 * On any change in the flag value, we 412 * turn off the DHCPFAILED and DHCPSTARTED 413 * flags; the change in the RUNNING state 414 * indicates a "fresh start" for the 415 * interface, so we should try dhcp again. 416 * 417 * Ignore specific IFF_RUNNING changes for 418 * wireless interfaces; their semantics are 419 * a bit different (either the flag is always 420 * on, or, with newer drivers, it indicates 421 * whether or not they are connected to an AP). 422 * 423 * For wired interfaces, if the interface was 424 * not plugged in and now it is, start info 425 * collection. 426 * 427 * If it was plugged in and now it is 428 * unplugged, generate an event. 429 * 430 * XXX We probably need a lock to protect 431 * if_flags setting and getting. 432 */ 433 if ((ifp->if_flags & IFF_RUNNING) != 434 (ifm->ifm_flags & IFF_RUNNING)) { 435 ifp->if_lflags &= ~IF_DHCPFAILED; 436 ifp->if_lflags &= ~IF_DHCPSTARTED; 437 } 438 if (ifp->if_type == IF_WIRELESS) 439 break; 440 plugged_in = 441 ((ifp->if_flags & IFF_RUNNING) != 0); 442 ifp->if_flags = ifm->ifm_flags; 443 if (!plugged_in && 444 (ifm->ifm_flags & IFF_RUNNING)) { 445 start_if_info_collect(ifp, NULL); 446 } else if (plugged_in && 447 !(ifm->ifm_flags & IFF_RUNNING)) { 448 check_drop_dhcp(ifp); 449 addevent_routing_msghdr(ifm, if_name); 450 } 451 break; 452 } 453 default: 454 dprintf("routing message %s socket %d discarded", 455 rtmtype_str(rtm->rtm_type), rtsock); 456 break; 457 } 458 } 459 /* NOTREACHED */ 460 return (NULL); 461 } 462 463 /* return B_TRUE if sin_family and sin_addr are the same, B_FALSE if not */ 464 static boolean_t 465 cmpsockaddr(struct sockaddr *addr1, struct sockaddr *addr2) 466 { 467 struct sockaddr_in *sina, *sinb; 468 struct sockaddr_in6 *sin6a, *sin6b; 469 470 if (addr1->sa_family != addr2->sa_family) 471 return (B_FALSE); 472 473 switch (addr1->sa_family) { 474 case AF_INET: 475 /* LINTED E_BAD_PTR_CAST_ALIGN */ 476 sina = (struct sockaddr_in *)addr1; 477 /* LINTED E_BAD_PTR_CAST_ALIGN */ 478 sinb = (struct sockaddr_in *)addr2; 479 return (sina->sin_addr.s_addr == sinb->sin_addr.s_addr); 480 case AF_INET6: 481 /* LINTED E_BAD_PTR_CAST_ALIGN */ 482 sin6a = (struct sockaddr_in6 *)addr1; 483 /* LINTED E_BAD_PTR_CAST_ALIGN */ 484 sin6b = (struct sockaddr_in6 *)addr2; 485 return 486 (IN6_ARE_ADDR_EQUAL(&sin6a->sin6_addr, &sin6b->sin6_addr)); 487 default: 488 dprintf("cmpsockaddr: unsupported af (%d)", addr1->sa_family); 489 return (B_FALSE); 490 } 491 } 492 493 /* 494 * Duplicate a sockaddr. Caller will be responsible for freeing memory when it 495 * is no longer needed. Currently only supports AF_INET and AF_INET6 496 * (returns NULL otherwise). 497 */ 498 static struct sockaddr * 499 dupsockaddr(struct sockaddr *addr) 500 { 501 struct sockaddr_in *t1, *ret1; 502 struct sockaddr_in6 *t2, *ret2; 503 504 switch (addr->sa_family) { 505 case AF_INET: 506 if ((ret1 = calloc(1, sizeof (struct sockaddr_in))) == NULL) { 507 syslog(LOG_ERR, "dupsockaddr: calloc failed"); 508 return (NULL); 509 } 510 /* LINTED E_BAD_PTR_CAST_ALIGN */ 511 t1 = (struct sockaddr_in *)addr; 512 ret1->sin_family = t1->sin_family; 513 ret1->sin_addr.s_addr = t1->sin_addr.s_addr; 514 return ((struct sockaddr *)ret1); 515 case AF_INET6: 516 if ((ret2 = calloc(1, sizeof (struct sockaddr_in6))) == NULL) { 517 syslog(LOG_ERR, "dupsockaddr: calloc failed"); 518 return (NULL); 519 } 520 /* LINTED E_BAD_PTR_CAST_ALIGN */ 521 t2 = (struct sockaddr_in6 *)addr; 522 ret2->sin6_family = t2->sin6_family; 523 (void) memcpy((void *)&ret2->sin6_addr, 524 (const void *)&t2->sin6_addr, sizeof (struct in6_addr)); 525 return ((struct sockaddr *)ret2); 526 default: 527 dprintf("dupsockaddr: unsupported af (%d)", addr->sa_family); 528 return (NULL); 529 } 530 } 531 532 static char * 533 printaddr(void **address) 534 { 535 static char buffer[80]; 536 sa_family_t family = *(sa_family_t *)*address; 537 struct sockaddr_in *s4 = *address; 538 struct sockaddr_in6 *s6 = *address; 539 struct sockaddr_dl *dl = *address; 540 541 switch (family) { 542 case AF_UNSPEC: 543 (void) inet_ntop(AF_UNSPEC, &s4->sin_addr, buffer, 544 sizeof (buffer)); 545 *address = (char *)*address + sizeof (*s4); 546 break; 547 case AF_INET: 548 (void) inet_ntop(AF_INET, &s4->sin_addr, buffer, 549 sizeof (buffer)); 550 *address = (char *)*address + sizeof (*s4); 551 break; 552 case AF_INET6: 553 (void) inet_ntop(AF_INET6, &s6->sin6_addr, buffer, 554 sizeof (buffer)); 555 *address = (char *)*address + sizeof (*s6); 556 break; 557 case AF_LINK: 558 (void) snprintf(buffer, sizeof (buffer), "link %.*s", 559 dl->sdl_nlen, dl->sdl_data); 560 *address = (char *)*address + sizeof (*dl); 561 break; 562 default: 563 /* 564 * We can't reliably update the size of this thing 565 * because we don't know what its type is. So bump 566 * it by a sockaddr_in and see what happens. The 567 * caller should really make sure this never happens. 568 */ 569 *address = (char *)*address + sizeof (*s4); 570 (void) snprintf(buffer, sizeof (buffer), 571 "unknown address family %d", family); 572 break; 573 } 574 return (buffer); 575 } 576 577 static void 578 printaddrs(int mask, void *address) 579 { 580 if (mask == 0) 581 return; 582 if (mask & RTA_DST) 583 dprintf("destination address: %s", printaddr(&address)); 584 if (mask & RTA_GATEWAY) 585 dprintf("gateway address: %s", printaddr(&address)); 586 if (mask & RTA_NETMASK) 587 dprintf("netmask: %s", printaddr(&address)); 588 if (mask & RTA_GENMASK) 589 dprintf("cloning mask: %s", printaddr(&address)); 590 if (mask & RTA_IFP) 591 dprintf("interface name: %s", printaddr(&address)); 592 if (mask & RTA_IFA) 593 dprintf("interface address: %s", printaddr(&address)); 594 if (mask & RTA_AUTHOR) 595 dprintf("author: %s", printaddr(&address)); 596 if (mask & RTA_BRD) 597 dprintf("broadcast address: %s", printaddr(&address)); 598 } 599 600 static void 601 nextaddr(void **address) 602 { 603 sa_family_t family = *(sa_family_t *)*address; 604 605 switch (family) { 606 case AF_UNSPEC: 607 case AF_INET: 608 *address = (char *)*address + sizeof (struct sockaddr_in); 609 break; 610 case AF_INET6: 611 *address = (char *)*address + sizeof (struct sockaddr_in6); 612 break; 613 case AF_LINK: 614 *address = (char *)*address + sizeof (struct sockaddr_dl); 615 break; 616 default: 617 syslog(LOG_ERR, "unknown af (%d) while parsing rtm", family); 618 break; 619 } 620 } 621 622 static void * 623 getaddr(int addrid, int mask, void *address) 624 { 625 int i; 626 void *p = address; 627 628 if ((mask & addrid) == 0) 629 return (NULL); 630 631 for (i = 1; i < addrid; i <<= 1) { 632 if (i & mask) 633 nextaddr(&p); 634 } 635 return (p); 636 } 637 638 boolean_t 639 start_event_collection(void) 640 { 641 int err; 642 643 /* 644 * if these are ever created/destroyed repetitively then we will 645 * have to change this. 646 */ 647 648 if (err = pthread_create(&routing, NULL, routing_events, NULL)) { 649 syslog(LOG_ERR, "pthread_create routing: %s", strerror(err)); 650 exit(EXIT_FAILURE); 651 } else { 652 dprintf("routing thread: %d", routing); 653 } 654 655 if (err = pthread_create(&scan, NULL, periodic_wireless_scan, NULL)) { 656 syslog(LOG_ERR, "pthread_create wireless scan: %s", 657 strerror(err)); 658 exit(EXIT_FAILURE); 659 } else { 660 dprintf("scan thread: %d", scan); 661 } 662 663 walk_interface(start_if_info_collect, NULL); 664 665 return (B_TRUE); 666 } 667