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 if_name = addr_dl->sdl_data; 357 ifp = get_interface(if_name); 358 if (ifp == NULL) { 359 dprintf("no interface struct for %s; ignoring " 360 "message", STRING(if_name)); 361 break; 362 } 363 364 /* if no cached address, cache it */ 365 if (ifp->if_ipaddr == NULL) { 366 ifp->if_ipaddr = dupsockaddr(addr); 367 dprintf("cached address %s for link %s", 368 printaddr((void **)&addr), if_name); 369 addevent_routing_ifa(ifa, if_name); 370 } else if (!cmpsockaddr(addr, ifp->if_ipaddr)) { 371 free(ifp->if_ipaddr); 372 ifp->if_ipaddr = dupsockaddr(addr); 373 addevent_routing_ifa(ifa, if_name); 374 } 375 break; 376 case RTM_IFINFO: 377 { 378 boolean_t plugged_in; 379 380 ifm = (void *)rtm; 381 addrs = (char *)ifm + sizeof (*ifm); 382 dprintf("routing message IFINFO: index %d flags %x", 383 ifm->ifm_index, ifm->ifm_flags); 384 printaddrs(ifm->ifm_addrs, addrs); 385 386 if ((addr_dl = (struct sockaddr_dl *)getaddr(RTA_IFP, 387 ifm->ifm_addrs, addrs)) == NULL) 388 break; 389 if_name = addr_dl->sdl_data; 390 ifp = get_interface(if_name); 391 if (ifp == NULL) { 392 dprintf("no interface struct for %s; ignoring " 393 "message", STRING(if_name)); 394 break; 395 } 396 397 /* 398 * Check for toggling of the IFF_RUNNING 399 * flag. 400 * 401 * On any change in the flag value, we 402 * turn off the DHCPFAILED and DHCPSTARTED 403 * flags; the change in the RUNNING state 404 * indicates a "fresh start" for the 405 * interface, so we should try dhcp again. 406 * 407 * Ignore specific IFF_RUNNING changes for 408 * wireless interfaces; their semantics are 409 * a bit different (either the flag is always 410 * on, or, with newer drivers, it indicates 411 * whether or not they are connected to an AP). 412 * 413 * For wired interfaces, if the interface was 414 * not plugged in and now it is, start info 415 * collection. 416 * 417 * If it was plugged in and now it is 418 * unplugged, generate an event. 419 * 420 * XXX We probably need a lock to protect 421 * if_flags setting and getting. 422 */ 423 if ((ifp->if_flags & IFF_RUNNING) != 424 (ifm->ifm_flags & IFF_RUNNING)) { 425 ifp->if_lflags &= ~IF_DHCPFAILED; 426 ifp->if_lflags &= ~IF_DHCPSTARTED; 427 } 428 if (ifp->if_type == IF_WIRELESS) 429 break; 430 plugged_in = 431 ((ifp->if_flags & IFF_RUNNING) != 0); 432 ifp->if_flags = ifm->ifm_flags; 433 if (!plugged_in && 434 (ifm->ifm_flags & IFF_RUNNING)) { 435 start_if_info_collect(ifp, NULL); 436 } else if (plugged_in && 437 !(ifm->ifm_flags & IFF_RUNNING)) { 438 check_drop_dhcp(ifp); 439 addevent_routing_msghdr(ifm, if_name); 440 } 441 break; 442 } 443 default: 444 dprintf("routing message %s socket %d discarded", 445 rtmtype_str(rtm->rtm_type), rtsock); 446 break; 447 } 448 } 449 /* NOTREACHED */ 450 return (NULL); 451 } 452 453 /* return B_TRUE if sin_family and sin_addr are the same, B_FALSE if not */ 454 static boolean_t 455 cmpsockaddr(struct sockaddr *addr1, struct sockaddr *addr2) 456 { 457 struct sockaddr_in *sina, *sinb; 458 struct sockaddr_in6 *sin6a, *sin6b; 459 460 if (addr1->sa_family != addr2->sa_family) 461 return (B_FALSE); 462 463 switch (addr1->sa_family) { 464 case AF_INET: 465 /* LINTED E_BAD_PTR_CAST_ALIGN */ 466 sina = (struct sockaddr_in *)addr1; 467 /* LINTED E_BAD_PTR_CAST_ALIGN */ 468 sinb = (struct sockaddr_in *)addr2; 469 return (sina->sin_addr.s_addr == sinb->sin_addr.s_addr); 470 case AF_INET6: 471 /* LINTED E_BAD_PTR_CAST_ALIGN */ 472 sin6a = (struct sockaddr_in6 *)addr1; 473 /* LINTED E_BAD_PTR_CAST_ALIGN */ 474 sin6b = (struct sockaddr_in6 *)addr2; 475 return 476 (IN6_ARE_ADDR_EQUAL(&sin6a->sin6_addr, &sin6b->sin6_addr)); 477 default: 478 dprintf("cmpsockaddr: unsupported af (%d)", addr1->sa_family); 479 return (B_FALSE); 480 } 481 } 482 483 /* 484 * Duplicate a sockaddr. Caller will be responsible for freeing memory when it 485 * is no longer needed. Currently only supports AF_INET and AF_INET6 486 * (returns NULL otherwise). 487 */ 488 static struct sockaddr * 489 dupsockaddr(struct sockaddr *addr) 490 { 491 struct sockaddr_in *t1, *ret1; 492 struct sockaddr_in6 *t2, *ret2; 493 494 switch (addr->sa_family) { 495 case AF_INET: 496 if ((ret1 = calloc(1, sizeof (struct sockaddr_in))) == NULL) { 497 syslog(LOG_ERR, "dupsockaddr: calloc failed"); 498 return (NULL); 499 } 500 /* LINTED E_BAD_PTR_CAST_ALIGN */ 501 t1 = (struct sockaddr_in *)addr; 502 ret1->sin_family = t1->sin_family; 503 ret1->sin_addr.s_addr = t1->sin_addr.s_addr; 504 return ((struct sockaddr *)ret1); 505 case AF_INET6: 506 if ((ret2 = calloc(1, sizeof (struct sockaddr_in6))) == NULL) { 507 syslog(LOG_ERR, "dupsockaddr: calloc failed"); 508 return (NULL); 509 } 510 /* LINTED E_BAD_PTR_CAST_ALIGN */ 511 t2 = (struct sockaddr_in6 *)addr; 512 ret2->sin6_family = t2->sin6_family; 513 (void) memcpy((void *)&ret2->sin6_addr, 514 (const void *)&t2->sin6_addr, sizeof (struct in6_addr)); 515 return ((struct sockaddr *)ret2); 516 default: 517 dprintf("dupsockaddr: unsupported af (%d)", addr->sa_family); 518 return (NULL); 519 } 520 } 521 522 static char * 523 printaddr(void **address) 524 { 525 static char buffer[80]; 526 sa_family_t family = *(sa_family_t *)*address; 527 struct sockaddr_in *s4 = *address; 528 struct sockaddr_in6 *s6 = *address; 529 struct sockaddr_dl *dl = *address; 530 531 switch (family) { 532 case AF_UNSPEC: 533 (void) inet_ntop(AF_UNSPEC, &s4->sin_addr, buffer, 534 sizeof (buffer)); 535 *address = (char *)*address + sizeof (*s4); 536 break; 537 case AF_INET: 538 (void) inet_ntop(AF_INET, &s4->sin_addr, buffer, 539 sizeof (buffer)); 540 *address = (char *)*address + sizeof (*s4); 541 break; 542 case AF_INET6: 543 (void) inet_ntop(AF_INET6, &s6->sin6_addr, buffer, 544 sizeof (buffer)); 545 *address = (char *)*address + sizeof (*s6); 546 break; 547 case AF_LINK: 548 (void) snprintf(buffer, sizeof (buffer), "link %s", 549 dl->sdl_data); 550 *address = (char *)*address + sizeof (*dl); 551 break; 552 default: 553 /* 554 * We can't reliably update the size of this thing 555 * because we don't know what its type is. So bump 556 * it by a sockaddr_in and see what happens. The 557 * caller should really make sure this never happens. 558 */ 559 *address = (char *)*address + sizeof (*s4); 560 (void) snprintf(buffer, sizeof (buffer), 561 "unknown address family %d", family); 562 break; 563 } 564 return (buffer); 565 } 566 567 static void 568 printaddrs(int mask, void *address) 569 { 570 if (mask == 0) 571 return; 572 if (mask & RTA_DST) 573 dprintf("destination address: %s", printaddr(&address)); 574 if (mask & RTA_GATEWAY) 575 dprintf("gateway address: %s", printaddr(&address)); 576 if (mask & RTA_NETMASK) 577 dprintf("netmask: %s", printaddr(&address)); 578 if (mask & RTA_GENMASK) 579 dprintf("cloning mask: %s", printaddr(&address)); 580 if (mask & RTA_IFP) 581 dprintf("interface name: %s", printaddr(&address)); 582 if (mask & RTA_IFA) 583 dprintf("interface address: %s", printaddr(&address)); 584 if (mask & RTA_AUTHOR) 585 dprintf("author: %s", printaddr(&address)); 586 if (mask & RTA_BRD) 587 dprintf("broadcast address: %s", printaddr(&address)); 588 } 589 590 static void 591 nextaddr(void **address) 592 { 593 sa_family_t family = *(sa_family_t *)*address; 594 595 switch (family) { 596 case AF_UNSPEC: 597 case AF_INET: 598 *address = (char *)*address + sizeof (struct sockaddr_in); 599 break; 600 case AF_INET6: 601 *address = (char *)*address + sizeof (struct sockaddr_in6); 602 break; 603 case AF_LINK: 604 *address = (char *)*address + sizeof (struct sockaddr_dl); 605 break; 606 default: 607 syslog(LOG_ERR, "unknown af (%d) while parsing rtm", family); 608 break; 609 } 610 } 611 612 static void * 613 getaddr(int addrid, int mask, void *address) 614 { 615 int i; 616 void *p = address; 617 618 if ((mask & addrid) == 0) 619 return (NULL); 620 621 for (i = 1; i < addrid; i <<= 1) { 622 if (i & mask) 623 nextaddr(&p); 624 } 625 return (p); 626 } 627 628 boolean_t 629 start_event_collection(void) 630 { 631 int err; 632 633 /* 634 * if these are ever created/destroyed repetitively then we will 635 * have to change this. 636 */ 637 638 if (err = pthread_create(&routing, NULL, routing_events, NULL)) { 639 syslog(LOG_ERR, "pthread_create routing: %s", strerror(err)); 640 exit(EXIT_FAILURE); 641 } else { 642 dprintf("routing thread: %d", routing); 643 } 644 645 if (err = pthread_create(&scan, NULL, periodic_wireless_scan, NULL)) { 646 syslog(LOG_ERR, "pthread_create wireless scan: %s", 647 strerror(err)); 648 exit(EXIT_FAILURE); 649 } else { 650 dprintf("scan thread: %d", scan); 651 } 652 653 walk_interface(start_if_info_collect, NULL); 654 655 return (B_TRUE); 656 } 657