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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include <atomic.h> 27 #include <errno.h> 28 #include <execinfo.h> 29 #include <libuutil.h> 30 #include <pthread.h> 31 #include <signal.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <strings.h> 35 #include <syslog.h> 36 #include <sys/time.h> 37 #include <unistd.h> 38 39 #include "conditions.h" 40 #include "events.h" 41 #include "objects.h" 42 #include "util.h" 43 44 /* 45 * events.c - contains routines which create/destroy event sources, 46 * handle the event queue and process events from that queue. 47 */ 48 49 /* Add new event sources here. */ 50 struct nwamd_event_source { 51 char *name; 52 void (*events_init)(void); 53 void (*events_fini)(void); 54 } event_sources[] = { 55 { "routing_events", 56 nwamd_routing_events_init, nwamd_routing_events_fini }, 57 { "sysevent_events", 58 nwamd_sysevent_events_init, nwamd_sysevent_events_fini }, 59 }; 60 61 /* Counter for event ids */ 62 static uint64_t event_id_counter = 0; 63 64 static uu_list_pool_t *event_pool = NULL; 65 static uu_list_t *event_queue = NULL; 66 static pthread_mutex_t event_queue_mutex = PTHREAD_MUTEX_INITIALIZER; 67 static pthread_cond_t event_queue_cond = PTHREAD_COND_INITIALIZER; 68 69 static int nwamd_event_compare(const void *, const void *, void *); 70 71 static const char * 72 nwamd_event_name(int event_type) 73 { 74 if (event_type <= NWAM_EVENT_MAX) 75 return (nwam_event_type_to_string(event_type)); 76 77 switch (event_type) { 78 case NWAM_EVENT_TYPE_OBJECT_INIT: 79 return ("OBJECT_INIT"); 80 case NWAM_EVENT_TYPE_OBJECT_FINI: 81 return ("OBJECT_FINI"); 82 case NWAM_EVENT_TYPE_TIMED_CHECK_CONDITIONS: 83 return ("TIMED_CHECK_CONDITIONS"); 84 case NWAM_EVENT_TYPE_TRIGGERED_CHECK_CONDITIONS: 85 return ("TRIGGERED_CHECK_CONDITIONS"); 86 case NWAM_EVENT_TYPE_NCU_CHECK: 87 return ("NCU_CHECK"); 88 case NWAM_EVENT_TYPE_TIMER: 89 return ("TIMER"); 90 case NWAM_EVENT_TYPE_UPGRADE: 91 return ("UPGRADE"); 92 case NWAM_EVENT_TYPE_PERIODIC_SCAN: 93 return ("PERIODIC_SCAN"); 94 case NWAM_EVENT_TYPE_QUEUE_QUIET: 95 return ("QUEUE_QUIET"); 96 default: 97 return ("N/A"); 98 } 99 } 100 101 void 102 nwamd_event_sources_init(void) 103 { 104 int i; 105 106 /* 107 * Now we can safely initialize event sources. 108 */ 109 for (i = 0; 110 i < sizeof (event_sources) / sizeof (struct nwamd_event_source); 111 i++) { 112 if (event_sources[i].events_init != NULL) 113 event_sources[i].events_init(); 114 } 115 } 116 117 void 118 nwamd_event_sources_fini(void) 119 { 120 int i; 121 122 for (i = 0; 123 i < sizeof (event_sources) / sizeof (struct nwamd_event_source); 124 i++) { 125 if (event_sources[i].events_init != NULL) 126 event_sources[i].events_fini(); 127 } 128 } 129 130 /* 131 * Comparison function for events, passed in as callback to 132 * uu_list_pool_create(). Compare by time, so that timer 133 * event queue can be sorted by nearest time to present. 134 */ 135 /* ARGSUSED */ 136 static int 137 nwamd_event_compare(const void *l_arg, const void *r_arg, void *private) 138 { 139 nwamd_event_t l = (nwamd_event_t)l_arg; 140 nwamd_event_t r = (nwamd_event_t)r_arg; 141 int rv; 142 143 rv = l->event_time.tv_sec - r->event_time.tv_sec; 144 if (rv == 0) 145 rv = l->event_time.tv_nsec - r->event_time.tv_nsec; 146 147 return (rv); 148 } 149 150 void 151 nwamd_event_queue_init(void) 152 { 153 event_pool = uu_list_pool_create("event_queue_pool", 154 sizeof (struct nwamd_event), 155 offsetof(struct nwamd_event, event_node), 156 nwamd_event_compare, UU_LIST_POOL_DEBUG); 157 if (event_pool == NULL) 158 pfail("uu_list_pool_create failed with error %d", uu_error()); 159 event_queue = uu_list_create(event_pool, NULL, UU_LIST_SORTED); 160 if (event_queue == NULL) 161 pfail("uu_list_create failed with error %d", uu_error()); 162 } 163 164 void 165 nwamd_event_queue_fini(void) 166 { 167 void *cookie = NULL; 168 nwamd_event_t event; 169 170 while ((event = uu_list_teardown(event_queue, &cookie)) != NULL) 171 nwamd_event_fini(event); 172 uu_list_destroy(event_queue); 173 if (event_pool != NULL) 174 uu_list_pool_destroy(event_pool); 175 } 176 177 nwamd_event_t 178 nwamd_event_init(int32_t type, nwam_object_type_t object_type, 179 size_t size, const char *object_name) 180 { 181 nwamd_event_t event; 182 183 event = calloc(1, sizeof (struct nwamd_event)); 184 if (event == NULL) { 185 nlog(LOG_ERR, "nwamd_event_init: could not create %s event for " 186 "object %s", nwamd_event_name(type), 187 object_name != NULL ? object_name : "<no object>"); 188 return (NULL); 189 } 190 191 /* Is this an externally-visible event? */ 192 if (type <= NWAM_EVENT_MAX) { 193 event->event_send = B_TRUE; 194 event->event_msg = calloc(1, sizeof (struct nwam_event) + size); 195 if (event->event_msg == NULL) { 196 nlog(LOG_ERR, 197 "nwamd_event_init: could not create %s event", 198 nwamd_event_name(type)); 199 free(event); 200 return (NULL); 201 } 202 event->event_msg->nwe_type = type; 203 event->event_msg->nwe_size = sizeof (struct nwam_event) + size; 204 } else { 205 event->event_send = B_FALSE; 206 event->event_msg = NULL; 207 } 208 209 event->event_type = type; 210 211 if (object_name != NULL) { 212 (void) strlcpy(event->event_object, object_name, 213 NWAM_MAX_NAME_LEN); 214 event->event_object_type = object_type; 215 } else { 216 event->event_object[0] = '\0'; 217 } 218 219 /* Set event id */ 220 event->event_id = atomic_add_64_nv(&event_id_counter, 1); 221 (void) clock_gettime(CLOCK_REALTIME, &event->event_time); 222 223 return (event); 224 } 225 226 void 227 nwamd_event_do_not_send(nwamd_event_t event) 228 { 229 nlog(LOG_DEBUG, "nwamd_event_do_not_send: cancelling delivery of " 230 "event %s for object %s", nwamd_event_name(event->event_type), 231 event->event_object[0] != '\0' ? 232 event->event_object : "<no object>"); 233 event->event_send = B_FALSE; 234 } 235 236 void 237 nwamd_event_fini(nwamd_event_t event) 238 { 239 if (event != NULL) { 240 free(event->event_msg); 241 free(event); 242 } 243 } 244 245 nwamd_event_t 246 nwamd_event_init_object_action(nwam_object_type_t object_type, 247 const char *object_name, const char *parent_name, 248 nwam_action_t object_action) 249 { 250 nwamd_event_t event; 251 252 event = nwamd_event_init(NWAM_EVENT_TYPE_OBJECT_ACTION, 253 object_type, 0, object_name); 254 if (event == NULL) 255 return (NULL); 256 257 event->event_msg->nwe_data.nwe_object_action.nwe_action = object_action; 258 event->event_msg->nwe_data.nwe_object_action.nwe_object_type = 259 object_type; 260 (void) strlcpy(event->event_msg->nwe_data.nwe_object_action.nwe_name, 261 object_name, 262 sizeof (event->event_msg->nwe_data.nwe_object_action.nwe_name)); 263 if (parent_name == NULL) { 264 event->event_msg->nwe_data.nwe_object_action.nwe_parent[0] = 265 '\0'; 266 return (event); 267 } 268 (void) strlcpy 269 (event->event_msg->nwe_data.nwe_object_action.nwe_parent, 270 parent_name, 271 sizeof (event->event_msg->nwe_data.nwe_object_action.nwe_parent)); 272 return (event); 273 } 274 275 nwamd_event_t 276 nwamd_event_init_object_state(nwam_object_type_t object_type, 277 const char *object_name, nwam_state_t state, nwam_aux_state_t aux_state) 278 { 279 nwamd_event_t event; 280 281 event = nwamd_event_init(NWAM_EVENT_TYPE_OBJECT_STATE, 282 object_type, 0, object_name); 283 if (event == NULL) 284 return (NULL); 285 286 event->event_msg->nwe_data.nwe_object_state.nwe_state = state; 287 event->event_msg->nwe_data.nwe_object_state.nwe_aux_state = aux_state; 288 event->event_msg->nwe_data.nwe_object_state.nwe_object_type = 289 object_type; 290 (void) strlcpy(event->event_msg->nwe_data.nwe_object_state.nwe_name, 291 object_name, 292 sizeof (event->event_msg->nwe_data.nwe_object_state.nwe_name)); 293 294 return (event); 295 } 296 297 nwamd_event_t 298 nwamd_event_init_priority_group_change(int64_t priority) 299 { 300 nwamd_event_t event; 301 302 event = nwamd_event_init(NWAM_EVENT_TYPE_PRIORITY_GROUP, 303 NWAM_OBJECT_TYPE_UNKNOWN, 0, NULL); 304 if (event == NULL) 305 return (NULL); 306 307 event->event_msg->nwe_data.nwe_priority_group_info.nwe_priority = 308 priority; 309 310 return (event); 311 } 312 313 nwamd_event_t 314 nwamd_event_init_link_action(const char *name, nwam_action_t link_action) 315 { 316 nwamd_event_t event; 317 nwam_error_t err; 318 char *object_name; 319 320 if ((err = nwam_ncu_name_to_typed_name(name, NWAM_NCU_TYPE_LINK, 321 &object_name)) != NWAM_SUCCESS) { 322 nlog(LOG_ERR, "nwamd_event_init_link_action: " 323 "nwam_ncu_name_to_typed_name: %s", 324 nwam_strerror(err)); 325 return (NULL); 326 } 327 event = nwamd_event_init(NWAM_EVENT_TYPE_LINK_ACTION, 328 NWAM_OBJECT_TYPE_NCU, 0, object_name); 329 free(object_name); 330 if (event == NULL) 331 return (NULL); 332 333 (void) strlcpy(event->event_msg->nwe_data.nwe_link_action.nwe_name, 334 name, 335 sizeof (event->event_msg->nwe_data.nwe_link_action.nwe_name)); 336 event->event_msg->nwe_data.nwe_link_action.nwe_action = link_action; 337 338 return (event); 339 } 340 341 nwamd_event_t 342 nwamd_event_init_link_state(const char *name, boolean_t up) 343 { 344 nwamd_event_t event; 345 nwam_error_t err; 346 char *object_name; 347 348 if ((err = nwam_ncu_name_to_typed_name(name, NWAM_NCU_TYPE_LINK, 349 &object_name)) != NWAM_SUCCESS) { 350 nlog(LOG_ERR, "nwamd_event_init_link_state: " 351 "nwam_ncu_name_to_typed_name: %s", 352 nwam_strerror(err)); 353 return (NULL); 354 } 355 356 event = nwamd_event_init(NWAM_EVENT_TYPE_LINK_STATE, 357 NWAM_OBJECT_TYPE_NCU, 0, object_name); 358 free(object_name); 359 if (event == NULL) 360 return (NULL); 361 362 (void) strlcpy(event->event_msg->nwe_data.nwe_link_state.nwe_name, name, 363 sizeof (event->event_msg->nwe_data.nwe_link_state.nwe_name)); 364 event->event_msg->nwe_data.nwe_link_state.nwe_link_up = up; 365 366 return (event); 367 } 368 369 nwamd_event_t 370 nwamd_event_init_if_state(const char *linkname, uint32_t flags, 371 uint32_t addr_added, struct sockaddr *addr, struct sockaddr *netmask) 372 { 373 nwamd_event_t event; 374 nwam_error_t err; 375 char *object_name; 376 377 /* linkname does not contain the lifnum */ 378 if ((err = nwam_ncu_name_to_typed_name(linkname, 379 NWAM_NCU_TYPE_INTERFACE, &object_name)) != NWAM_SUCCESS) { 380 nlog(LOG_ERR, "nwamd_event_init_if_state: " 381 "nwam_ncu_name_to_typed_name: %s", 382 nwam_strerror(err)); 383 return (NULL); 384 } 385 386 event = nwamd_event_init(NWAM_EVENT_TYPE_IF_STATE, 387 NWAM_OBJECT_TYPE_NCU, 0, object_name); 388 free(object_name); 389 if (event == NULL) 390 return (NULL); 391 392 (void) strlcpy(event->event_msg->nwe_data.nwe_if_state.nwe_name, 393 linkname, 394 sizeof (event->event_msg->nwe_data.nwe_if_state.nwe_name)); 395 event->event_msg->nwe_data.nwe_if_state.nwe_flags = flags; 396 event->event_msg->nwe_data.nwe_if_state.nwe_addr_added = addr_added; 397 event->event_msg->nwe_data.nwe_if_state.nwe_addr_valid = (addr != NULL); 398 399 if (addr != NULL) { 400 bcopy(addr, &(event->event_msg->nwe_data.nwe_if_state.nwe_addr), 401 addr->sa_family == AF_INET ? sizeof (struct sockaddr_in) : 402 sizeof (struct sockaddr_in6)); 403 } 404 if (netmask != NULL) { 405 bcopy(netmask, 406 &(event->event_msg->nwe_data.nwe_if_state.nwe_netmask), 407 netmask->sa_family == AF_INET ? 408 sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6)); 409 } 410 411 return (event); 412 } 413 414 nwamd_event_t 415 nwamd_event_init_wlan(const char *name, int32_t type, boolean_t connected, 416 nwam_wlan_t *wlans, uint_t num_wlans) 417 { 418 size_t size = 0; 419 char *object_name; 420 nwamd_event_t event; 421 nwam_error_t err; 422 423 switch (type) { 424 case NWAM_EVENT_TYPE_WLAN_SCAN_REPORT: 425 case NWAM_EVENT_TYPE_WLAN_NEED_CHOICE: 426 size = sizeof (nwam_wlan_t) * (num_wlans - 1); 427 break; 428 case NWAM_EVENT_TYPE_WLAN_NEED_KEY: 429 case NWAM_EVENT_TYPE_WLAN_CONNECTION_REPORT: 430 break; 431 default: 432 nlog(LOG_ERR, "nwamd_event_init_wlan: unexpected " 433 "event type %s (%d)", nwamd_event_name(type), type); 434 return (NULL); 435 } 436 if ((err = nwam_ncu_name_to_typed_name(name, NWAM_NCU_TYPE_LINK, 437 &object_name)) != NWAM_SUCCESS) { 438 nlog(LOG_ERR, "nwamd_event_init_wlan: " 439 "nwam_ncu_name_to_typed_name: %s", 440 nwam_strerror(err)); 441 return (NULL); 442 } 443 444 event = nwamd_event_init(type, NWAM_OBJECT_TYPE_NCU, size, object_name); 445 free(object_name); 446 if (event == NULL) 447 return (NULL); 448 449 (void) strlcpy(event->event_msg->nwe_data.nwe_wlan_info.nwe_name, name, 450 sizeof (event->event_msg->nwe_data.nwe_wlan_info.nwe_name)); 451 event->event_msg->nwe_data.nwe_wlan_info.nwe_connected = connected; 452 event->event_msg->nwe_data.nwe_wlan_info.nwe_num_wlans = num_wlans; 453 454 /* copy the wlans */ 455 (void) memcpy(event->event_msg->nwe_data.nwe_wlan_info.nwe_wlans, wlans, 456 num_wlans * sizeof (nwam_wlan_t)); 457 458 return (event); 459 } 460 461 nwamd_event_t 462 nwamd_event_init_ncu_check(void) 463 { 464 return (nwamd_event_init(NWAM_EVENT_TYPE_NCU_CHECK, 465 NWAM_OBJECT_TYPE_NCP, 0, NULL)); 466 } 467 468 nwamd_event_t 469 nwamd_event_init_init(void) 470 { 471 return (nwamd_event_init(NWAM_EVENT_TYPE_INIT, 472 NWAM_OBJECT_TYPE_UNKNOWN, 0, NULL)); 473 } 474 475 nwamd_event_t 476 nwamd_event_init_shutdown(void) 477 { 478 return (nwamd_event_init(NWAM_EVENT_TYPE_SHUTDOWN, 479 NWAM_OBJECT_TYPE_UNKNOWN, 0, NULL)); 480 } 481 482 /* 483 * Add event to the event list. 484 */ 485 void 486 nwamd_event_enqueue(nwamd_event_t event) 487 { 488 nwamd_event_enqueue_timed(event, 0); 489 } 490 491 /* 492 * Schedule an event to be added to the event list for future processing. 493 * The event will be scheduled in delta_seconds seconds mod schedule delay and 494 * time resolution. 495 */ 496 void 497 nwamd_event_enqueue_timed(nwamd_event_t event, int delta_seconds) 498 { 499 uu_list_index_t idx; 500 501 nlog(LOG_DEBUG, "enqueueing event %lld %d (%s) for object %s in %ds", 502 event->event_id, event->event_type, 503 nwamd_event_name(event->event_type), 504 event->event_object[0] != 0 ? event->event_object : "none", 505 delta_seconds); 506 507 (void) clock_gettime(CLOCK_REALTIME, &event->event_time); 508 event->event_time.tv_sec += delta_seconds; 509 510 uu_list_node_init(event, &event->event_node, event_pool); 511 512 (void) pthread_mutex_lock(&event_queue_mutex); 513 514 /* 515 * Find appropriate location to insert the event based on time. 516 */ 517 (void) uu_list_find(event_queue, event, NULL, &idx); 518 (void) uu_list_insert(event_queue, event, idx); 519 520 (void) pthread_cond_signal(&event_queue_cond); 521 (void) pthread_mutex_unlock(&event_queue_mutex); 522 } 523 524 /* 525 * Is the specified event enqueued on the event (or pending event queue) 526 * for execution in when seconds? An object may be specified also. 527 */ 528 boolean_t 529 nwamd_event_enqueued(int32_t event_type, nwam_object_type_t object_type, 530 const char *object) 531 { 532 nwamd_event_t event; 533 534 (void) pthread_mutex_lock(&event_queue_mutex); 535 for (event = uu_list_first(event_queue); 536 event != NULL; 537 event = uu_list_next(event_queue, event)) { 538 if (event->event_type != event_type) 539 continue; 540 if (object_type != NWAM_OBJECT_TYPE_UNKNOWN && 541 event->event_object_type != object_type) 542 continue; 543 if (object != NULL && strcmp(object, event->event_object) != 0) 544 continue; 545 (void) pthread_mutex_unlock(&event_queue_mutex); 546 return (B_TRUE); 547 } 548 (void) pthread_mutex_unlock(&event_queue_mutex); 549 550 return (B_FALSE); 551 } 552 553 /* 554 * Is the time in the past. 555 */ 556 static boolean_t 557 in_past(struct timespec t) 558 { 559 struct timespec now; 560 561 (void) clock_gettime(CLOCK_REALTIME, &now); 562 if (t.tv_sec < now.tv_sec) 563 return (B_TRUE); 564 if (t.tv_sec > now.tv_sec) 565 return (B_FALSE); 566 if (t.tv_nsec < now.tv_nsec) 567 return (B_TRUE); 568 return (B_FALSE); 569 } 570 571 /* 572 * Remove event at head of event list for processing. This takes a number of 573 * nanoseconds to wait. If the number is 0 then it blocks. If there is 574 * nothing on the queue then it returns an event which says that the queue 575 * is quiet. 576 */ 577 static nwamd_event_t 578 nwamd_event_dequeue(long nsec) 579 { 580 nwamd_event_t event; 581 582 (void) pthread_mutex_lock(&event_queue_mutex); 583 event = uu_list_first(event_queue); 584 if (event == NULL && nsec == 0) { 585 do { 586 (void) pthread_cond_wait(&event_queue_cond, 587 &event_queue_mutex); 588 } while ((event = uu_list_first(event_queue)) == NULL); 589 } else { 590 struct timespec waitcap; 591 592 if (nsec != 0) { 593 (void) clock_gettime(CLOCK_REALTIME, &waitcap); 594 waitcap.tv_nsec += nsec; 595 waitcap.tv_sec += NSEC_TO_SEC(waitcap.tv_nsec); 596 waitcap.tv_nsec = NSEC_TO_FRACNSEC(waitcap.tv_nsec); 597 } 598 599 /* 600 * Keep going as long as the first event hasn't matured and 601 * we havn't passed our maximum wait time. 602 */ 603 while ((event == NULL || !in_past(event->event_time)) && 604 (nsec == 0 || !in_past(waitcap))) { 605 struct timespec eventwait; 606 607 /* 608 * Three cases: 609 * no maximum waittime - just use the event 610 * both an event and cap - take the least one 611 * just a maximum waittime - use it 612 */ 613 if (nsec == 0) { 614 eventwait = event->event_time; 615 } else if (event != NULL) { 616 uint64_t diff; 617 diff = SEC_TO_NSEC(event->event_time.tv_sec - 618 waitcap.tv_sec) + 619 event->event_time.tv_nsec - waitcap.tv_nsec; 620 621 if (diff > 0) 622 eventwait = waitcap; 623 else 624 eventwait = event->event_time; 625 } else { 626 /* 627 * Note that if the event is NULL then nsec is 628 * nonzero and waitcap is valid. 629 */ 630 eventwait = waitcap; 631 } 632 633 (void) pthread_cond_timedwait(&event_queue_cond, 634 &event_queue_mutex, &eventwait); 635 event = uu_list_first(event_queue); 636 } 637 } 638 639 /* 640 * At this point we've met the guard contition of the while loop. 641 * The event at the top of the queue might be mature in which case 642 * we use it. Otherwise we hit our cap and we need to enqueue a 643 * quiesced queue event. 644 */ 645 if (event != NULL && in_past(event->event_time)) { 646 uu_list_remove(event_queue, event); 647 uu_list_node_fini(event, &event->event_node, event_pool); 648 } else { 649 event = nwamd_event_init(NWAM_EVENT_TYPE_QUEUE_QUIET, 650 NWAM_OBJECT_TYPE_UNKNOWN, 0, NULL); 651 } 652 653 if (event != NULL) 654 nlog(LOG_DEBUG, 655 "dequeueing event %lld of type %d (%s) for object %s", 656 event->event_id, event->event_type, 657 nwamd_event_name(event->event_type), 658 event->event_object[0] != 0 ? event->event_object : 659 "none"); 660 661 (void) pthread_mutex_unlock(&event_queue_mutex); 662 663 return (event); 664 } 665 666 void 667 nwamd_event_send(nwam_event_t event_msg) 668 { 669 nwam_error_t err; 670 671 if (shutting_down && event_msg->nwe_type != NWAM_EVENT_TYPE_SHUTDOWN) { 672 nlog(LOG_DEBUG, "nwamd_event_send: tossing event as nwamd " 673 "is shutting down"); 674 return; 675 } 676 677 err = nwam_event_send(event_msg); 678 679 if (err != NWAM_SUCCESS) { 680 nlog(LOG_ERR, "nwamd_event_send: nwam_event_send: %s", 681 nwam_strerror(err)); 682 } 683 } 684 685 /* 686 * Run state machine for object. Method is run if 687 * - event method is non-null 688 * - event method is valid for current object state (determined by 689 * ORing the current state against the set of valid states for the method). 690 * 691 * If these criteria are met, the method is run. 692 */ 693 static void 694 nwamd_event_run_method(nwamd_event_t event) 695 { 696 nwamd_event_method_t *event_methods; 697 int i; 698 699 event_methods = nwamd_object_event_methods(event->event_object_type); 700 701 /* If we're shutting down, only fini events are accepted for objects */ 702 if (shutting_down && event->event_type != NWAM_EVENT_TYPE_OBJECT_FINI) { 703 nlog(LOG_DEBUG, "nwamd_event_run_method: tossing non-fini " 704 "event %s for object %s", 705 nwamd_event_name(event->event_type), event->event_object); 706 return; 707 } 708 709 for (i = 0; 710 event_methods[i].event_type != NWAM_EVENT_TYPE_NOOP; 711 i++) { 712 if (event_methods[i].event_type == 713 event->event_type && 714 event_methods[i].event_method != NULL) { 715 nlog(LOG_DEBUG, 716 "(%p) %s: running method for event %s", 717 (void *)event, event->event_object, 718 nwamd_event_name(event->event_type)); 719 /* run method */ 720 event_methods[i].event_method(event); 721 return; 722 } 723 } 724 nlog(LOG_DEBUG, "(%p) %s: no matching method for event %d (%s)", 725 (void *)event, event->event_object, event->event_type, 726 nwamd_event_name(event->event_type)); 727 } 728 729 /* 730 * Called when we are checking to see what should be activated. First activate 731 * all of the manual NCUs. Then see if we can find a valid priority group. 732 * If we can, activate it. Otherwise try all the priority groups starting 733 * with the lowest one that makes sense. 734 */ 735 static void 736 nwamd_activate_ncus(void) { 737 int64_t prio = INVALID_PRIORITY_GROUP; 738 boolean_t selected; 739 740 nwamd_ncp_activate_manual_ncus(); 741 selected = nwamd_ncp_check_priority_group(&prio); 742 if (selected) { 743 /* 744 * Activate chosen priority group and stop anything going on in 745 * lesser priority groups. 746 */ 747 nwamd_ncp_activate_priority_group(prio); 748 nwamd_ncp_deactivate_priority_group_all(prio + 1); 749 } else { 750 /* 751 * Nothing unique could be started so try them all. Once one 752 * of them gets into a reasonable state then we will prune 753 * everything below it (see first part of this conditional). 754 */ 755 int64_t oldprio = INVALID_PRIORITY_GROUP; 756 while (nwamd_ncp_find_next_priority_group(++oldprio, &prio)) { 757 nwamd_ncp_activate_priority_group(prio); 758 oldprio = prio; 759 } 760 } 761 } 762 763 /* 764 * Event handler thread 765 * 766 * The complexity in this code comes about from wanting to delay the decision 767 * making process until after bursts of events. Keep roughly polling (waiting 768 * for .1s) until we see the queue quiet event and then block. 769 */ 770 void 771 nwamd_event_handler(void) 772 { 773 boolean_t got_shutdown_event = B_FALSE; 774 boolean_t check_conditions = B_FALSE; 775 boolean_t ncu_check = B_FALSE; 776 int queue_quiet_time = 0; 777 nwamd_event_t event; 778 779 /* 780 * Dequeue events and process them. In most cases, events have 781 * an assocated object type, and we use this to retrieve 782 * the function that will process the event. 783 */ 784 while (!got_shutdown_event) { 785 event = nwamd_event_dequeue(queue_quiet_time); 786 /* keep pulling events as long as they are close together */ 787 queue_quiet_time = SEC_TO_NSEC(1)/10; 788 789 /* 790 * This is an event with no associated object. 791 */ 792 if (event->event_object[0] == '\0') { 793 switch (event->event_type) { 794 case NWAM_EVENT_TYPE_NOOP: 795 case NWAM_EVENT_TYPE_INIT: 796 /* 797 * The only action for an INIT event 798 * is to relay it to event listeners, 799 * which is done below. 800 */ 801 break; 802 case NWAM_EVENT_TYPE_PRIORITY_GROUP: 803 (void) pthread_mutex_lock(&active_ncp_mutex); 804 current_ncu_priority_group = 805 event->event_msg->nwe_data. 806 nwe_priority_group_info.nwe_priority; 807 (void) pthread_mutex_unlock(&active_ncp_mutex); 808 break; 809 case NWAM_EVENT_TYPE_TIMED_CHECK_CONDITIONS: 810 if (!shutting_down) { 811 nwamd_set_timed_check_all_conditions(); 812 check_conditions = B_TRUE; 813 } 814 break; 815 case NWAM_EVENT_TYPE_TRIGGERED_CHECK_CONDITIONS: 816 if (!shutting_down) 817 check_conditions = B_TRUE; 818 break; 819 case NWAM_EVENT_TYPE_NCU_CHECK: 820 if (!shutting_down) 821 ncu_check = B_TRUE; 822 break; 823 case NWAM_EVENT_TYPE_UPGRADE: 824 if (!shutting_down) { 825 /* 826 * Upgrade events have no associated 827 * object. 828 */ 829 nwamd_event_run_method(event); 830 } 831 break; 832 case NWAM_EVENT_TYPE_SHUTDOWN: 833 got_shutdown_event = B_TRUE; 834 break; 835 836 /* 837 * We want to delay processing of condition and ncu 838 * checking until after short bursts of events. So we 839 * keep track of times we've scheduled checking and 840 * wait for the queue to quiesce. 841 */ 842 case NWAM_EVENT_TYPE_QUEUE_QUIET: 843 queue_quiet_time = 0; /* now we can block */ 844 if (!shutting_down && check_conditions) { 845 nwamd_check_all_conditions(); 846 check_conditions = B_FALSE; 847 } 848 849 if (!shutting_down && ncu_check) { 850 nwamd_activate_ncus(); 851 ncu_check = B_FALSE; 852 } 853 break; 854 855 default: 856 nlog(LOG_ERR, 857 "event %d (%s)had no object associated " 858 "with it", event->event_type, 859 nwamd_event_name(event->event_type)); 860 break; 861 } 862 } else { 863 /* 864 * Event has an associated object - run event method 865 * for that object type (if any). 866 */ 867 nwamd_event_run_method(event); 868 } 869 /* 870 * Send associated message to listeners if event type is 871 * externally visible. 872 */ 873 if (event->event_send) 874 nwamd_event_send(event->event_msg); 875 876 nwamd_event_fini(event); 877 } 878 /* If we get here, we got a shutdown event. */ 879 nwamd_event_queue_fini(); 880 nwamd_object_lists_fini(); 881 } 882