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 *
nwamd_event_name(int event_type)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
nwamd_event_sources_init(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
nwamd_event_sources_fini(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
nwamd_event_compare(const void * l_arg,const void * r_arg,void * private)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
nwamd_event_queue_init(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
nwamd_event_queue_fini(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
nwamd_event_init(int32_t type,nwam_object_type_t object_type,size_t size,const char * object_name)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
nwamd_event_do_not_send(nwamd_event_t event)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
nwamd_event_fini(nwamd_event_t event)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
nwamd_event_init_object_action(nwam_object_type_t object_type,const char * object_name,const char * parent_name,nwam_action_t object_action)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
nwamd_event_init_object_state(nwam_object_type_t object_type,const char * object_name,nwam_state_t state,nwam_aux_state_t aux_state)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
nwamd_event_init_priority_group_change(int64_t priority)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
nwamd_event_init_link_action(const char * name,nwam_action_t link_action)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
nwamd_event_init_link_state(const char * name,boolean_t up)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
nwamd_event_init_if_state(const char * linkname,uint32_t flags,uint32_t addr_added,struct sockaddr * addr,struct sockaddr * netmask)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
nwamd_event_init_wlan(const char * name,int32_t type,boolean_t connected,nwam_wlan_t * wlans,uint_t num_wlans)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
nwamd_event_init_ncu_check(void)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
nwamd_event_init_init(void)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
nwamd_event_init_shutdown(void)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
nwamd_event_enqueue(nwamd_event_t event)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
nwamd_event_enqueue_timed(nwamd_event_t event,int delta_seconds)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
nwamd_event_enqueued(int32_t event_type,nwam_object_type_t object_type,const char * object)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
in_past(struct timespec 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
nwamd_event_dequeue(long nsec)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
nwamd_event_send(nwam_event_t event_msg)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
nwamd_event_run_method(nwamd_event_t event)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
nwamd_activate_ncus(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
nwamd_event_handler(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