Move /var/svc/log to /var/log/svc
[unleashed/lotheac.git] / usr / src / cmd / cmd-inet / lib / nwamd / ncu.c
blobe94435d7813d98a4c39036940ab5ed27e74ecaa0
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
27 #include <arpa/inet.h>
28 #include <assert.h>
29 #include <errno.h>
30 #include <libdlaggr.h>
31 #include <libdllink.h>
32 #include <libdlstat.h>
33 #include <libnwam.h>
34 #include <libscf.h>
35 #include <netinet/in.h>
36 #include <stdlib.h>
37 #include <strings.h>
38 #include <sys/param.h>
39 #include <sys/socket.h>
40 #include <sys/time.h>
41 #include <sys/types.h>
42 #include <values.h>
43 #include <zone.h>
45 #include "conditions.h"
46 #include "events.h"
47 #include "objects.h"
48 #include "ncp.h"
49 #include "util.h"
52 * ncu.c - handles various NCU tasks - intialization/refresh, state machine
53 * for NCUs etc.
56 #define VBOX_IFACE_PREFIX "vboxnet"
58 static void populate_ip_ncu_properties(nwam_ncu_handle_t, nwamd_ncu_t *);
61 * Find ncu of specified type for link/interface name.
63 nwamd_object_t
64 nwamd_ncu_object_find(nwam_ncu_type_t type, const char *name)
66 nwam_error_t err;
67 char *object_name;
68 nwamd_object_t ncu_obj = NULL;
70 if ((err = nwam_ncu_name_to_typed_name(name, type, &object_name))
71 != NWAM_SUCCESS) {
72 nlog(LOG_ERR, "nwamd_ncu_find: nwam_ncu_name_to_typed_name "
73 "returned %s", nwam_strerror(err));
74 return (NULL);
76 ncu_obj = nwamd_object_find(NWAM_OBJECT_TYPE_NCU, object_name);
78 free(object_name);
79 return (ncu_obj);
82 nwam_error_t
83 nwamd_set_ncu_string(nwam_ncu_handle_t ncuh, char **strval, uint_t cnt,
84 const char *prop)
86 nwam_error_t err;
87 nwam_value_t val;
89 if ((err = nwam_value_create_string_array(strval, cnt, &val))
90 != NWAM_SUCCESS)
91 return (err);
92 err = nwam_ncu_set_prop_value(ncuh, prop, val);
93 nwam_value_free(val);
94 return (err);
97 nwam_error_t
98 nwamd_set_ncu_uint(nwam_ncu_handle_t ncuh, uint64_t *uintval, uint_t cnt,
99 const char *prop)
101 nwam_error_t err;
102 nwam_value_t val;
104 if ((err = nwam_value_create_uint64_array(uintval, cnt, &val))
105 != NWAM_SUCCESS)
106 return (err);
107 err = nwam_ncu_set_prop_value(ncuh, prop, val);
108 nwam_value_free(val);
109 return (err);
112 nwam_error_t
113 nwamd_get_ncu_string(nwam_ncu_handle_t ncuh, nwam_value_t *val, char ***strval,
114 uint_t *cnt, const char *prop)
116 nwam_error_t err;
118 if ((err = nwam_ncu_get_prop_value(ncuh, prop, val)) != NWAM_SUCCESS)
119 return (err);
120 return (nwam_value_get_string_array(*val, strval, cnt));
123 nwam_error_t
124 nwamd_get_ncu_uint(nwam_ncu_handle_t ncuh, nwam_value_t *val,
125 uint64_t **uintval, uint_t *cnt, const char *prop)
127 nwam_error_t err;
129 if ((err = nwam_ncu_get_prop_value(ncuh, prop, val)) != NWAM_SUCCESS)
130 return (err);
131 return (nwam_value_get_uint64_array(*val, uintval, cnt));
134 nwam_error_t
135 nwamd_get_ncu_boolean(nwam_ncu_handle_t ncuh, nwam_value_t *val,
136 boolean_t **boolval, uint_t *cnt, const char *prop)
138 nwam_error_t err;
140 if ((err = nwam_ncu_get_prop_value(ncuh, prop, val)) != NWAM_SUCCESS)
141 return (err);
142 return (nwam_value_get_boolean_array(*val, boolval, cnt));
146 * Run link/interface state machine in response to a state change
147 * or enable/disable action event.
149 static void
150 nwamd_ncu_state_machine(const char *object_name)
152 nwamd_object_t object;
153 nwamd_ncu_t *ncu;
154 link_state_t link_state;
155 nwamd_event_t event;
156 nwam_wlan_t key_wlan, connected_wlan;
157 nwamd_link_t *link;
158 char linkname[NWAM_MAX_NAME_LEN];
159 boolean_t up;
161 if ((object = nwamd_object_find(NWAM_OBJECT_TYPE_NCU, object_name))
162 == NULL) {
163 nlog(LOG_ERR, "nwamd_ncu_state_machine: "
164 "request for nonexistent NCU %s", object_name);
165 return;
168 ncu = object->nwamd_object_data;
169 link = &ncu->ncu_link;
171 switch (object->nwamd_object_aux_state) {
172 case NWAM_AUX_STATE_INITIALIZED:
173 if (ncu->ncu_type == NWAM_NCU_TYPE_LINK) {
175 * For wired/wireless links, need to get link
176 * up/down events and even if these are not supported,
177 * dlpi_open()ing the link prevents the driver from
178 * being unloaded.
180 nwamd_dlpi_add_link(object);
182 if (link->nwamd_link_media == DL_WIFI) {
184 * First, if we're unexpectedly connected,
185 * disconnect.
187 if (!link->nwamd_link_wifi_connected &&
188 nwamd_wlan_connected(object)) {
189 nlog(LOG_DEBUG,
190 "nwamd_ncu_state_machine: "
191 "WiFi unexpectedly connected, "
192 "disconnecting...");
193 (void) dladm_wlan_disconnect(dld_handle,
194 link->nwamd_link_id);
195 nwamd_set_selected_connected(ncu,
196 B_FALSE, B_FALSE);
198 /* move to scanning aux state */
199 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
200 object_name, object->nwamd_object_state,
201 NWAM_AUX_STATE_LINK_WIFI_SCANNING);
202 } else {
204 * If initial wired link state is unknown, we
205 * will need to assume the link is up, since
206 * we won´t get DL_NOTE_LINK_UP/DOWN events.
208 link_state = nwamd_get_link_state
209 (ncu->ncu_name);
210 if (link_state == LINK_STATE_UP ||
211 link_state == LINK_STATE_UNKNOWN) {
212 nwamd_object_set_state
213 (NWAM_OBJECT_TYPE_NCU,
214 object_name, NWAM_STATE_ONLINE,
215 NWAM_AUX_STATE_UP);
216 } else {
217 nwamd_object_set_state
218 (NWAM_OBJECT_TYPE_NCU,
219 object_name,
220 NWAM_STATE_ONLINE_TO_OFFLINE,
221 NWAM_AUX_STATE_DOWN);
224 } else {
226 * In the current implementation, initialization has to
227 * start from scratch since the complexity of minimizing
228 * configuration change is considerable (e.g. if we
229 * refresh and had DHCP running on the physical
230 * interface, and now have changed to static assignment,
231 * we need to remove DHCP etc). To avoid all this,
232 * unplumb before re-plumbing the protocols and
233 * addresses we wish to configure. In the future, it
234 * would be good to try and minimize configuration
235 * changes.
237 nwamd_unplumb_interface(ncu, AF_INET);
238 nwamd_unplumb_interface(ncu, AF_INET6);
241 * We may be restarting the state machine. Re-read
242 * the IP NCU properties as the ipadm_addrobj_t in
243 * nwamd_if_address should not be reused.
245 populate_ip_ncu_properties(object->nwamd_object_handle,
246 ncu);
249 * Enqueue a WAITING_FOR_ADDR aux state change so that
250 * we are eligible to receive the IF_STATE events
251 * associated with static, DHCP, DHCPv6 and autoconf
252 * address assignment. The latter two can happen
253 * quite quickly after plumbing so we need to be ready.
255 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
256 object_name, NWAM_STATE_OFFLINE_TO_ONLINE,
257 NWAM_AUX_STATE_IF_WAITING_FOR_ADDR);
259 if (ncu->ncu_if.nwamd_if_ipv4)
260 nwamd_plumb_interface(ncu, AF_INET);
262 if (ncu->ncu_if.nwamd_if_ipv6)
263 nwamd_plumb_interface(ncu, AF_INET6);
265 /* Configure addresses */
266 nwamd_configure_interface_addresses(ncu);
268 break;
270 case NWAM_AUX_STATE_IF_DHCP_TIMED_OUT:
271 case NWAM_AUX_STATE_IF_WAITING_FOR_ADDR:
273 * nothing to do here - RTM_NEWADDRs will trigger IF_STATE
274 * events to move us online.
276 break;
278 case NWAM_AUX_STATE_LINK_WIFI_SCANNING:
279 /* launch scan thread */
280 (void) strlcpy(linkname, ncu->ncu_name, sizeof (linkname));
281 (void) nwamd_wlan_scan(linkname);
282 /* Create periodic scan event */
283 nwamd_ncu_create_periodic_scan_event(object);
284 break;
286 case NWAM_AUX_STATE_LINK_WIFI_NEED_SELECTION:
287 /* send "need choice" event */
288 event = nwamd_event_init_wlan
289 (ncu->ncu_name, NWAM_EVENT_TYPE_WLAN_NEED_CHOICE, B_FALSE,
290 link->nwamd_link_wifi_scan.nwamd_wifi_scan_curr,
291 link->nwamd_link_wifi_scan.nwamd_wifi_scan_curr_num);
292 if (event == NULL)
293 break;
294 nwamd_event_enqueue(event);
295 nwamd_set_selected_connected(ncu, B_FALSE, B_FALSE);
296 break;
298 case NWAM_AUX_STATE_LINK_WIFI_NEED_KEY:
300 * Send "need key" event. Set selected to true, connected
301 * and have_key to false. Do not fill in WLAN details as
302 * multiple WLANs may match the ESSID name, and each may
303 * have a different speed and channel.
305 bzero(&key_wlan, sizeof (key_wlan));
306 (void) strlcpy(key_wlan.nww_essid, link->nwamd_link_wifi_essid,
307 sizeof (key_wlan.nww_essid));
308 (void) strlcpy(key_wlan.nww_bssid, link->nwamd_link_wifi_bssid,
309 sizeof (key_wlan.nww_bssid));
310 key_wlan.nww_security_mode =
311 link->nwamd_link_wifi_security_mode;
312 key_wlan.nww_selected = B_TRUE;
313 key_wlan.nww_connected = B_FALSE;
314 key_wlan.nww_have_key = B_FALSE;
315 event = nwamd_event_init_wlan
316 (ncu->ncu_name, NWAM_EVENT_TYPE_WLAN_NEED_KEY, B_FALSE,
317 &key_wlan, 1);
318 if (event == NULL)
319 break;
320 nwamd_event_enqueue(event);
321 break;
323 case NWAM_AUX_STATE_LINK_WIFI_CONNECTING:
324 (void) strlcpy(linkname, ncu->ncu_name, sizeof (linkname));
325 nwamd_wlan_connect(linkname);
326 break;
328 case NWAM_AUX_STATE_UP:
329 case NWAM_AUX_STATE_DOWN:
330 up = (object->nwamd_object_aux_state == NWAM_AUX_STATE_UP);
331 if (ncu->ncu_type == NWAM_NCU_TYPE_LINK) {
332 if (link->nwamd_link_media == DL_WIFI) {
334 * Connected/disconnected - send WLAN
335 * connection report.
337 link->nwamd_link_wifi_connected = up;
338 nwamd_set_selected_connected(ncu, B_TRUE, up);
340 (void) strlcpy(connected_wlan.nww_essid,
341 link->nwamd_link_wifi_essid,
342 sizeof (connected_wlan.nww_essid));
343 (void) strlcpy(connected_wlan.nww_bssid,
344 link->nwamd_link_wifi_bssid,
345 sizeof (connected_wlan.nww_bssid));
346 connected_wlan.nww_security_mode =
347 link->nwamd_link_wifi_security_mode;
348 event = nwamd_event_init_wlan
349 (ncu->ncu_name,
350 NWAM_EVENT_TYPE_WLAN_CONNECTION_REPORT, up,
351 &connected_wlan, 1);
352 if (event == NULL)
353 break;
354 nwamd_event_enqueue(event);
357 * If disconnected, restart the state machine
358 * for the WiFi link (WiFi is always trying
359 * to connect).
361 * If connected, start signal strength
362 * monitoring thread.
364 if (!up && ncu->ncu_enabled) {
365 nlog(LOG_DEBUG,
366 "nwamd_ncu_state_machine: "
367 "wifi disconnect - start over "
368 "after %dsec interval",
369 WIRELESS_RETRY_INTERVAL);
370 link->nwamd_link_wifi_connected =
371 B_FALSE;
372 /* propogate down event to IP NCU */
373 nwamd_propogate_link_up_down_to_ip
374 (ncu->ncu_name, B_FALSE);
375 nwamd_object_set_state_timed
376 (NWAM_OBJECT_TYPE_NCU, object_name,
377 NWAM_STATE_OFFLINE_TO_ONLINE,
378 NWAM_AUX_STATE_INITIALIZED,
379 WIRELESS_RETRY_INTERVAL);
380 } else {
381 nlog(LOG_DEBUG,
382 "nwamd_ncu_state_machine: "
383 "wifi connected, start monitoring");
384 (void) strlcpy(linkname, ncu->ncu_name,
385 sizeof (linkname));
386 nwamd_wlan_monitor_signal(linkname);
391 /* If not in ONLINE/OFFLINE state yet, change state */
392 if ((up && object->nwamd_object_state != NWAM_STATE_ONLINE) ||
393 (!up && object->nwamd_object_state != NWAM_STATE_OFFLINE)) {
394 nlog(LOG_DEBUG, "nwamd_ncu_state_machine: "
395 "%s is moving %s", object_name,
396 up ? "online" : "offline");
397 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
398 object_name,
399 up ? NWAM_STATE_ONLINE : NWAM_STATE_OFFLINE,
400 up ? NWAM_AUX_STATE_UP : NWAM_AUX_STATE_DOWN);
402 if (ncu->ncu_type == NWAM_NCU_TYPE_INTERFACE) {
403 if (up) {
405 * Moving online, add v4/v6 default
406 * routes (if any).
408 nwamd_add_default_routes(ncu);
409 } else {
411 * If this is an interface NCU and we
412 * got a down event, it is a consequence
413 * of NCU refresh, so reapply addresses
414 * by reinitializing.
416 nwamd_object_set_state
417 (NWAM_OBJECT_TYPE_NCU, object_name,
418 NWAM_STATE_OFFLINE_TO_ONLINE,
419 NWAM_AUX_STATE_INITIALIZED);
422 } else {
423 nlog(LOG_DEBUG, "nwamd_ncu_state_machine: "
424 "%s is %s", object_name,
425 up ? "online" : "offline");
428 * NCU is UP or DOWN, trigger all condition checking, even if
429 * the NCU is already in the ONLINE state - an ENM may depend
430 * on NCU activity.
432 nwamd_create_triggered_condition_check_event(NEXT_FEW_SECONDS);
433 break;
435 case NWAM_AUX_STATE_CONDITIONS_NOT_MET:
437 * Link/interface is moving offline. Nothing to do except
438 * for WiFi, where we disconnect. Don't unplumb IP on
439 * a link since it may be a transient change.
441 if (ncu->ncu_type == NWAM_NCU_TYPE_LINK) {
442 if (link->nwamd_link_media == DL_WIFI) {
443 (void) dladm_wlan_disconnect(dld_handle,
444 link->nwamd_link_id);
445 link->nwamd_link_wifi_connected = B_FALSE;
446 nwamd_set_selected_connected(ncu, B_FALSE,
447 B_FALSE);
449 } else {
451 * Unplumb here. In the future we may elaborate on
452 * the approach used and not unplumb for WiFi
453 * until we reconnect to a different WLAN (i.e. with
454 * a different ESSID).
456 nwamd_unplumb_interface(ncu, AF_INET);
457 nwamd_unplumb_interface(ncu, AF_INET6);
459 if (object->nwamd_object_state != NWAM_STATE_OFFLINE) {
460 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
461 object_name, NWAM_STATE_OFFLINE,
462 NWAM_AUX_STATE_CONDITIONS_NOT_MET);
464 break;
466 case NWAM_AUX_STATE_MANUAL_DISABLE:
467 /* Manual disable, set enabled state appropriately. */
468 ncu->ncu_enabled = B_FALSE;
469 /* FALLTHROUGH */
470 case NWAM_AUX_STATE_UNINITIALIZED:
471 case NWAM_AUX_STATE_NOT_FOUND:
473 * Link/interface NCU has been disabled/deactivated/removed.
474 * For WiFi links disconnect, and for IP interfaces we unplumb.
476 if (ncu->ncu_type == NWAM_NCU_TYPE_LINK) {
477 if (link->nwamd_link_media == DL_WIFI) {
478 (void) dladm_wlan_disconnect(dld_handle,
479 link->nwamd_link_id);
480 link->nwamd_link_wifi_connected = B_FALSE;
481 nwamd_set_selected_connected(ncu, B_FALSE,
482 B_FALSE);
484 nwamd_dlpi_delete_link(object);
485 } else {
486 /* Unplumb here. */
487 if (ncu->ncu_if.nwamd_if_ipv4) {
488 nwamd_unplumb_interface(ncu, AF_INET);
490 if (ncu->ncu_if.nwamd_if_ipv6) {
491 nwamd_unplumb_interface(ncu, AF_INET6);
493 /* trigger location condition checking */
494 nwamd_create_triggered_condition_check_event(0);
497 switch (object->nwamd_object_aux_state) {
498 case NWAM_AUX_STATE_MANUAL_DISABLE:
499 /* Change state to DISABLED if manually disabled */
500 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
501 object_name, NWAM_STATE_DISABLED,
502 NWAM_AUX_STATE_MANUAL_DISABLE);
503 /* Note that NCU has been disabled */
504 ncu->ncu_enabled = B_FALSE;
505 break;
506 case NWAM_AUX_STATE_NOT_FOUND:
507 /* Change state to UNINITIALIZED for device removal */
508 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
509 object_name, NWAM_STATE_UNINITIALIZED,
510 NWAM_AUX_STATE_NOT_FOUND);
511 break;
512 default:
513 break;
515 break;
516 default:
517 nlog(LOG_ERR, "nwamd_ncu_state_machine: unexpected state");
518 break;
521 nwamd_object_release(object);
524 static int
525 ncu_create_init_fini_event(nwam_ncu_handle_t ncuh, void *data)
527 boolean_t *init = data;
528 char *name, *typedname;
529 nwam_error_t err;
530 nwam_value_t typeval = NULL;
531 uint64_t *type;
532 uint_t numvalues;
533 nwamd_event_t ncu_event;
535 if (nwam_ncu_get_name(ncuh, &name) != NWAM_SUCCESS) {
536 nlog(LOG_ERR,
537 "ncu_create_init_fini_event: could not get NCU name");
538 return (0);
541 nlog(LOG_DEBUG, "ncu_create_init_fini_event(%s, %p)", name, data);
543 if ((err = nwamd_get_ncu_uint(ncuh, &typeval, &type, &numvalues,
544 NWAM_NCU_PROP_TYPE)) != NWAM_SUCCESS) {
545 nlog(LOG_ERR, "ncu_create_init_fini_event: "
546 "could not get NCU type: %s", nwam_strerror(err));
547 free(name);
548 nwam_value_free(typeval);
549 return (0);
552 /* convert name to typedname for event */
553 if ((err = nwam_ncu_name_to_typed_name(name, *type, &typedname))
554 != NWAM_SUCCESS) {
555 nlog(LOG_ERR, "ncu_create_init_fini_event: "
556 "NCU name translation failed: %s", nwam_strerror(err));
557 free(name);
558 return (0);
560 free(name);
561 nwam_value_free(typeval);
563 ncu_event = nwamd_event_init(*init ?
564 NWAM_EVENT_TYPE_OBJECT_INIT : NWAM_EVENT_TYPE_OBJECT_FINI,
565 NWAM_OBJECT_TYPE_NCU, 0, typedname);
566 if (ncu_event != NULL)
567 nwamd_event_enqueue(ncu_event);
568 free(typedname);
570 return (0);
574 * Initialization - walk the NCUs, creating initialization events for each
575 * NCU. nwamd_ncu_handle_init_event() will check if the associated
576 * physical link exists or not.
578 void
579 nwamd_init_ncus(void)
581 boolean_t init = B_TRUE;
583 (void) pthread_mutex_lock(&active_ncp_mutex);
584 if (active_ncph != NULL) {
585 nlog(LOG_DEBUG, "nwamd_init_ncus: "
586 "(re)intializing NCUs for NCP %s", active_ncp);
587 (void) nwam_ncp_walk_ncus(active_ncph,
588 ncu_create_init_fini_event, &init, NWAM_FLAG_NCU_TYPE_ALL,
589 NULL);
591 (void) pthread_mutex_unlock(&active_ncp_mutex);
594 void
595 nwamd_fini_ncus(void)
597 boolean_t init = B_FALSE;
599 /* We may not have an active NCP on initialization, so skip fini */
600 (void) pthread_mutex_lock(&active_ncp_mutex);
601 if (active_ncph != NULL) {
602 nlog(LOG_DEBUG, "nwamd_fini_ncus: deinitializing NCUs for %s",
603 active_ncp);
604 (void) nwam_ncp_walk_ncus(active_ncph,
605 ncu_create_init_fini_event, &init, NWAM_FLAG_NCU_TYPE_ALL,
606 NULL);
608 (void) pthread_mutex_unlock(&active_ncp_mutex);
612 * Most properties of this type don't need to be cached locally. Only those
613 * interesting to the daemon are stored in an nwamd_ncu_t.
615 static void
616 populate_common_ncu_properties(nwam_ncu_handle_t ncuh, nwamd_ncu_t *ncu_data)
618 nwam_value_t ncu_prop;
619 nwam_error_t err;
620 boolean_t enablevalue;
621 uint_t numvalues;
622 char **parent;
624 if ((err = nwam_ncu_get_prop_value(ncuh, NWAM_NCU_PROP_ENABLED,
625 &ncu_prop)) != NWAM_SUCCESS) {
626 char *name;
627 (void) nwam_ncu_name_to_typed_name(ncu_data->ncu_name,
628 ncu_data->ncu_type, &name);
629 nlog(LOG_ERR, "nwam_ncu_get_prop_value %s ENABLED failed: %s",
630 name, nwam_strerror(err));
631 free(name);
632 ncu_data->ncu_enabled = B_TRUE;
633 } else {
634 if ((err = nwam_value_get_boolean(ncu_prop, &enablevalue)) !=
635 NWAM_SUCCESS) {
636 nlog(LOG_ERR, "nwam_value_get_boolean ENABLED failed: "
637 "%s", nwam_strerror(err));
638 } else {
639 ncu_data->ncu_enabled = enablevalue;
641 nwam_value_free(ncu_prop);
644 if ((err = nwamd_get_ncu_string(ncuh, &ncu_prop, &parent,
645 &numvalues, NWAM_NCU_PROP_PARENT_NCP)) != NWAM_SUCCESS) {
646 nlog(LOG_ERR, "nwam_ncu_get_prop_value %s PARENT failed: %s",
647 ncu_data->ncu_name, nwam_strerror(err));
648 } else {
649 (void) strlcpy(ncu_data->ncu_parent, parent[0],
650 sizeof (ncu_data->ncu_parent));
651 nwam_value_free(ncu_prop);
656 * Read in link properties.
658 static void
659 populate_link_ncu_properties(nwam_ncu_handle_t ncuh, nwamd_ncu_t *ncu_data)
661 nwam_value_t ncu_prop;
662 nwam_error_t err;
663 char **mac_addr;
664 uint64_t *uintval;
665 uint_t numvalues;
667 /* activation-mode */
668 if ((err = nwamd_get_ncu_uint(ncuh, &ncu_prop, &uintval, &numvalues,
669 NWAM_NCU_PROP_ACTIVATION_MODE)) != NWAM_SUCCESS) {
670 nlog(LOG_ERR,
671 "populate_link_ncu_properties: could not get %s value: %s",
672 NWAM_NCU_PROP_ACTIVATION_MODE, nwam_strerror(err));
673 } else {
674 ncu_data->ncu_link.nwamd_link_activation_mode = uintval[0];
675 nwam_value_free(ncu_prop);
678 /* priority-group and priority-mode for prioritized activation */
679 if (ncu_data->ncu_link.nwamd_link_activation_mode ==
680 NWAM_ACTIVATION_MODE_PRIORITIZED) {
681 /* ncus with prioritized activation are always enabled */
682 ncu_data->ncu_enabled = B_TRUE;
683 if ((err = nwamd_get_ncu_uint(ncuh, &ncu_prop, &uintval,
684 &numvalues, NWAM_NCU_PROP_PRIORITY_MODE))
685 != NWAM_SUCCESS) {
686 nlog(LOG_ERR, "populate_link_ncu_properties: "
687 "could not get %s value: %s",
688 NWAM_NCU_PROP_PRIORITY_MODE, nwam_strerror(err));
689 } else {
690 ncu_data->ncu_link.nwamd_link_priority_mode =
691 uintval[0];
692 nwam_value_free(ncu_prop);
695 if ((err = nwamd_get_ncu_uint(ncuh, &ncu_prop, &uintval,
696 &numvalues, NWAM_NCU_PROP_PRIORITY_GROUP))
697 != NWAM_SUCCESS) {
698 nlog(LOG_ERR, "populate_link_ncu_properties: "
699 "could not get %s value: %s",
700 NWAM_NCU_PROP_PRIORITY_GROUP, nwam_strerror(err));
701 } else {
702 ncu_data->ncu_link.nwamd_link_priority_group =
703 uintval[0];
704 nwam_value_free(ncu_prop);
708 /* link-mac-addr */
709 if ((err = nwamd_get_ncu_string(ncuh, &ncu_prop, &mac_addr, &numvalues,
710 NWAM_NCU_PROP_LINK_MAC_ADDR)) != NWAM_SUCCESS) {
711 nlog(LOG_DEBUG,
712 "populate_link_ncu_properties: could not get %s value: %s",
713 NWAM_NCU_PROP_LINK_MAC_ADDR, nwam_strerror(err));
714 ncu_data->ncu_link.nwamd_link_mac_addr = NULL;
715 } else {
716 ncu_data->ncu_link.nwamd_link_mac_addr = strdup(*mac_addr);
717 ncu_data->ncu_link.nwamd_link_mac_addr_len = strlen(*mac_addr);
718 nwam_value_free(ncu_prop);
721 /* link-mtu */
722 if ((err = nwamd_get_ncu_uint(ncuh, &ncu_prop, &uintval, &numvalues,
723 NWAM_NCU_PROP_LINK_MTU)) != NWAM_SUCCESS) {
724 nlog(LOG_DEBUG,
725 "populate_link_ncu_properties: could not get %s value: %s",
726 NWAM_NCU_PROP_LINK_MTU, nwam_strerror(err));
727 ncu_data->ncu_link.nwamd_link_mtu = 0;
728 } else {
729 ncu_data->ncu_link.nwamd_link_mtu = uintval[0];
730 nwam_value_free(ncu_prop);
733 /* link-autopush */
734 if ((err = nwamd_get_ncu_string(ncuh, &ncu_prop,
735 &ncu_data->ncu_link.nwamd_link_autopush,
736 &ncu_data->ncu_link.nwamd_link_num_autopush,
737 NWAM_NCU_PROP_LINK_AUTOPUSH)) != NWAM_SUCCESS) {
738 nlog(LOG_DEBUG,
739 "populate_link_ncu_properties: could not get %s value: %s",
740 NWAM_NCU_PROP_LINK_AUTOPUSH, nwam_strerror(err));
741 ncu_data->ncu_link.nwamd_link_num_autopush = 0;
745 static void
746 populate_ip_ncu_properties(nwam_ncu_handle_t ncuh, nwamd_ncu_t *ncu_data)
748 nwamd_if_t *nif = &ncu_data->ncu_if;
749 struct nwamd_if_address **nifa, *nifai, *nifait;
750 boolean_t static_addr = B_FALSE, *boolvalue, dhcp_primary = B_FALSE;
751 uint64_t *addrsrcvalue;
752 nwam_value_t ncu_prop;
753 nwam_error_t err;
754 ipadm_addrobj_t ipaddr;
755 ipadm_status_t ipstatus;
756 char **addrvalue, ipreqhost[MAXNAMELEN];
757 uint_t numvalues;
758 uint64_t *ipversion;
759 int i;
761 nif->nwamd_if_ipv4 = B_FALSE;
762 nif->nwamd_if_ipv6 = B_FALSE;
763 nif->nwamd_if_dhcp_requested = B_FALSE;
764 nif->nwamd_if_stateful_requested = B_FALSE;
765 nif->nwamd_if_stateless_requested = B_FALSE;
766 nif->nwamd_if_ipv4_default_route_set = B_FALSE;
767 nif->nwamd_if_ipv6_default_route_set = B_FALSE;
769 /* ip-version */
770 if ((err = nwamd_get_ncu_uint(ncuh, &ncu_prop, &ipversion, &numvalues,
771 NWAM_NCU_PROP_IP_VERSION)) != NWAM_SUCCESS) {
772 nlog(LOG_ERR,
773 "populate_ip_ncu_properties: could not get %s value: %s",
774 NWAM_NCU_PROP_IP_VERSION, nwam_strerror(err));
775 } else {
776 for (i = 0; i < numvalues; i++) {
777 switch (ipversion[i]) {
778 case IPV4_VERSION:
779 nif->nwamd_if_ipv4 = B_TRUE;
780 break;
781 case IPV6_VERSION:
782 nif->nwamd_if_ipv6 = B_TRUE;
783 break;
784 default:
785 nlog(LOG_ERR, "bogus ip version %lld",
786 ipversion[i]);
787 break;
790 nwam_value_free(ncu_prop);
793 /* ip-primary */
794 if ((err = nwamd_get_ncu_boolean(ncuh, &ncu_prop, &boolvalue,
795 &numvalues, NWAM_NCU_PROP_IP_PRIMARY)) != NWAM_SUCCESS) {
796 /* ip-primary is optional, so do not LOG_ERR */
797 nlog(LOG_DEBUG, "populate_ip_ncu_properties: "
798 "could not get %s value: %s",
799 NWAM_NCU_PROP_IP_PRIMARY, nwam_strerror(err));
800 } else {
801 if (numvalues > 0)
802 dhcp_primary = boolvalue[0];
803 nwam_value_free(ncu_prop);
806 /* ip-reqhost */
807 *ipreqhost = '\0';
809 if ((err = nwamd_get_ncu_string(ncuh, &ncu_prop, &addrvalue,
810 &numvalues, NWAM_NCU_PROP_IP_REQHOST)) != NWAM_SUCCESS) {
811 /* ip-reqhost is optional, so do not LOG_ERR */
812 nlog(LOG_DEBUG, "populate_ip_ncu_properties: "
813 "could not get %s value: %s",
814 NWAM_NCU_PROP_IP_REQHOST, nwam_strerror(err));
815 } else {
816 if (numvalues > 0 && strlcpy(ipreqhost, addrvalue[0],
817 sizeof (ipreqhost)) >= sizeof (ipreqhost)) {
818 nlog(LOG_WARNING, "populate_ip_ncu_properties: "
819 "too long %s value: %s",
820 NWAM_NCU_PROP_IP_REQHOST, addrvalue[0]);
821 *ipreqhost = '\0';
823 nwam_value_free(ncu_prop);
826 /* Free the old list. */
827 for (nifai = nif->nwamd_if_list; nifai != NULL; nifai = nifait) {
828 nifait = nifai->next;
829 nifai->next = NULL;
830 ipadm_destroy_addrobj(nifai->ipaddr);
831 free(nifai);
833 nif->nwamd_if_list = NULL;
834 nifa = &(nif->nwamd_if_list);
836 if (!nif->nwamd_if_ipv4)
837 goto skip_ipv4;
839 /* ipv4-addrsrc */
840 if ((err = nwamd_get_ncu_uint(ncuh, &ncu_prop, &addrsrcvalue,
841 &numvalues, NWAM_NCU_PROP_IPV4_ADDRSRC)) != NWAM_SUCCESS) {
842 nlog(nif->nwamd_if_ipv4 ? LOG_ERR : LOG_DEBUG,
843 "populate_ip_ncu_properties: could not get %s value: %s",
844 NWAM_NCU_PROP_IPV4_ADDRSRC, nwam_strerror(err));
845 } else {
846 for (i = 0; i < numvalues; i++) {
847 switch (addrsrcvalue[i]) {
848 case NWAM_ADDRSRC_DHCP:
849 nif->nwamd_if_dhcp_requested = B_TRUE;
850 break;
851 case NWAM_ADDRSRC_STATIC:
852 static_addr = B_TRUE;
853 break;
854 default:
855 break;
858 nwam_value_free(ncu_prop);
860 if (nif->nwamd_if_dhcp_requested) {
861 ipstatus = ipadm_create_addrobj(IPADM_ADDR_DHCP,
862 ncu_data->ncu_name, &ipaddr);
863 if (ipstatus != IPADM_SUCCESS) {
864 nlog(LOG_ERR, "populate_ip_ncu_properties: "
865 "ipadm_create_addrobj failed for v4 dhcp: %s",
866 ipadm_status2str(ipstatus));
867 goto skip_ipv4_dhcp;
870 ipstatus = ipadm_set_wait_time(ipaddr, ncu_wait_time);
871 if (ipstatus != IPADM_SUCCESS) {
872 nlog(LOG_ERR, "populate_ip_ncu_properties: "
873 "ipadm_set_wait_time failed for v4 dhcp: %s",
874 ipadm_status2str(ipstatus));
875 ipadm_destroy_addrobj(ipaddr);
876 goto skip_ipv4_dhcp;
878 ipstatus = ipadm_set_primary(ipaddr, dhcp_primary);
879 if (ipstatus != IPADM_SUCCESS) {
880 nlog(LOG_ERR, "populate_ip_ncu_properties: "
881 "ipadm_set_primary failed for v4 dhcp: %s",
882 ipadm_status2str(ipstatus));
883 ipadm_destroy_addrobj(ipaddr);
884 goto skip_ipv4_dhcp;
886 ipstatus = ipadm_set_reqhost(ipaddr, ipreqhost);
887 if (ipstatus != IPADM_SUCCESS) {
888 nlog(LOG_ERR, "populate_ip_ncu_properties: "
889 "ipadm_set_reqhost failed for v4 dhcp: %s",
890 ipadm_status2str(ipstatus));
891 ipadm_destroy_addrobj(ipaddr);
892 goto skip_ipv4_dhcp;
894 if ((*nifa = calloc(sizeof (**nifa), 1)) != NULL) {
895 (*nifa)->family = AF_INET;
896 (*nifa)->ipaddr_atype = IPADM_ADDR_DHCP;
897 (*nifa)->ipaddr = ipaddr;
898 nifa = &((*nifa)->next);
899 *nifa = NULL;
900 } else {
901 nlog(LOG_ERR, "populate_ip_ncu_properties: "
902 "couldn't allocate nwamd address for v4 dhcp: %s",
903 strerror(errno));
904 ipadm_destroy_addrobj(ipaddr);
908 skip_ipv4_dhcp:
909 /* ipv4-addr */
910 if (static_addr) {
911 if ((err = nwamd_get_ncu_string(ncuh, &ncu_prop, &addrvalue,
912 &numvalues, NWAM_NCU_PROP_IPV4_ADDR)) != NWAM_SUCCESS) {
913 nlog(LOG_ERR, "populate_ip_ncu_properties: "
914 "could not get %s value: %s",
915 NWAM_NCU_PROP_IPV4_ADDR, nwam_strerror(err));
916 } else {
917 for (i = 0; i < numvalues; i++) {
918 ipstatus = ipadm_create_addrobj(
919 IPADM_ADDR_STATIC, ncu_data->ncu_name,
920 &ipaddr);
921 if (ipstatus != IPADM_SUCCESS) {
922 nlog(LOG_ERR,
923 "populate_ip_ncu_properties: "
924 "ipadm_create_addrobj failed "
925 "for %s: %s", addrvalue[i],
926 ipadm_status2str(ipstatus));
927 continue;
929 /* ipadm_set_addr takes <addr>[/<mask>] */
930 ipstatus = ipadm_set_addr(ipaddr, addrvalue[i],
931 AF_INET);
932 if (ipstatus != IPADM_SUCCESS) {
933 nlog(LOG_ERR,
934 "populate_ip_ncu_properties: "
935 "ipadm_set_addr failed for %s: %s",
936 addrvalue[i],
937 ipadm_status2str(ipstatus));
938 ipadm_destroy_addrobj(ipaddr);
939 continue;
942 if ((*nifa = calloc(sizeof (**nifa), 1))
943 != NULL) {
944 (*nifa)->family = AF_INET;
945 (*nifa)->ipaddr_atype =
946 IPADM_ADDR_STATIC;
947 (*nifa)->ipaddr = ipaddr;
948 nifa = &((*nifa)->next);
949 } else {
950 nlog(LOG_ERR,
951 "populate_ip_ncu_properties: "
952 "couldn't allocate nwamd address "
953 "for %s: %s", addrvalue[i],
954 strerror(errno));
955 ipadm_destroy_addrobj(ipaddr);
958 *nifa = NULL;
960 nwam_value_free(ncu_prop);
964 /* get default route, if any */
965 if ((err = nwamd_get_ncu_string(ncuh, &ncu_prop, &addrvalue,
966 &numvalues, NWAM_NCU_PROP_IPV4_DEFAULT_ROUTE)) == NWAM_SUCCESS) {
967 /* Only one default route is allowed. */
968 nif->nwamd_if_ipv4_default_route.sin_family = AF_INET;
969 (void) inet_pton(AF_INET, addrvalue[0],
970 &(nif->nwamd_if_ipv4_default_route.sin_addr));
971 nif->nwamd_if_ipv4_default_route_set = B_TRUE;
972 nwam_value_free(ncu_prop);
975 skip_ipv4:
976 if (!nif->nwamd_if_ipv6)
977 goto skip_ipv6;
979 /* ipv6-addrsrc */
980 static_addr = B_FALSE;
981 if ((err = nwamd_get_ncu_uint(ncuh, &ncu_prop, &addrsrcvalue,
982 &numvalues, NWAM_NCU_PROP_IPV6_ADDRSRC)) != NWAM_SUCCESS) {
983 nlog(nif->nwamd_if_ipv6 ? LOG_ERR : LOG_DEBUG,
984 "populate_ip_ncu_properties: could not get %s value: %s",
985 NWAM_NCU_PROP_IPV6_ADDRSRC, nwam_strerror(err));
986 } else {
987 for (i = 0; i < numvalues; i++) {
988 switch (addrsrcvalue[i]) {
989 case NWAM_ADDRSRC_DHCP:
990 nif->nwamd_if_stateful_requested = B_TRUE;
991 break;
992 case NWAM_ADDRSRC_AUTOCONF:
993 nif->nwamd_if_stateless_requested = B_TRUE;
994 break;
995 case NWAM_ADDRSRC_STATIC:
996 static_addr = B_TRUE;
997 break;
998 default:
999 break;
1002 nwam_value_free(ncu_prop);
1005 * Both stateful and stateless share the same nwamd_if_address because
1006 * only one ipaddr for both of these addresses can be created.
1007 * ipadm_create_addr() adds both addresses from the same ipaddr.
1009 if (nif->nwamd_if_stateful_requested ||
1010 nif->nwamd_if_stateless_requested) {
1011 ipstatus = ipadm_create_addrobj(IPADM_ADDR_IPV6_ADDRCONF,
1012 ncu_data->ncu_name, &ipaddr);
1013 if (ipstatus != IPADM_SUCCESS) {
1014 nlog(LOG_ERR, "populate_ip_ncu_properties: "
1015 "ipadm_create_addrobj failed for v6 "
1016 "stateless/stateful: %s",
1017 ipadm_status2str(ipstatus));
1018 goto skip_ipv6_addrconf;
1020 /* create_addrobj sets both stateless and stateful to B_TRUE */
1021 if (!nif->nwamd_if_stateful_requested) {
1022 ipstatus = ipadm_set_stateful(ipaddr, B_FALSE);
1023 if (ipstatus != IPADM_SUCCESS) {
1024 nlog(LOG_ERR, "populate_ip_ncu_properties: "
1025 "ipadm_set_stateful failed for v6: %s",
1026 ipadm_status2str(ipstatus));
1027 ipadm_destroy_addrobj(ipaddr);
1028 goto skip_ipv6_addrconf;
1031 if (!nif->nwamd_if_stateless_requested) {
1032 ipstatus = ipadm_set_stateless(ipaddr, B_FALSE);
1033 if (ipstatus != IPADM_SUCCESS) {
1034 nlog(LOG_ERR, "populate_ip_ncu_properties: "
1035 "ipadm_set_stateless failed for v6: %s",
1036 ipadm_status2str(ipstatus));
1037 ipadm_destroy_addrobj(ipaddr);
1038 goto skip_ipv6_addrconf;
1041 if ((*nifa = calloc(sizeof (**nifa), 1)) != NULL) {
1042 (*nifa)->family = AF_INET6;
1043 (*nifa)->ipaddr_atype = IPADM_ADDR_IPV6_ADDRCONF;
1044 (*nifa)->ipaddr = ipaddr;
1045 nifa = &((*nifa)->next);
1046 *nifa = NULL;
1047 } else {
1048 nlog(LOG_ERR, "populate_ip_ncu_properties: "
1049 "couldn't allocate nwamd address for "
1050 "v6 stateless/stateful: %s", strerror(errno));
1051 ipadm_destroy_addrobj(ipaddr);
1055 skip_ipv6_addrconf:
1056 /* ipv6-addr */
1057 if (static_addr) {
1058 if ((err = nwamd_get_ncu_string(ncuh, &ncu_prop, &addrvalue,
1059 &numvalues, NWAM_NCU_PROP_IPV6_ADDR)) != NWAM_SUCCESS) {
1060 nlog(LOG_ERR, "populate_ip_ncu_properties: "
1061 "could not get %s value: %s",
1062 NWAM_NCU_PROP_IPV6_ADDR, nwam_strerror(err));
1063 } else {
1064 for (i = 0; i < numvalues; i++) {
1065 ipstatus = ipadm_create_addrobj(
1066 IPADM_ADDR_STATIC, ncu_data->ncu_name,
1067 &ipaddr);
1068 if (ipstatus != IPADM_SUCCESS) {
1069 nlog(LOG_ERR,
1070 "populate_ip_ncu_properties: "
1071 "ipadm_create_addrobj failed "
1072 "for %s: %s", addrvalue[i],
1073 ipadm_status2str(ipstatus));
1074 continue;
1076 /* ipadm_set_addr takes <addr>[/<mask>] */
1077 ipstatus = ipadm_set_addr(ipaddr, addrvalue[i],
1078 AF_INET6);
1079 if (ipstatus != IPADM_SUCCESS) {
1080 nlog(LOG_ERR,
1081 "populate_ip_ncu_properties: "
1082 "ipadm_set_addr failed for %s: %s",
1083 addrvalue[i],
1084 ipadm_status2str(ipstatus));
1085 ipadm_destroy_addrobj(ipaddr);
1086 continue;
1089 if ((*nifa = calloc(sizeof (**nifa), 1))
1090 != NULL) {
1091 (*nifa)->family = AF_INET6;
1092 (*nifa)->ipaddr_atype =
1093 IPADM_ADDR_STATIC;
1094 (*nifa)->ipaddr = ipaddr;
1095 nifa = &((*nifa)->next);
1096 } else {
1097 nlog(LOG_ERR,
1098 "populate_ip_ncu_properties: "
1099 "couldn't allocate nwamd address "
1100 "for %s: %s", addrvalue[i],
1101 strerror(errno));
1102 ipadm_destroy_addrobj(ipaddr);
1105 *nifa = NULL;
1107 nwam_value_free(ncu_prop);
1111 /* get default route, if any */
1112 if ((err = nwamd_get_ncu_string(ncuh, &ncu_prop, &addrvalue,
1113 &numvalues, NWAM_NCU_PROP_IPV6_DEFAULT_ROUTE)) == NWAM_SUCCESS) {
1114 /* Only one default route is allowed. */
1115 nif->nwamd_if_ipv6_default_route.sin6_family = AF_INET6;
1116 (void) inet_pton(AF_INET6, addrvalue[0],
1117 &(nif->nwamd_if_ipv6_default_route.sin6_addr));
1118 nif->nwamd_if_ipv6_default_route_set = B_TRUE;
1119 nwam_value_free(ncu_prop);
1122 skip_ipv6:
1126 static nwamd_ncu_t *
1127 nwamd_ncu_init(nwam_ncu_type_t ncu_type, const char *name)
1129 nwamd_ncu_t *rv;
1131 nlog(LOG_DEBUG, "nwamd_ncu_init(%d, %s)", ncu_type, name);
1133 if ((rv = calloc(1, sizeof (*rv))) == NULL)
1134 return (NULL);
1136 rv->ncu_type = ncu_type;
1137 rv->ncu_name = strdup(name);
1138 rv->ncu_enabled = B_FALSE;
1140 /* Initialize link/interface-specific data */
1141 if (rv->ncu_type == NWAM_NCU_TYPE_LINK) {
1142 (void) bzero(&rv->ncu_link, sizeof (nwamd_link_t));
1143 (void) dladm_name2info(dld_handle, name,
1144 &rv->ncu_link.nwamd_link_id, NULL, NULL,
1145 &rv->ncu_link.nwamd_link_media);
1146 (void) pthread_mutex_init(
1147 &rv->ncu_link.nwamd_link_wifi_mutex, NULL);
1148 rv->ncu_link.nwamd_link_wifi_priority = MAXINT;
1149 } else {
1150 (void) bzero(&rv->ncu_if, sizeof (nwamd_if_t));
1153 return (rv);
1156 void
1157 nwamd_ncu_free(nwamd_ncu_t *ncu)
1159 if (ncu != NULL) {
1160 assert(ncu->ncu_type == NWAM_NCU_TYPE_LINK ||
1161 ncu->ncu_type == NWAM_NCU_TYPE_INTERFACE);
1162 if (ncu->ncu_type == NWAM_NCU_TYPE_LINK) {
1163 struct nwamd_link *l = &ncu->ncu_link;
1164 int i;
1166 free(l->nwamd_link_wifi_key);
1167 free(l->nwamd_link_mac_addr);
1168 for (i = 0; i < l->nwamd_link_num_autopush; i++)
1169 free(l->nwamd_link_autopush[i]);
1170 } else if (ncu->ncu_type == NWAM_NCU_TYPE_INTERFACE) {
1171 struct nwamd_if_address *nifa;
1173 nifa = ncu->ncu_if.nwamd_if_list;
1174 while (nifa != NULL) {
1175 struct nwamd_if_address *n;
1177 n = nifa;
1178 nifa = nifa->next;
1179 ipadm_destroy_addrobj(n->ipaddr);
1180 free(n);
1183 free(ncu->ncu_name);
1184 free(ncu);
1188 static int
1189 nwamd_ncu_display(nwamd_object_t ncu_obj, void *data)
1191 nwamd_ncu_t *ncu = (nwamd_ncu_t *)ncu_obj->nwamd_object_data;
1192 data = data;
1193 nlog(LOG_DEBUG, "NCU (%p) %s state %s, %s",
1194 (void *)ncu, ncu_obj->nwamd_object_name,
1195 nwam_state_to_string(ncu_obj->nwamd_object_state),
1196 nwam_aux_state_to_string(ncu_obj->nwamd_object_aux_state));
1197 return (0);
1200 void
1201 nwamd_log_ncus(void)
1203 nlog(LOG_DEBUG, "NCP %s", active_ncp);
1204 (void) nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU, nwamd_ncu_display,
1205 NULL);
1209 nwamd_ncu_action(const char *ncu, const char *parent, nwam_action_t action)
1211 nwamd_event_t ncu_event = nwamd_event_init_object_action
1212 (NWAM_OBJECT_TYPE_NCU, ncu, parent, action);
1213 if (ncu_event == NULL)
1214 return (1);
1215 nwamd_event_enqueue(ncu_event);
1216 return (0);
1219 static void
1220 add_phys_ncu_to_ncp(nwam_ncp_handle_t ncph, const char *name)
1222 dladm_status_t dlrtn;
1223 uint32_t media;
1224 boolean_t is_wireless;
1225 nwam_error_t err;
1226 nwam_ncu_handle_t ncuh;
1227 uint64_t uintval;
1229 if ((dlrtn = dladm_name2info(dld_handle, name, NULL, NULL, NULL,
1230 &media)) != DLADM_STATUS_OK) {
1231 char errmsg[DLADM_STRSIZE];
1232 nlog(LOG_ERR, "failed to get media type for %s: %s", name,
1233 dladm_status2str(dlrtn, errmsg));
1234 return;
1236 is_wireless = (media == DL_WIFI);
1238 if ((err = nwam_ncu_create(ncph, name, NWAM_NCU_TYPE_LINK,
1239 NWAM_NCU_CLASS_PHYS, &ncuh)) != NWAM_SUCCESS) {
1240 nlog(LOG_ERR, "failed to create link ncu for %s: %s", name,
1241 nwam_strerror(err));
1242 if (err == NWAM_ENTITY_READ_ONLY) {
1243 nwamd_event_t retry_event;
1246 * Root filesystem may be read-only, retry in
1247 * a few seconds.
1249 nlog(LOG_DEBUG, "Retrying addition of phys ncu for %s",
1250 name);
1251 retry_event = nwamd_event_init_link_action(name,
1252 NWAM_ACTION_ADD);
1253 if (retry_event != NULL) {
1254 nwamd_event_enqueue_timed(retry_event,
1255 NWAMD_READONLY_RETRY_INTERVAL);
1258 return;
1261 uintval = NWAM_ACTIVATION_MODE_PRIORITIZED;
1262 if ((err = nwamd_set_ncu_uint(ncuh, &uintval, 1,
1263 NWAM_NCU_PROP_ACTIVATION_MODE)) != NWAM_SUCCESS) {
1264 goto finish;
1267 uintval = is_wireless ? 1 : 0;
1268 if ((err = nwamd_set_ncu_uint(ncuh, &uintval, 1,
1269 NWAM_NCU_PROP_PRIORITY_GROUP)) != NWAM_SUCCESS) {
1270 goto finish;
1273 uintval = is_wireless ? NWAM_PRIORITY_MODE_EXCLUSIVE :
1274 NWAM_PRIORITY_MODE_SHARED;
1275 if ((err = nwamd_set_ncu_uint(ncuh, &uintval, 1,
1276 NWAM_NCU_PROP_PRIORITY_MODE)) != NWAM_SUCCESS) {
1277 goto finish;
1280 err = nwam_ncu_commit(ncuh, 0);
1282 finish:
1283 nwam_ncu_free(ncuh);
1284 if (err != NWAM_SUCCESS) {
1285 nlog(LOG_ERR,
1286 "failed to create automatic link ncu for %s: %s",
1287 name, nwam_strerror(err));
1291 static void
1292 add_ip_ncu_to_ncp(nwam_ncp_handle_t ncph, const char *name)
1294 nwam_error_t err;
1295 nwam_ncu_handle_t ncuh;
1297 if ((err = nwam_ncu_create(ncph, name, NWAM_NCU_TYPE_INTERFACE,
1298 NWAM_NCU_CLASS_IP, &ncuh)) != NWAM_SUCCESS) {
1299 nlog(LOG_ERR, "failed to create ip ncu for %s: %s", name,
1300 nwam_strerror(err));
1302 * Root filesystem may be read-only, but no need to
1303 * retry here since add_phys_ncu_to_ncp() enqueues
1304 * a retry event which will lead to add_ip_ncu_to_ncp()
1305 * being called.
1307 return;
1310 /* IP NCU has the default values, so nothing else to do */
1311 err = nwam_ncu_commit(ncuh, 0);
1313 finish:
1314 nwam_ncu_free(ncuh);
1315 if (err != NWAM_SUCCESS) {
1316 nlog(LOG_ERR,
1317 "failed to create ip ncu for %s: %s", name,
1318 nwam_strerror(err));
1322 static void
1323 remove_ncu_from_ncp(nwam_ncp_handle_t ncph, const char *name,
1324 nwam_ncu_type_t type)
1326 nwam_error_t err;
1327 nwam_ncu_handle_t ncuh;
1329 if ((err = nwam_ncu_read(ncph, name, type, 0, &ncuh)) != NWAM_SUCCESS) {
1330 nlog(LOG_ERR, "failed to read automatic ncu %s: %s", name,
1331 nwam_strerror(err));
1332 return;
1335 err = nwam_ncu_destroy(ncuh, 0);
1336 if (err != NWAM_SUCCESS) {
1337 nlog(LOG_ERR, "failed to delete automatic ncu %s: %s", name,
1338 nwam_strerror(err));
1343 * Device represented by NCU has been added or removed for the active
1344 * User NCP. If an associated NCU of the given type is found, transition it
1345 * to the appropriate state.
1347 void
1348 ncu_action_change_state(nwam_action_t action, nwam_ncu_type_t type,
1349 const char *name)
1351 nwamd_object_t ncu_obj = NULL;
1352 nwamd_ncu_t *ncu;
1354 if ((ncu_obj = nwamd_ncu_object_find(type, name)) == NULL)
1355 return;
1357 ncu = ncu_obj->nwamd_object_data;
1360 * If device has been added, transition from uninitialized to offline.
1361 * If device has been removed, transition to uninitialized (via online*
1362 * if the NCU is currently enabled in order to tear down config).
1364 if (action == NWAM_ACTION_ADD) {
1365 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
1366 ncu_obj->nwamd_object_name,
1367 NWAM_STATE_OFFLINE, NWAM_AUX_STATE_CONDITIONS_NOT_MET);
1368 } else {
1369 if (ncu->ncu_enabled) {
1370 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
1371 ncu_obj->nwamd_object_name,
1372 NWAM_STATE_ONLINE_TO_OFFLINE,
1373 NWAM_AUX_STATE_NOT_FOUND);
1374 } else {
1375 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
1376 ncu_obj->nwamd_object_name,
1377 NWAM_STATE_UNINITIALIZED,
1378 NWAM_AUX_STATE_NOT_FOUND);
1381 nwamd_object_release(ncu_obj);
1385 * Called with hotplug sysevent or when nwam is started and walking the
1386 * physical interfaces. Add/remove both link and interface NCUs from the
1387 * Automatic NCP. Assumes that both link and interface NCUs don't exist.
1389 void
1390 nwamd_ncu_handle_link_action_event(nwamd_event_t event)
1392 nwam_ncp_handle_t ncph;
1393 nwam_ncu_type_t type;
1394 nwam_action_t action =
1395 event->event_msg->nwe_data.nwe_link_action.nwe_action;
1396 nwam_error_t err;
1397 char *name;
1398 boolean_t automatic_ncp_active = B_FALSE;
1400 if (action != NWAM_ACTION_ADD && action != NWAM_ACTION_REMOVE) {
1401 nlog(LOG_ERR, "nwamd_ncu_handle_link_action_event: "
1402 "invalid link action %s", nwam_action_to_string(action));
1403 nwamd_event_do_not_send(event);
1404 return;
1407 nlog(LOG_DEBUG, "nwamd_ncu_handle_link_action_event: "
1408 "link action '%s' event on %s", nwam_action_to_string(action),
1409 event->event_object[0] == 0 ? "n/a" : event->event_object);
1411 if ((err = nwam_ncu_typed_name_to_name(event->event_object, &type,
1412 &name)) != NWAM_SUCCESS) {
1413 nlog(LOG_ERR, "nwamd_ncu_handle_link_action_event: "
1414 "translation from typedname error: %s", nwam_strerror(err));
1415 nwamd_event_do_not_send(event);
1416 return;
1419 (void) pthread_mutex_lock(&active_ncp_mutex);
1420 if (strcmp(active_ncp, NWAM_NCP_NAME_AUTOMATIC) == 0 &&
1421 active_ncph != NULL) {
1422 automatic_ncp_active = B_TRUE;
1424 (void) pthread_mutex_unlock(&active_ncp_mutex);
1427 * We could use active_ncph for cases where the Automatic NCP is active,
1428 * but that would involve holding the active_ncp_mutex for too long.
1430 if ((err = nwam_ncp_read(NWAM_NCP_NAME_AUTOMATIC, 0, &ncph))
1431 == NWAM_ENTITY_NOT_FOUND) {
1432 /* Automatic NCP doesn't exist, create it */
1433 err = nwam_ncp_create(NWAM_NCP_NAME_AUTOMATIC, 0, &ncph);
1435 if (err != NWAM_SUCCESS)
1436 goto fail;
1438 /* add or remove NCUs from Automatic NCP */
1439 if (action == NWAM_ACTION_ADD) {
1440 add_phys_ncu_to_ncp(ncph, name);
1441 add_ip_ncu_to_ncp(ncph, name);
1442 } else {
1444 * Order is important here, remove IP NCU first to prevent
1445 * propogation of down event from link to IP. No need to
1446 * create REFRESH or DESTROY events. They are generated by
1447 * nwam_ncu_commit() and nwam_ncu_destroy().
1449 remove_ncu_from_ncp(ncph, name, NWAM_NCU_TYPE_INTERFACE);
1450 remove_ncu_from_ncp(ncph, name, NWAM_NCU_TYPE_LINK);
1452 nwam_ncp_free(ncph);
1455 * If the Automatic NCP is not active, and the associated NCUs
1456 * exist, they must be moved into the appropriate states given the
1457 * action that has occurred.
1459 if (!automatic_ncp_active) {
1460 ncu_action_change_state(action, NWAM_NCU_TYPE_INTERFACE, name);
1461 ncu_action_change_state(action, NWAM_NCU_TYPE_LINK, name);
1464 /* Need NCU check to evaluate state in light of added/removed NCUs */
1465 if (!nwamd_event_enqueued(NWAM_EVENT_TYPE_NCU_CHECK,
1466 NWAM_OBJECT_TYPE_NCP, NULL)) {
1467 nwamd_create_ncu_check_event(NEXT_FEW_SECONDS);
1470 fail:
1471 free(name);
1472 if (err != NWAM_SUCCESS) {
1473 nwamd_event_t retry_event = nwamd_event_init_link_action(name,
1474 action);
1475 if (retry_event == NULL) {
1476 nlog(LOG_ERR, "nwamd_ncu_handle_link_action_event: "
1477 "could not create retry event to read/create "
1478 "%s NCP", NWAM_NCP_NAME_AUTOMATIC);
1479 return;
1482 nlog(LOG_ERR, "nwamd_ncu_handle_link_action_event: "
1483 "could not read/create %s NCP, retrying in %d seconds",
1484 NWAM_NCP_NAME_AUTOMATIC, NWAMD_READONLY_RETRY_INTERVAL);
1485 nwamd_event_enqueue_timed(retry_event,
1486 NWAMD_READONLY_RETRY_INTERVAL);
1491 * Figure out if this link is part of an aggregation. This is fairly
1492 * inefficient since we generate this list for every query and search
1493 * linearly. A better way would be to generate the list of links in an
1494 * aggregation once and then check each link against it.
1496 struct link_aggr_search_data {
1497 datalink_id_t linkid;
1498 boolean_t under;
1501 static int
1502 ncu_aggr_search(const char *name, void *data)
1504 struct link_aggr_search_data *lasd = data;
1505 dladm_aggr_grp_attr_t ginfo;
1506 datalink_id_t linkid;
1507 int i;
1509 if (dladm_name2info(dld_handle, name, &linkid, NULL, NULL, NULL) !=
1510 DLADM_STATUS_OK)
1511 return (DLADM_WALK_CONTINUE);
1512 if (dladm_aggr_info(dld_handle, linkid, &ginfo, DLADM_OPT_ACTIVE)
1513 != DLADM_STATUS_OK || ginfo.lg_nports == 0)
1514 return (DLADM_WALK_CONTINUE);
1516 for (i = 0; i < ginfo.lg_nports; i++) {
1517 if (lasd->linkid == ginfo.lg_ports[i].lp_linkid) {
1518 lasd->under = B_TRUE;
1519 return (DLADM_WALK_TERMINATE);
1522 free(ginfo.lg_ports);
1523 return (DLADM_WALK_CONTINUE);
1526 static boolean_t
1527 nwamd_link_belongs_to_an_aggr(const char *name)
1529 struct link_aggr_search_data lasd;
1531 if (dladm_name2info(dld_handle, name, &lasd.linkid, NULL, NULL, NULL)
1532 != DLADM_STATUS_OK)
1533 return (B_FALSE);
1534 lasd.under = B_FALSE;
1535 (void) dladm_walk(ncu_aggr_search, dld_handle, &lasd,
1536 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
1537 return (lasd.under);
1541 * If NCU doesn't exist for interface with given name, enqueue a ADD
1542 * LINK_ACTION event.
1544 static int
1545 ncu_create_link_action_event(const char *name, void *data)
1547 nwam_ncp_handle_t ncph = data;
1548 nwam_ncu_handle_t ncuh;
1549 nwamd_event_t link_event;
1551 /* Do not generate an event if this is a VirtualBox interface. */
1552 if (strncmp(name, VBOX_IFACE_PREFIX, strlen(VBOX_IFACE_PREFIX)) == 0)
1553 return (DLADM_WALK_CONTINUE);
1555 /* Do not generate an event if this link belongs to another zone. */
1556 if (!nwamd_link_belongs_to_this_zone(name))
1557 return (DLADM_WALK_CONTINUE);
1559 /* Do not generate an event if this link belongs to an aggregation. */
1560 if (nwamd_link_belongs_to_an_aggr(name)) {
1561 return (DLADM_WALK_CONTINUE);
1564 /* Don't create an event if the NCU already exists. */
1565 if (ncph != NULL && nwam_ncu_read(ncph, name, NWAM_NCU_TYPE_LINK, 0,
1566 &ncuh) == NWAM_SUCCESS) {
1567 nwam_ncu_free(ncuh);
1568 return (DLADM_WALK_CONTINUE);
1571 nlog(LOG_DEBUG, "ncu_create_link_action_event: adding ncus for %s",
1572 name);
1574 link_event = nwamd_event_init_link_action(name, NWAM_ACTION_ADD);
1575 if (link_event != NULL)
1576 nwamd_event_enqueue(link_event);
1578 return (DLADM_WALK_CONTINUE);
1582 * Check if interface exists for this NCU. If not, enqueue a REMOVE
1583 * LINK_ACTION event.
1585 /* ARGSUSED */
1586 static int
1587 nwamd_destroy_ncu(nwam_ncu_handle_t ncuh, void *data)
1589 char *name;
1590 uint32_t flags;
1591 nwamd_event_t link_event;
1593 if (nwam_ncu_get_name(ncuh, &name) != NWAM_SUCCESS) {
1594 nlog(LOG_ERR, "nwamd_destroy_ncu: could not get NCU name");
1595 return (0);
1598 /* Interfaces that exist return DLADM_OPT_ACTIVE flag */
1599 if ((dladm_name2info(dld_handle, name, NULL, &flags, NULL, NULL)
1600 == DLADM_STATUS_OK && (flags & DLADM_OPT_ACTIVE)) &&
1601 !nwamd_link_belongs_to_an_aggr(name)) {
1602 free(name);
1603 return (0);
1606 nlog(LOG_DEBUG, "nwamd_destroy_ncu: destroying ncus for %s", name);
1608 link_event = nwamd_event_init_link_action(name, NWAM_ACTION_REMOVE);
1609 if (link_event != NULL)
1610 nwamd_event_enqueue(link_event);
1611 free(name);
1612 return (0);
1616 * Called when nwamd is starting up.
1618 * Walk all NCUs and destroy any NCU from the Automatic NCP without an
1619 * underlying interface (assumption here is that the interface was removed
1620 * when nwam was disabled).
1622 * Walk the physical interfaces and create ADD LINK_ACTION event, which
1623 * will create appropriate interface and link NCUs in the Automatic NCP.
1625 void
1626 nwamd_walk_physical_configuration(void)
1628 nwam_ncp_handle_t ncph;
1629 datalink_class_t dlclass = DATALINK_CLASS_PHYS;
1630 zoneid_t zoneid = getzoneid();
1632 (void) pthread_mutex_lock(&active_ncp_mutex);
1633 if (strcmp(active_ncp, NWAM_NCP_NAME_AUTOMATIC) == 0 &&
1634 active_ncph != NULL) {
1635 ncph = active_ncph;
1636 } else {
1637 if (nwam_ncp_read(NWAM_NCP_NAME_AUTOMATIC, 0, &ncph)
1638 != NWAM_SUCCESS) {
1639 ncph = NULL;
1643 /* destroy NCUs for interfaces that don't exist */
1644 if (ncph != NULL) {
1645 (void) nwam_ncp_walk_ncus(ncph, nwamd_destroy_ncu, NULL,
1646 NWAM_FLAG_NCU_TYPE_LINK, NULL);
1649 /* In non-global zones NWAM can support VNICs */
1650 if (zoneid != GLOBAL_ZONEID)
1651 dlclass |= DATALINK_CLASS_VNIC;
1653 /* create NCUs for interfaces without NCUs */
1654 (void) dladm_walk(ncu_create_link_action_event, dld_handle, ncph,
1655 dlclass, DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
1657 if (strcmp(active_ncp, NWAM_NCP_NAME_AUTOMATIC) != 0 ||
1658 active_ncph == NULL) {
1659 nwam_ncp_free(ncph);
1661 (void) pthread_mutex_unlock(&active_ncp_mutex);
1665 * Handle NCU initialization/refresh event.
1667 void
1668 nwamd_ncu_handle_init_event(nwamd_event_t event)
1670 nwamd_object_t object = NULL;
1671 nwam_ncu_handle_t ncuh;
1672 nwamd_ncu_t *ncu = NULL;
1673 nwam_error_t err;
1674 nwam_ncu_type_t type;
1675 char *name;
1676 uint32_t flags;
1677 boolean_t new = B_TRUE;
1679 nlog(LOG_DEBUG, "nwamd_ncu_handle_init_event(%s)",
1680 event->event_object);
1682 /* Get base linkname rather than interface:linkname or link:linkname */
1683 err = nwam_ncu_typed_name_to_name(event->event_object,
1684 &type, &name);
1685 if (err != NWAM_SUCCESS) {
1686 nlog(LOG_ERR, "nwamd_ncu_handle_init_event: "
1687 "nwam_ncu_typed_name_to_name returned %s",
1688 nwam_strerror(err));
1689 nwamd_event_do_not_send(event);
1690 return;
1693 (void) pthread_mutex_lock(&active_ncp_mutex);
1694 if (active_ncph == NULL) {
1695 nlog(LOG_DEBUG,
1696 "nwamd_ncu_handle_init_event: active NCP handle NULL");
1697 nwamd_event_do_not_send(event);
1698 free(name);
1699 (void) pthread_mutex_unlock(&active_ncp_mutex);
1700 return;
1702 err = nwam_ncu_read(active_ncph, event->event_object,
1703 type, 0, &ncuh);
1704 (void) pthread_mutex_unlock(&active_ncp_mutex);
1705 if (err != NWAM_SUCCESS) {
1706 nlog(LOG_ERR, "nwamd_ncu_handle_init_event: "
1707 "could not read object '%s': %s",
1708 event->event_object, nwam_strerror(err));
1709 free(name);
1710 nwamd_event_do_not_send(event);
1711 return;
1714 if ((object = nwamd_object_find(NWAM_OBJECT_TYPE_NCU,
1715 event->event_object)) != NULL)
1716 new = B_FALSE;
1719 * For new NCUs, or interface NCUs, we (re)initialize data from scratch.
1720 * For link NCUs, we want to retain object data.
1722 switch (type) {
1723 case NWAM_NCU_TYPE_LINK:
1724 if (new) {
1725 ncu = nwamd_ncu_init(type, name);
1726 } else {
1727 ncu = object->nwamd_object_data;
1728 nwam_ncu_free(object->nwamd_object_handle);
1730 populate_common_ncu_properties(ncuh, ncu);
1731 populate_link_ncu_properties(ncuh, ncu);
1732 break;
1733 case NWAM_NCU_TYPE_INTERFACE:
1734 if (!new) {
1735 nwam_ncu_free(object->nwamd_object_handle);
1736 nwamd_ncu_free(object->nwamd_object_data);
1738 ncu = nwamd_ncu_init(type, name);
1739 populate_common_ncu_properties(ncuh, ncu);
1740 populate_ip_ncu_properties(ncuh, ncu);
1741 break;
1742 default:
1743 nlog(LOG_ERR, "unknown ncu type %d", type);
1744 free(name);
1745 nwam_ncu_free(ncuh);
1746 nwamd_event_do_not_send(event);
1747 nwamd_object_release(object);
1748 return;
1751 if (new) {
1752 nlog(LOG_DEBUG, "nwamd_ncu_handle_init_event: didn't find "
1753 "ncu so create it %s", name);
1754 object = nwamd_object_init(NWAM_OBJECT_TYPE_NCU,
1755 event->event_object, ncuh, ncu);
1756 } else {
1757 nlog(LOG_DEBUG, "nwamd_ncu_handle_init_event: refreshing "
1758 "ncu %s", name);
1759 object->nwamd_object_data = ncu;
1760 object->nwamd_object_handle = ncuh;
1764 * If the physical link for this NCU doesn't exist in the system,
1765 * the state should be UNINITIALIZED/NOT_FOUND. Interfaces that
1766 * exist return DLADM_OPT_ACTIVE flag.
1768 if (dladm_name2info(dld_handle, name, NULL, &flags, NULL, NULL)
1769 != DLADM_STATUS_OK || !(flags & DLADM_OPT_ACTIVE)) {
1770 nlog(LOG_DEBUG, "nwam_ncu_handle_init_event: "
1771 "interface for NCU %s doesn't exist",
1772 event->event_object);
1773 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
1774 object->nwamd_object_name, NWAM_STATE_UNINITIALIZED,
1775 NWAM_AUX_STATE_NOT_FOUND);
1776 free(name);
1777 nwamd_object_release(object);
1778 return;
1782 * If NCU is being initialized (rather than refreshed), the
1783 * object_state is INITIALIZED (from nwamd_object_init()).
1785 if (object->nwamd_object_state == NWAM_STATE_INITIALIZED) {
1787 * If the NCU is disabled, initial state should be DISABLED.
1789 * Otherwise, the initial state will be
1790 * OFFLINE/CONDITIONS_NOT_MET, and the link selection
1791 * algorithm will do the rest.
1793 if (!ncu->ncu_enabled) {
1794 object->nwamd_object_state = NWAM_STATE_DISABLED;
1795 object->nwamd_object_aux_state =
1796 NWAM_AUX_STATE_MANUAL_DISABLE;
1797 } else {
1798 object->nwamd_object_state = NWAM_STATE_OFFLINE;
1799 object->nwamd_object_aux_state =
1800 NWAM_AUX_STATE_CONDITIONS_NOT_MET;
1802 } else {
1803 nwamd_link_t *link = &ncu->ncu_link;
1806 * Refresh NCU. Deal with disabled cases first, moving NCUs
1807 * that are not disabled - but have the enabled value set - to
1808 * the disabled state. Then handle cases where the NCU was
1809 * disabled but is no longer. Finally, deal with refresh of
1810 * link and interface NCUs, as these are handled differently.
1812 if (!ncu->ncu_enabled) {
1813 if (object->nwamd_object_state != NWAM_STATE_DISABLED) {
1814 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
1815 object->nwamd_object_name,
1816 NWAM_STATE_ONLINE_TO_OFFLINE,
1817 NWAM_AUX_STATE_MANUAL_DISABLE);
1819 goto done;
1820 } else {
1821 if (object->nwamd_object_state == NWAM_STATE_DISABLED) {
1822 int64_t c;
1825 * Try to activate the NCU if manual or
1826 * prioritized (when priority <= current).
1828 (void) pthread_mutex_lock(&active_ncp_mutex);
1829 c = current_ncu_priority_group;
1830 (void) pthread_mutex_unlock(&active_ncp_mutex);
1831 if (link->nwamd_link_activation_mode ==
1832 NWAM_ACTIVATION_MODE_MANUAL ||
1833 (link->nwamd_link_activation_mode ==
1834 NWAM_ACTIVATION_MODE_PRIORITIZED &&
1835 link->nwamd_link_priority_mode <= c)) {
1836 nwamd_object_set_state
1837 (NWAM_OBJECT_TYPE_NCU,
1838 object->nwamd_object_name,
1839 NWAM_STATE_OFFLINE_TO_ONLINE,
1840 NWAM_AUX_STATE_INITIALIZED);
1841 } else {
1842 nwamd_object_set_state
1843 (NWAM_OBJECT_TYPE_NCU,
1844 object->nwamd_object_name,
1845 NWAM_STATE_OFFLINE_TO_ONLINE,
1846 NWAM_AUX_STATE_INITIALIZED);
1848 goto done;
1852 switch (type) {
1853 case NWAM_NCU_TYPE_LINK:
1854 if (ncu->ncu_link.nwamd_link_media == DL_WIFI) {
1856 * Do rescan. If the current state and the
1857 * active priority-group do not allow wireless
1858 * network selection, then it won't happen.
1860 (void) nwamd_wlan_scan(ncu->ncu_name);
1862 break;
1863 case NWAM_NCU_TYPE_INTERFACE:
1865 * If interface NCU is offline*, online or in
1866 * maintenance, mark it down (from there, it will be
1867 * reinitialized to reapply addresses).
1869 if (object->nwamd_object_state != NWAM_STATE_OFFLINE) {
1870 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
1871 object->nwamd_object_name,
1872 NWAM_STATE_ONLINE_TO_OFFLINE,
1873 NWAM_AUX_STATE_DOWN);
1874 } else {
1875 object->nwamd_object_state = NWAM_STATE_OFFLINE;
1876 object->nwamd_object_aux_state =
1877 NWAM_AUX_STATE_CONDITIONS_NOT_MET;
1879 break;
1883 done:
1884 if (type == NWAM_NCU_TYPE_LINK &&
1885 !nwamd_event_enqueued(NWAM_EVENT_TYPE_NCU_CHECK,
1886 NWAM_OBJECT_TYPE_NCP, NULL)) {
1887 nwamd_create_ncu_check_event(NEXT_FEW_SECONDS);
1889 free(name);
1890 nwamd_object_release(object);
1893 void
1894 nwamd_ncu_handle_fini_event(nwamd_event_t event)
1896 nwamd_object_t object;
1897 nwamd_event_t state_event;
1899 nlog(LOG_DEBUG, "nwamd_ncu_handle_fini_event(%s)",
1900 event->event_object);
1903 * Simulate a state event so that the state machine can correctly
1904 * disable the NCU. Then free up allocated objects.
1906 state_event = nwamd_event_init_object_state(NWAM_OBJECT_TYPE_NCU,
1907 event->event_object, NWAM_STATE_ONLINE_TO_OFFLINE,
1908 NWAM_AUX_STATE_UNINITIALIZED);
1909 if (state_event == NULL) {
1910 nwamd_event_do_not_send(event);
1911 return;
1913 nwamd_ncu_handle_state_event(state_event);
1914 nwamd_event_fini(state_event);
1916 if ((object = nwamd_object_find(NWAM_OBJECT_TYPE_NCU,
1917 event->event_object)) == NULL) {
1918 nlog(LOG_INFO, "nwamd_ncu_handle_fini_event: "
1919 "ncu %s not found", event->event_object);
1920 nwamd_event_do_not_send(event);
1921 return;
1923 nwamd_object_release_and_destroy(object);
1926 void
1927 nwamd_ncu_handle_action_event(nwamd_event_t event)
1929 nwamd_object_t object;
1931 (void) pthread_mutex_lock(&active_ncp_mutex);
1932 if (strcmp(event->event_msg->nwe_data.nwe_object_action.nwe_parent,
1933 active_ncp) != 0) {
1934 nlog(LOG_DEBUG, "nwamd_ncu_handle_action_event: action for "
1935 "inactive NCP %s, nothing to do",
1936 event->event_msg->nwe_data.nwe_object_action.nwe_parent);
1937 (void) pthread_mutex_unlock(&active_ncp_mutex);
1938 return;
1940 (void) pthread_mutex_unlock(&active_ncp_mutex);
1942 switch (event->event_msg->nwe_data.nwe_object_action.nwe_action) {
1943 case NWAM_ACTION_ENABLE:
1944 object = nwamd_object_find(NWAM_OBJECT_TYPE_NCU,
1945 event->event_object);
1946 if (object == NULL) {
1947 nlog(LOG_ERR, "nwamd_ncu_handle_action_event: "
1948 "could not find ncu %s", event->event_object);
1949 nwamd_event_do_not_send(event);
1950 return;
1952 if (object->nwamd_object_state == NWAM_STATE_ONLINE) {
1953 nlog(LOG_DEBUG, "nwamd_ncu_handle_action_event: "
1954 "ncu %s already online, nothing to do",
1955 event->event_object);
1956 nwamd_object_release(object);
1957 return;
1959 nwamd_object_release(object);
1961 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
1962 event->event_object, NWAM_STATE_OFFLINE_TO_ONLINE,
1963 NWAM_AUX_STATE_INITIALIZED);
1964 break;
1965 case NWAM_ACTION_DISABLE:
1966 object = nwamd_object_find(NWAM_OBJECT_TYPE_NCU,
1967 event->event_object);
1968 if (object == NULL) {
1969 nlog(LOG_ERR, "nwamd_ncu_handle_action_event: "
1970 "could not find ncu %s", event->event_object);
1971 nwamd_event_do_not_send(event);
1972 return;
1974 if (object->nwamd_object_state == NWAM_STATE_DISABLED) {
1975 nlog(LOG_DEBUG, "nwamd_ncu_handle_action_event: "
1976 "ncu %s already disabled, nothing to do",
1977 event->event_object);
1978 nwamd_object_release(object);
1979 return;
1981 nwamd_object_release(object);
1983 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
1984 event->event_object, NWAM_STATE_ONLINE_TO_OFFLINE,
1985 NWAM_AUX_STATE_MANUAL_DISABLE);
1986 break;
1987 case NWAM_ACTION_ADD:
1988 case NWAM_ACTION_REFRESH:
1989 nwamd_ncu_handle_init_event(event);
1990 break;
1991 case NWAM_ACTION_DESTROY:
1992 nwamd_ncu_handle_fini_event(event);
1993 break;
1994 default:
1995 nlog(LOG_INFO, "nwam_ncu_handle_action_event: "
1996 "unexpected action");
1997 nwamd_event_do_not_send(event);
1998 break;
2002 void
2003 nwamd_ncu_handle_state_event(nwamd_event_t event)
2005 nwamd_object_t object;
2006 nwam_state_t old_state, new_state;
2007 nwam_aux_state_t new_aux_state;
2008 nwamd_ncu_t *ncu;
2009 boolean_t is_link, enabled, prioritized = B_FALSE;
2010 char linkname[NWAM_MAX_NAME_LEN];
2011 nwam_event_t m = event->event_msg;
2013 if ((object = nwamd_object_find(NWAM_OBJECT_TYPE_NCU,
2014 event->event_object)) == NULL) {
2015 nlog(LOG_INFO, "nwamd_ncu_handle_state_event %lld: "
2016 "state event for nonexistent NCU %s", event->event_id,
2017 event->event_object);
2018 nwamd_event_do_not_send(event);
2019 return;
2021 ncu = object->nwamd_object_data;
2022 old_state = object->nwamd_object_state;
2023 new_state = event->event_msg->nwe_data.nwe_object_state.nwe_state;
2024 new_aux_state =
2025 event->event_msg->nwe_data.nwe_object_state.nwe_aux_state;
2028 * For NCU state changes, we need to supply the parent NCP name also,
2029 * regardless of whether the event is handled or not. It is best to
2030 * fill this in here as we have the object lock - when we create
2031 * object state events we sometimes do not have the object lock, but
2032 * at this point in consuming the events (and prior to the associated
2033 * event message being sent out) we do.
2035 (void) strlcpy(m->nwe_data.nwe_object_state.nwe_parent, ncu->ncu_parent,
2036 sizeof (m->nwe_data.nwe_object_state.nwe_parent));
2039 * If we receive a state change event moving this NCU to
2040 * DHCP_TIMED_OUT or UP state but this NCU is already ONLINE, then
2041 * ignore this state change event.
2043 if ((new_aux_state == NWAM_AUX_STATE_IF_DHCP_TIMED_OUT ||
2044 new_aux_state == NWAM_AUX_STATE_UP) &&
2045 object->nwamd_object_state == NWAM_STATE_ONLINE) {
2046 nlog(LOG_INFO, "nwamd_ncu_handle_state_event: "
2047 "NCU %s already online, not going to '%s' state",
2048 object->nwamd_object_name,
2049 nwam_aux_state_to_string(new_aux_state));
2050 nwamd_event_do_not_send(event);
2051 nwamd_object_release(object);
2052 return;
2055 if (new_state == object->nwamd_object_state &&
2056 new_aux_state == object->nwamd_object_aux_state) {
2057 nlog(LOG_DEBUG, "nwamd_ncu_handle_state_event: "
2058 "NCU %s already in state (%s, %s)",
2059 object->nwamd_object_name, nwam_state_to_string(new_state),
2060 nwam_aux_state_to_string(new_aux_state));
2061 nwamd_object_release(object);
2062 return;
2065 if (old_state == NWAM_STATE_MAINTENANCE &&
2066 (new_state == NWAM_STATE_ONLINE ||
2067 (new_state == NWAM_STATE_OFFLINE_TO_ONLINE &&
2068 new_aux_state != NWAM_AUX_STATE_INITIALIZED))) {
2069 nlog(LOG_DEBUG, "nwamd_ncu_handle_state_event: "
2070 "NCU %s cannot transition from state %s to state (%s, %s)",
2071 object->nwamd_object_name, nwam_state_to_string(old_state),
2072 nwam_state_to_string(new_state),
2073 nwam_aux_state_to_string(new_aux_state));
2074 nwamd_event_do_not_send(event);
2075 nwamd_object_release(object);
2076 return;
2079 object->nwamd_object_state = new_state;
2080 object->nwamd_object_aux_state = new_aux_state;
2082 nlog(LOG_DEBUG, "nwamd_ncu_handle_state_event: changing state for NCU "
2083 "%s to (%s, %s)", object->nwamd_object_name,
2084 nwam_state_to_string(object->nwamd_object_state),
2085 nwam_aux_state_to_string(object->nwamd_object_aux_state));
2087 is_link = (ncu->ncu_type == NWAM_NCU_TYPE_LINK);
2088 if (is_link)
2089 (void) strlcpy(linkname, ncu->ncu_name, sizeof (linkname));
2090 prioritized = (ncu->ncu_type == NWAM_NCU_TYPE_LINK &&
2091 ncu->ncu_link.nwamd_link_activation_mode ==
2092 NWAM_ACTIVATION_MODE_PRIORITIZED);
2093 enabled = ncu->ncu_enabled;
2095 nwamd_object_release(object);
2098 * State machine for NCUs
2100 switch (new_state) {
2101 case NWAM_STATE_OFFLINE_TO_ONLINE:
2102 if (enabled) {
2103 nwamd_ncu_state_machine(event->event_object);
2104 } else {
2105 nlog(LOG_DEBUG, "nwamd_ncu_handle_state_event: "
2106 "cannot move disabled NCU %s online",
2107 event->event_object);
2108 nwamd_event_do_not_send(event);
2110 break;
2112 case NWAM_STATE_ONLINE_TO_OFFLINE:
2113 nwamd_ncu_state_machine(event->event_object);
2114 break;
2116 case NWAM_STATE_ONLINE:
2118 * We usually don't need to do anything when we're in the
2119 * ONLINE state. However, for WiFi we can be in INIT or
2120 * SCAN aux states while being ONLINE.
2122 nwamd_ncu_state_machine(event->event_object);
2123 break;
2125 case NWAM_STATE_OFFLINE:
2126 /* Reassess priority group now member is offline */
2127 if (prioritized) {
2128 nwamd_create_ncu_check_event(0);
2130 break;
2132 case NWAM_STATE_DISABLED:
2133 case NWAM_STATE_UNINITIALIZED:
2134 case NWAM_STATE_MAINTENANCE:
2135 case NWAM_STATE_DEGRADED:
2136 default:
2137 /* do nothing */
2138 break;
2141 if (is_link) {
2142 if ((new_state == NWAM_STATE_ONLINE_TO_OFFLINE &&
2143 new_aux_state != NWAM_AUX_STATE_UNINITIALIZED &&
2144 new_aux_state != NWAM_AUX_STATE_NOT_FOUND) ||
2145 new_state == NWAM_STATE_DISABLED) {
2147 * Going offline, propogate down event to IP NCU. Do
2148 * not propogate event if new aux state is uninitialized
2149 * or not found as these auxiliary states signify
2150 * that an NCP switch/device removal is in progress.
2152 nwamd_propogate_link_up_down_to_ip(linkname, B_FALSE);
2154 if (new_state == NWAM_STATE_ONLINE) {
2155 /* gone online, propogate up event to IP NCU */
2156 nwamd_propogate_link_up_down_to_ip(linkname, B_TRUE);
2158 } else {
2159 /* If IP NCU is online, reasses priority group */
2160 if (new_state == NWAM_STATE_ONLINE)
2161 nwamd_create_ncu_check_event(0);