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 void *getaddr(int addrid, int mask, void *address); 81 82 union rtm_buf 83 { 84 /* Routing information. */ 85 struct 86 { 87 struct rt_msghdr rtm; 88 struct sockaddr_storage addr[RTAX_MAX]; 89 } r; 90 91 /* Interface information. */ 92 struct 93 { 94 struct if_msghdr ifm; 95 struct sockaddr_storage addr[RTAX_MAX]; 96 } im; 97 98 /* Interface address information. */ 99 struct 100 { 101 struct ifa_msghdr ifa; 102 struct sockaddr_storage addr[RTAX_MAX]; 103 } ia; 104 }; 105 106 void 107 free_event(struct np_event *e) 108 { 109 free(e->npe_name); 110 free(e); 111 } 112 113 void 114 np_queue_add_event(struct np_event *e) 115 { 116 (void) pthread_mutex_lock(&queue_mutex); 117 if (equeue_end != NULL) { 118 equeue_end->npe_next = e; 119 equeue_end = e; 120 } else { 121 equeue = equeue_end = e; 122 } 123 equeue_end->npe_next = NULL; 124 (void) pthread_cond_signal(&queue_cond); 125 (void) pthread_mutex_unlock(&queue_mutex); 126 } 127 128 /* 129 * Blocking getevent. This routine will block until there is an event for 130 * it to return. 131 */ 132 struct np_event * 133 np_queue_get_event(void) 134 { 135 struct np_event *rv = NULL; 136 137 (void) pthread_mutex_lock(&queue_mutex); 138 139 while (equeue == NULL) 140 (void) pthread_cond_wait(&queue_cond, &queue_mutex); 141 142 rv = equeue; 143 equeue = equeue->npe_next; 144 if (equeue == NULL) 145 equeue_end = NULL; 146 147 (void) pthread_mutex_unlock(&queue_mutex); 148 149 rv->npe_next = NULL; 150 return (rv); 151 } 152 153 const char * 154 npe_type_str(enum np_event_type type) 155 { 156 switch (type) { 157 case EV_ROUTING: 158 return ("ROUTING"); 159 case EV_SYS: 160 return ("SYS"); 161 case EV_TIMER: 162 return ("TIMER"); 163 case EV_SHUTDOWN: 164 return ("SHUTDOWN"); 165 case EV_NEWADDR: 166 return ("NEWADDR"); 167 default: 168 return ("unknown"); 169 } 170 } 171 172 static void 173 addevent_routing_ifa(struct ifa_msghdr *ifa, const char *name) 174 { 175 struct np_event *e; 176 177 dprintf("addevent_routing_ifa"); 178 if (ifa->ifam_index == 0) { 179 /* what is this? */ 180 dprintf("tossing index 0 routing event"); 181 return; 182 } 183 184 e = calloc(1, sizeof (*e)); 185 if (e == NULL) { 186 syslog(LOG_ERR, "calloc failed"); 187 return; 188 } 189 190 switch (ifa->ifam_type) { 191 case RTM_NEWADDR: 192 assert(name != NULL); 193 e->npe_type = EV_NEWADDR; 194 if ((e->npe_name = strdup(name)) == NULL) { 195 syslog(LOG_ERR, "strdup failed"); 196 free(e); 197 return; 198 } 199 dprintf("adding event type %s name %s to queue", 200 npe_type_str(e->npe_type), STRING(e->npe_name)); 201 np_queue_add_event(e); 202 break; 203 204 default: 205 free(e); 206 dprintf("unhandled type in addevent_routing_ifa %d", 207 ifa->ifam_type); 208 break; 209 } 210 } 211 212 static void 213 addevent_routing_msghdr(struct if_msghdr *ifm, const char *name) 214 { 215 struct np_event *e; 216 217 dprintf("addevent_routing_msghdr"); 218 if (ifm->ifm_index == 0) { 219 /* what is this? */ 220 dprintf("tossing index 0 routing event"); 221 return; 222 } 223 224 switch (ifm->ifm_type) { 225 case RTM_IFINFO: 226 assert(name != NULL); 227 e = calloc(1, sizeof (*e)); 228 if (e == NULL) { 229 syslog(LOG_ERR, "calloc failed"); 230 return; 231 } 232 233 e->npe_type = EV_ROUTING; 234 if ((e->npe_name = strdup(name)) == NULL) { 235 syslog(LOG_ERR, "strdup failed"); 236 free(e); 237 return; 238 } 239 dprintf("flags = %x, IFF_RUNNING = %x", ifm->ifm_flags, 240 IFF_RUNNING); 241 dprintf("adding event type %s name %s to queue", 242 npe_type_str(e->npe_type), STRING(e->npe_name)); 243 np_queue_add_event(e); 244 break; 245 246 default: 247 dprintf("unhandled type in addevent_routing_msghdr %d", 248 ifm->ifm_type); 249 break; 250 } 251 } 252 253 static const char * 254 rtmtype_str(int type) 255 { 256 static char typestr[12]; /* strlen("type ") + enough for an int */ 257 258 switch (type) { 259 case RTM_ADD: 260 return ("ADD"); 261 case RTM_DELETE: 262 return ("DELETE"); 263 case RTM_NEWADDR: 264 return ("NEWADDR"); 265 case RTM_DELADDR: 266 return ("DELADDR"); 267 case RTM_IFINFO: 268 return ("IFINFO"); 269 default: 270 (void) snprintf(typestr, sizeof (typestr), "type %d", 271 type); 272 return (typestr); 273 } 274 } 275 276 /* ARGSUSED */ 277 static void * 278 routing_events(void *arg) 279 { 280 int rtsock; 281 int n; 282 union rtm_buf buffer; 283 struct rt_msghdr *rtm; 284 struct ifa_msghdr *ifa; 285 struct if_msghdr *ifm; 286 287 /* 288 * We use v4 interfaces as proxies for links so those are the only 289 * routing messages we need to listen to. Look at the comments in 290 * structures.h for more information about the split between the 291 * llp and interfaces. 292 */ 293 rtsock = socket(AF_ROUTE, SOCK_RAW, AF_INET); 294 if (rtsock == -1) { 295 syslog(LOG_ERR, "failed to open routing socket: %m"); 296 exit(EXIT_FAILURE); 297 } 298 299 dprintf("routing socket %d", rtsock); 300 301 for (;;) { 302 struct interface *ifp; 303 char *addrs, *if_name; 304 struct sockaddr_dl *addr_dl; 305 struct sockaddr *addr; 306 307 rtm = &buffer.r.rtm; 308 n = read(rtsock, &buffer, sizeof (buffer)); 309 if (n == -1 && errno == EAGAIN) { 310 continue; 311 } else if (n == -1) { 312 syslog(LOG_ERR, "error reading routing socket " 313 "%d: %m", rtsock); 314 /* Low likelihood. What's recovery path? */ 315 continue; 316 } 317 318 if (rtm->rtm_msglen < n) { 319 syslog(LOG_ERR, "only read %d bytes from " 320 "routing socket but message claims to be " 321 "of length %d", rtm->rtm_msglen); 322 continue; 323 } 324 325 if (rtm->rtm_version != RTM_VERSION) { 326 syslog(LOG_ERR, "tossing routing message of " 327 "version %d type %d", rtm->rtm_version, 328 rtm->rtm_type); 329 continue; 330 } 331 332 if (rtm->rtm_msglen != n) { 333 dprintf("routing message of %d size came from " 334 "read of %d on socket %d", rtm->rtm_msglen, 335 n, rtsock); 336 } 337 338 switch (rtm->rtm_type) { 339 case RTM_NEWADDR: 340 ifa = (void *)rtm; 341 addrs = (char *)ifa + sizeof (*ifa); 342 343 dprintf("routing message NEWADDR: index %d flags %x", 344 ifa->ifam_index, ifa->ifam_flags); 345 printaddrs(ifa->ifam_addrs, addrs); 346 347 if ((addr = (struct sockaddr *)getaddr(RTA_IFA, 348 ifa->ifam_addrs, addrs)) == NULL) 349 break; 350 351 if ((addr_dl = (struct sockaddr_dl *)getaddr 352 (RTA_IFP, ifa->ifam_addrs, addrs)) == NULL) 353 break; 354 /* 355 * We don't use the lladdr in this structure so we can 356 * run over it. 357 */ 358 addr_dl->sdl_data[addr_dl->sdl_nlen] = 0; 359 if_name = addr_dl->sdl_data; 360 ifp = get_interface(if_name); 361 if (ifp == NULL) { 362 dprintf("no interface struct for %s; ignoring " 363 "message", STRING(if_name)); 364 break; 365 } 366 367 /* if no cached address, cache it */ 368 if (ifp->if_ipaddr == NULL) { 369 ifp->if_ipaddr = dupsockaddr(addr); 370 dprintf("cached address %s for link %s", 371 printaddr((void **)&addr), if_name); 372 addevent_routing_ifa(ifa, if_name); 373 } else if (!cmpsockaddr(addr, ifp->if_ipaddr)) { 374 free(ifp->if_ipaddr); 375 ifp->if_ipaddr = dupsockaddr(addr); 376 addevent_routing_ifa(ifa, if_name); 377 } 378 break; 379 case RTM_IFINFO: 380 { 381 boolean_t plugged_in; 382 383 ifm = (void *)rtm; 384 addrs = (char *)ifm + sizeof (*ifm); 385 dprintf("routing message IFINFO: index %d flags %x", 386 ifm->ifm_index, ifm->ifm_flags); 387 printaddrs(ifm->ifm_addrs, addrs); 388 389 if ((addr_dl = (struct sockaddr_dl *)getaddr(RTA_IFP, 390 ifm->ifm_addrs, addrs)) == NULL) 391 break; 392 /* 393 * We don't use the lladdr in this structure so we can 394 * run over it. 395 */ 396 addr_dl->sdl_data[addr_dl->sdl_nlen] = 0; 397 if_name = addr_dl->sdl_data; 398 ifp = get_interface(if_name); 399 if (ifp == NULL) { 400 dprintf("no interface struct for %s; ignoring " 401 "message", STRING(if_name)); 402 break; 403 } 404 405 /* 406 * Check for toggling of the IFF_RUNNING flag. 407 * 408 * On any change in the flag value, we turn off the 409 * DHCP flags; the change in the RUNNING state 410 * indicates a "fresh start" for the interface, so we 411 * should try dhcp again. 412 * 413 * Ignore specific IFF_RUNNING changes for 414 * wireless interfaces; their semantics are 415 * a bit different (either the flag is always 416 * on, or, with newer drivers, it indicates 417 * whether or not they are connected to an AP). 418 * 419 * For wired interfaces, if the interface was 420 * not plugged in and now it is, start info 421 * collection. 422 * 423 * If it was plugged in and now it is 424 * unplugged, generate an event. 425 * 426 * XXX We probably need a lock to protect 427 * if_flags setting and getting. 428 */ 429 if ((ifp->if_flags & IFF_RUNNING) != 430 (ifm->ifm_flags & IFF_RUNNING)) { 431 ifp->if_lflags &= ~IF_DHCPFLAGS; 432 } 433 if (ifp->if_type == IF_WIRELESS) 434 break; 435 plugged_in = ((ifp->if_flags & IFF_RUNNING) != 0); 436 ifp->if_flags = ifm->ifm_flags; 437 if (!plugged_in && 438 (ifm->ifm_flags & IFF_RUNNING)) { 439 start_if_info_collect(ifp, NULL); 440 } else if (plugged_in && 441 !(ifm->ifm_flags & IFF_RUNNING)) { 442 check_drop_dhcp(ifp); 443 addevent_routing_msghdr(ifm, if_name); 444 } 445 break; 446 } 447 default: 448 dprintf("routing message %s socket %d discarded", 449 rtmtype_str(rtm->rtm_type), rtsock); 450 break; 451 } 452 } 453 /* NOTREACHED */ 454 return (NULL); 455 } 456 457 static char * 458 printaddr(void **address) 459 { 460 static char buffer[80]; 461 sa_family_t family = *(sa_family_t *)*address; 462 struct sockaddr_in *s4 = *address; 463 struct sockaddr_in6 *s6 = *address; 464 struct sockaddr_dl *dl = *address; 465 466 switch (family) { 467 case AF_UNSPEC: 468 (void) inet_ntop(AF_UNSPEC, &s4->sin_addr, buffer, 469 sizeof (buffer)); 470 *address = (char *)*address + sizeof (*s4); 471 break; 472 case AF_INET: 473 (void) inet_ntop(AF_INET, &s4->sin_addr, buffer, 474 sizeof (buffer)); 475 *address = (char *)*address + sizeof (*s4); 476 break; 477 case AF_INET6: 478 (void) inet_ntop(AF_INET6, &s6->sin6_addr, buffer, 479 sizeof (buffer)); 480 *address = (char *)*address + sizeof (*s6); 481 break; 482 case AF_LINK: 483 (void) snprintf(buffer, sizeof (buffer), "link %.*s", 484 dl->sdl_nlen, dl->sdl_data); 485 *address = (char *)*address + sizeof (*dl); 486 break; 487 default: 488 /* 489 * We can't reliably update the size of this thing 490 * because we don't know what its type is. So bump 491 * it by a sockaddr_in and see what happens. The 492 * caller should really make sure this never happens. 493 */ 494 *address = (char *)*address + sizeof (*s4); 495 (void) snprintf(buffer, sizeof (buffer), 496 "unknown address family %d", family); 497 break; 498 } 499 return (buffer); 500 } 501 502 static void 503 printaddrs(int mask, void *address) 504 { 505 if (mask == 0) 506 return; 507 if (mask & RTA_DST) 508 dprintf("destination address: %s", printaddr(&address)); 509 if (mask & RTA_GATEWAY) 510 dprintf("gateway address: %s", printaddr(&address)); 511 if (mask & RTA_NETMASK) 512 dprintf("netmask: %s", printaddr(&address)); 513 if (mask & RTA_GENMASK) 514 dprintf("cloning mask: %s", printaddr(&address)); 515 if (mask & RTA_IFP) 516 dprintf("interface name: %s", printaddr(&address)); 517 if (mask & RTA_IFA) 518 dprintf("interface address: %s", printaddr(&address)); 519 if (mask & RTA_AUTHOR) 520 dprintf("author: %s", printaddr(&address)); 521 if (mask & RTA_BRD) 522 dprintf("broadcast address: %s", printaddr(&address)); 523 } 524 525 static void 526 nextaddr(void **address) 527 { 528 sa_family_t family = *(sa_family_t *)*address; 529 530 switch (family) { 531 case AF_UNSPEC: 532 case AF_INET: 533 *address = (char *)*address + sizeof (struct sockaddr_in); 534 break; 535 case AF_INET6: 536 *address = (char *)*address + sizeof (struct sockaddr_in6); 537 break; 538 case AF_LINK: 539 *address = (char *)*address + sizeof (struct sockaddr_dl); 540 break; 541 default: 542 syslog(LOG_ERR, "unknown af (%d) while parsing rtm", family); 543 break; 544 } 545 } 546 547 static void * 548 getaddr(int addrid, int mask, void *address) 549 { 550 int i; 551 void *p = address; 552 553 if ((mask & addrid) == 0) 554 return (NULL); 555 556 for (i = 1; i < addrid; i <<= 1) { 557 if (i & mask) 558 nextaddr(&p); 559 } 560 return (p); 561 } 562 563 boolean_t 564 start_event_collection(void) 565 { 566 int err; 567 boolean_t check_cache = B_TRUE; 568 569 /* 570 * if these are ever created/destroyed repetitively then we will 571 * have to change this. 572 */ 573 574 if (err = pthread_create(&routing, NULL, routing_events, NULL)) { 575 syslog(LOG_ERR, "pthread_create routing: %s", strerror(err)); 576 exit(EXIT_FAILURE); 577 } else { 578 dprintf("routing thread: %d", routing); 579 } 580 581 if (err = pthread_create(&scan, NULL, periodic_wireless_scan, NULL)) { 582 syslog(LOG_ERR, "pthread_create wireless scan: %s", 583 strerror(err)); 584 exit(EXIT_FAILURE); 585 } else { 586 dprintf("scan thread: %d", scan); 587 } 588 589 walk_interface(start_if_info_collect, &check_cache); 590 591 return (B_TRUE); 592 } 593