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]
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <arpa/inet.h>
28 #include <libdlaggr.h>
29 #include <libdllink.h>
30 #include <libdlstat.h>
33 #include <netinet/in.h>
36 #include <sys/socket.h>
38 #include <sys/types.h>
42 #include "conditions.h"
49 * ncu.c - handles various NCU tasks - intialization/refresh, state machine
53 #define VBOX_IFACE_PREFIX "vboxnet"
55 static void populate_ip_ncu_properties(nwam_ncu_handle_t
, nwamd_ncu_t
*);
58 * Find ncu of specified type for link/interface name.
61 nwamd_ncu_object_find(nwam_ncu_type_t type
, const char *name
)
65 nwamd_object_t ncu_obj
= NULL
;
67 if ((err
= nwam_ncu_name_to_typed_name(name
, type
, &object_name
))
69 nlog(LOG_ERR
, "nwamd_ncu_find: nwam_ncu_name_to_typed_name "
70 "returned %s", nwam_strerror(err
));
73 ncu_obj
= nwamd_object_find(NWAM_OBJECT_TYPE_NCU
, object_name
);
80 nwamd_set_ncu_string(nwam_ncu_handle_t ncuh
, char **strval
, uint_t cnt
,
86 if ((err
= nwam_value_create_string_array(strval
, cnt
, &val
))
89 err
= nwam_ncu_set_prop_value(ncuh
, prop
, val
);
95 nwamd_set_ncu_uint(nwam_ncu_handle_t ncuh
, uint64_t *uintval
, uint_t cnt
,
101 if ((err
= nwam_value_create_uint64_array(uintval
, cnt
, &val
))
104 err
= nwam_ncu_set_prop_value(ncuh
, prop
, val
);
105 nwam_value_free(val
);
110 nwamd_get_ncu_string(nwam_ncu_handle_t ncuh
, nwam_value_t
*val
, char ***strval
,
111 uint_t
*cnt
, const char *prop
)
115 if ((err
= nwam_ncu_get_prop_value(ncuh
, prop
, val
)) != NWAM_SUCCESS
)
117 return (nwam_value_get_string_array(*val
, strval
, cnt
));
121 nwamd_get_ncu_uint(nwam_ncu_handle_t ncuh
, nwam_value_t
*val
,
122 uint64_t **uintval
, uint_t
*cnt
, const char *prop
)
126 if ((err
= nwam_ncu_get_prop_value(ncuh
, prop
, val
)) != NWAM_SUCCESS
)
128 return (nwam_value_get_uint64_array(*val
, uintval
, cnt
));
132 * Run link/interface state machine in response to a state change
133 * or enable/disable action event.
136 nwamd_ncu_state_machine(const char *object_name
)
138 nwamd_object_t object
;
140 link_state_t link_state
;
142 nwam_wlan_t key_wlan
, connected_wlan
;
144 char linkname
[NWAM_MAX_NAME_LEN
];
147 if ((object
= nwamd_object_find(NWAM_OBJECT_TYPE_NCU
, object_name
))
149 nlog(LOG_ERR
, "nwamd_ncu_state_machine: "
150 "request for nonexistent NCU %s", object_name
);
154 ncu
= object
->nwamd_object_data
;
155 link
= &ncu
->ncu_link
;
157 switch (object
->nwamd_object_aux_state
) {
158 case NWAM_AUX_STATE_INITIALIZED
:
159 if (ncu
->ncu_type
== NWAM_NCU_TYPE_LINK
) {
161 * For wired/wireless links, need to get link
162 * up/down events and even if these are not supported,
163 * dlpi_open()ing the link prevents the driver from
166 nwamd_dlpi_add_link(object
);
168 if (link
->nwamd_link_media
== DL_WIFI
) {
170 * First, if we're unexpectedly connected,
173 if (!link
->nwamd_link_wifi_connected
&&
174 nwamd_wlan_connected(object
)) {
176 "nwamd_ncu_state_machine: "
177 "WiFi unexpectedly connected, "
179 (void) dladm_wlan_disconnect(dld_handle
,
180 link
->nwamd_link_id
);
181 nwamd_set_selected_connected(ncu
,
184 /* move to scanning aux state */
185 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU
,
186 object_name
, object
->nwamd_object_state
,
187 NWAM_AUX_STATE_LINK_WIFI_SCANNING
);
190 * If initial wired link state is unknown, we
191 * will need to assume the link is up, since
192 * we won´t get DL_NOTE_LINK_UP/DOWN events.
194 link_state
= nwamd_get_link_state
196 if (link_state
== LINK_STATE_UP
||
197 link_state
== LINK_STATE_UNKNOWN
) {
198 nwamd_object_set_state
199 (NWAM_OBJECT_TYPE_NCU
,
200 object_name
, NWAM_STATE_ONLINE
,
203 nwamd_object_set_state
204 (NWAM_OBJECT_TYPE_NCU
,
206 NWAM_STATE_ONLINE_TO_OFFLINE
,
207 NWAM_AUX_STATE_DOWN
);
212 * In the current implementation, initialization has to
213 * start from scratch since the complexity of minimizing
214 * configuration change is considerable (e.g. if we
215 * refresh and had DHCP running on the physical
216 * interface, and now have changed to static assignment,
217 * we need to remove DHCP etc). To avoid all this,
218 * unplumb before re-plumbing the protocols and
219 * addresses we wish to configure. In the future, it
220 * would be good to try and minimize configuration
223 nwamd_unplumb_interface(ncu
, AF_INET
);
224 nwamd_unplumb_interface(ncu
, AF_INET6
);
227 * We may be restarting the state machine. Re-read
228 * the IP NCU properties as the ipadm_addrobj_t in
229 * nwamd_if_address should not be reused.
231 populate_ip_ncu_properties(object
->nwamd_object_handle
,
235 * Enqueue a WAITING_FOR_ADDR aux state change so that
236 * we are eligible to receive the IF_STATE events
237 * associated with static, DHCP, DHCPv6 and autoconf
238 * address assignment. The latter two can happen
239 * quite quickly after plumbing so we need to be ready.
241 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU
,
242 object_name
, NWAM_STATE_OFFLINE_TO_ONLINE
,
243 NWAM_AUX_STATE_IF_WAITING_FOR_ADDR
);
245 if (ncu
->ncu_if
.nwamd_if_ipv4
)
246 nwamd_plumb_interface(ncu
, AF_INET
);
248 if (ncu
->ncu_if
.nwamd_if_ipv6
)
249 nwamd_plumb_interface(ncu
, AF_INET6
);
251 /* Configure addresses */
252 nwamd_configure_interface_addresses(ncu
);
256 case NWAM_AUX_STATE_IF_DHCP_TIMED_OUT
:
257 case NWAM_AUX_STATE_IF_WAITING_FOR_ADDR
:
259 * nothing to do here - RTM_NEWADDRs will trigger IF_STATE
260 * events to move us online.
264 case NWAM_AUX_STATE_LINK_WIFI_SCANNING
:
265 /* launch scan thread */
266 (void) strlcpy(linkname
, ncu
->ncu_name
, sizeof (linkname
));
267 (void) nwamd_wlan_scan(linkname
);
268 /* Create periodic scan event */
269 nwamd_ncu_create_periodic_scan_event(object
);
272 case NWAM_AUX_STATE_LINK_WIFI_NEED_SELECTION
:
273 /* send "need choice" event */
274 event
= nwamd_event_init_wlan
275 (ncu
->ncu_name
, NWAM_EVENT_TYPE_WLAN_NEED_CHOICE
, B_FALSE
,
276 link
->nwamd_link_wifi_scan
.nwamd_wifi_scan_curr
,
277 link
->nwamd_link_wifi_scan
.nwamd_wifi_scan_curr_num
);
280 nwamd_event_enqueue(event
);
281 nwamd_set_selected_connected(ncu
, B_FALSE
, B_FALSE
);
284 case NWAM_AUX_STATE_LINK_WIFI_NEED_KEY
:
286 * Send "need key" event. Set selected to true, connected
287 * and have_key to false. Do not fill in WLAN details as
288 * multiple WLANs may match the ESSID name, and each may
289 * have a different speed and channel.
291 bzero(&key_wlan
, sizeof (key_wlan
));
292 (void) strlcpy(key_wlan
.nww_essid
, link
->nwamd_link_wifi_essid
,
293 sizeof (key_wlan
.nww_essid
));
294 (void) strlcpy(key_wlan
.nww_bssid
, link
->nwamd_link_wifi_bssid
,
295 sizeof (key_wlan
.nww_bssid
));
296 key_wlan
.nww_security_mode
=
297 link
->nwamd_link_wifi_security_mode
;
298 key_wlan
.nww_selected
= B_TRUE
;
299 key_wlan
.nww_connected
= B_FALSE
;
300 key_wlan
.nww_have_key
= B_FALSE
;
301 event
= nwamd_event_init_wlan
302 (ncu
->ncu_name
, NWAM_EVENT_TYPE_WLAN_NEED_KEY
, B_FALSE
,
306 nwamd_event_enqueue(event
);
309 case NWAM_AUX_STATE_LINK_WIFI_CONNECTING
:
310 (void) strlcpy(linkname
, ncu
->ncu_name
, sizeof (linkname
));
311 nwamd_wlan_connect(linkname
);
314 case NWAM_AUX_STATE_UP
:
315 case NWAM_AUX_STATE_DOWN
:
316 up
= (object
->nwamd_object_aux_state
== NWAM_AUX_STATE_UP
);
317 if (ncu
->ncu_type
== NWAM_NCU_TYPE_LINK
) {
318 if (link
->nwamd_link_media
== DL_WIFI
) {
320 * Connected/disconnected - send WLAN
323 link
->nwamd_link_wifi_connected
= up
;
324 nwamd_set_selected_connected(ncu
, B_TRUE
, up
);
326 (void) strlcpy(connected_wlan
.nww_essid
,
327 link
->nwamd_link_wifi_essid
,
328 sizeof (connected_wlan
.nww_essid
));
329 (void) strlcpy(connected_wlan
.nww_bssid
,
330 link
->nwamd_link_wifi_bssid
,
331 sizeof (connected_wlan
.nww_bssid
));
332 connected_wlan
.nww_security_mode
=
333 link
->nwamd_link_wifi_security_mode
;
334 event
= nwamd_event_init_wlan
336 NWAM_EVENT_TYPE_WLAN_CONNECTION_REPORT
, up
,
340 nwamd_event_enqueue(event
);
343 * If disconnected, restart the state machine
344 * for the WiFi link (WiFi is always trying
347 * If connected, start signal strength
350 if (!up
&& ncu
->ncu_enabled
) {
352 "nwamd_ncu_state_machine: "
353 "wifi disconnect - start over "
354 "after %dsec interval",
355 WIRELESS_RETRY_INTERVAL
);
356 link
->nwamd_link_wifi_connected
=
358 /* propogate down event to IP NCU */
359 nwamd_propogate_link_up_down_to_ip
360 (ncu
->ncu_name
, B_FALSE
);
361 nwamd_object_set_state_timed
362 (NWAM_OBJECT_TYPE_NCU
, object_name
,
363 NWAM_STATE_OFFLINE_TO_ONLINE
,
364 NWAM_AUX_STATE_INITIALIZED
,
365 WIRELESS_RETRY_INTERVAL
);
368 "nwamd_ncu_state_machine: "
369 "wifi connected, start monitoring");
370 (void) strlcpy(linkname
, ncu
->ncu_name
,
372 nwamd_wlan_monitor_signal(linkname
);
377 /* If not in ONLINE/OFFLINE state yet, change state */
378 if ((up
&& object
->nwamd_object_state
!= NWAM_STATE_ONLINE
) ||
379 (!up
&& object
->nwamd_object_state
!= NWAM_STATE_OFFLINE
)) {
380 nlog(LOG_DEBUG
, "nwamd_ncu_state_machine: "
381 "%s is moving %s", object_name
,
382 up
? "online" : "offline");
383 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU
,
385 up
? NWAM_STATE_ONLINE
: NWAM_STATE_OFFLINE
,
386 up
? NWAM_AUX_STATE_UP
: NWAM_AUX_STATE_DOWN
);
388 if (ncu
->ncu_type
== NWAM_NCU_TYPE_INTERFACE
) {
391 * Moving online, add v4/v6 default
394 nwamd_add_default_routes(ncu
);
397 * If this is an interface NCU and we
398 * got a down event, it is a consequence
399 * of NCU refresh, so reapply addresses
402 nwamd_object_set_state
403 (NWAM_OBJECT_TYPE_NCU
, object_name
,
404 NWAM_STATE_OFFLINE_TO_ONLINE
,
405 NWAM_AUX_STATE_INITIALIZED
);
409 nlog(LOG_DEBUG
, "nwamd_ncu_state_machine: "
410 "%s is %s", object_name
,
411 up
? "online" : "offline");
414 * NCU is UP or DOWN, trigger all condition checking, even if
415 * the NCU is already in the ONLINE state - an ENM may depend
418 nwamd_create_triggered_condition_check_event(NEXT_FEW_SECONDS
);
421 case NWAM_AUX_STATE_CONDITIONS_NOT_MET
:
423 * Link/interface is moving offline. Nothing to do except
424 * for WiFi, where we disconnect. Don't unplumb IP on
425 * a link since it may be a transient change.
427 if (ncu
->ncu_type
== NWAM_NCU_TYPE_LINK
) {
428 if (link
->nwamd_link_media
== DL_WIFI
) {
429 (void) dladm_wlan_disconnect(dld_handle
,
430 link
->nwamd_link_id
);
431 link
->nwamd_link_wifi_connected
= B_FALSE
;
432 nwamd_set_selected_connected(ncu
, B_FALSE
,
437 * Unplumb here. In the future we may elaborate on
438 * the approach used and not unplumb for WiFi
439 * until we reconnect to a different WLAN (i.e. with
440 * a different ESSID).
442 nwamd_unplumb_interface(ncu
, AF_INET
);
443 nwamd_unplumb_interface(ncu
, AF_INET6
);
445 if (object
->nwamd_object_state
!= NWAM_STATE_OFFLINE
) {
446 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU
,
447 object_name
, NWAM_STATE_OFFLINE
,
448 NWAM_AUX_STATE_CONDITIONS_NOT_MET
);
452 case NWAM_AUX_STATE_MANUAL_DISABLE
:
453 /* Manual disable, set enabled state appropriately. */
454 ncu
->ncu_enabled
= B_FALSE
;
456 case NWAM_AUX_STATE_UNINITIALIZED
:
457 case NWAM_AUX_STATE_NOT_FOUND
:
459 * Link/interface NCU has been disabled/deactivated/removed.
460 * For WiFi links disconnect, and for IP interfaces we unplumb.
462 if (ncu
->ncu_type
== NWAM_NCU_TYPE_LINK
) {
463 if (link
->nwamd_link_media
== DL_WIFI
) {
464 (void) dladm_wlan_disconnect(dld_handle
,
465 link
->nwamd_link_id
);
466 link
->nwamd_link_wifi_connected
= B_FALSE
;
467 nwamd_set_selected_connected(ncu
, B_FALSE
,
470 nwamd_dlpi_delete_link(object
);
473 if (ncu
->ncu_if
.nwamd_if_ipv4
) {
474 nwamd_unplumb_interface(ncu
, AF_INET
);
476 if (ncu
->ncu_if
.nwamd_if_ipv6
) {
477 nwamd_unplumb_interface(ncu
, AF_INET6
);
479 /* trigger location condition checking */
480 nwamd_create_triggered_condition_check_event(0);
483 switch (object
->nwamd_object_aux_state
) {
484 case NWAM_AUX_STATE_MANUAL_DISABLE
:
485 /* Change state to DISABLED if manually disabled */
486 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU
,
487 object_name
, NWAM_STATE_DISABLED
,
488 NWAM_AUX_STATE_MANUAL_DISABLE
);
489 /* Note that NCU has been disabled */
490 ncu
->ncu_enabled
= B_FALSE
;
492 case NWAM_AUX_STATE_NOT_FOUND
:
493 /* Change state to UNINITIALIZED for device removal */
494 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU
,
495 object_name
, NWAM_STATE_UNINITIALIZED
,
496 NWAM_AUX_STATE_NOT_FOUND
);
503 nlog(LOG_ERR
, "nwamd_ncu_state_machine: unexpected state");
507 nwamd_object_release(object
);
511 ncu_create_init_fini_event(nwam_ncu_handle_t ncuh
, void *data
)
513 boolean_t
*init
= data
;
514 char *name
, *typedname
;
516 nwam_value_t typeval
= NULL
;
519 nwamd_event_t ncu_event
;
521 if (nwam_ncu_get_name(ncuh
, &name
) != NWAM_SUCCESS
) {
523 "ncu_create_init_fini_event: could not get NCU name");
527 nlog(LOG_DEBUG
, "ncu_create_init_fini_event(%s, %p)", name
, data
);
529 if ((err
= nwamd_get_ncu_uint(ncuh
, &typeval
, &type
, &numvalues
,
530 NWAM_NCU_PROP_TYPE
)) != NWAM_SUCCESS
) {
531 nlog(LOG_ERR
, "ncu_create_init_fini_event: "
532 "could not get NCU type: %s", nwam_strerror(err
));
534 nwam_value_free(typeval
);
538 /* convert name to typedname for event */
539 if ((err
= nwam_ncu_name_to_typed_name(name
, *type
, &typedname
))
541 nlog(LOG_ERR
, "ncu_create_init_fini_event: "
542 "NCU name translation failed: %s", nwam_strerror(err
));
547 nwam_value_free(typeval
);
549 ncu_event
= nwamd_event_init(*init
?
550 NWAM_EVENT_TYPE_OBJECT_INIT
: NWAM_EVENT_TYPE_OBJECT_FINI
,
551 NWAM_OBJECT_TYPE_NCU
, 0, typedname
);
552 if (ncu_event
!= NULL
)
553 nwamd_event_enqueue(ncu_event
);
560 * Initialization - walk the NCUs, creating initialization events for each
561 * NCU. nwamd_ncu_handle_init_event() will check if the associated
562 * physical link exists or not.
565 nwamd_init_ncus(void)
567 boolean_t init
= B_TRUE
;
569 (void) pthread_mutex_lock(&active_ncp_mutex
);
570 if (active_ncph
!= NULL
) {
571 nlog(LOG_DEBUG
, "nwamd_init_ncus: "
572 "(re)intializing NCUs for NCP %s", active_ncp
);
573 (void) nwam_ncp_walk_ncus(active_ncph
,
574 ncu_create_init_fini_event
, &init
, NWAM_FLAG_NCU_TYPE_ALL
,
577 (void) pthread_mutex_unlock(&active_ncp_mutex
);
581 nwamd_fini_ncus(void)
583 boolean_t init
= B_FALSE
;
585 /* We may not have an active NCP on initialization, so skip fini */
586 (void) pthread_mutex_lock(&active_ncp_mutex
);
587 if (active_ncph
!= NULL
) {
588 nlog(LOG_DEBUG
, "nwamd_fini_ncus: deinitializing NCUs for %s",
590 (void) nwam_ncp_walk_ncus(active_ncph
,
591 ncu_create_init_fini_event
, &init
, NWAM_FLAG_NCU_TYPE_ALL
,
594 (void) pthread_mutex_unlock(&active_ncp_mutex
);
598 * Most properties of this type don't need to be cached locally. Only those
599 * interesting to the daemon are stored in an nwamd_ncu_t.
602 populate_common_ncu_properties(nwam_ncu_handle_t ncuh
, nwamd_ncu_t
*ncu_data
)
604 nwam_value_t ncu_prop
;
606 boolean_t enablevalue
;
610 if ((err
= nwam_ncu_get_prop_value(ncuh
, NWAM_NCU_PROP_ENABLED
,
611 &ncu_prop
)) != NWAM_SUCCESS
) {
613 (void) nwam_ncu_name_to_typed_name(ncu_data
->ncu_name
,
614 ncu_data
->ncu_type
, &name
);
615 nlog(LOG_ERR
, "nwam_ncu_get_prop_value %s ENABLED failed: %s",
616 name
, nwam_strerror(err
));
618 ncu_data
->ncu_enabled
= B_TRUE
;
620 if ((err
= nwam_value_get_boolean(ncu_prop
, &enablevalue
)) !=
622 nlog(LOG_ERR
, "nwam_value_get_boolean ENABLED failed: "
623 "%s", nwam_strerror(err
));
625 ncu_data
->ncu_enabled
= enablevalue
;
627 nwam_value_free(ncu_prop
);
630 if ((err
= nwamd_get_ncu_string(ncuh
, &ncu_prop
, &parent
,
631 &numvalues
, NWAM_NCU_PROP_PARENT_NCP
)) != NWAM_SUCCESS
) {
632 nlog(LOG_ERR
, "nwam_ncu_get_prop_value %s PARENT failed: %s",
633 ncu_data
->ncu_name
, nwam_strerror(err
));
635 (void) strlcpy(ncu_data
->ncu_parent
, parent
[0],
636 sizeof (ncu_data
->ncu_parent
));
637 nwam_value_free(ncu_prop
);
642 * Read in link properties.
645 populate_link_ncu_properties(nwam_ncu_handle_t ncuh
, nwamd_ncu_t
*ncu_data
)
647 nwam_value_t ncu_prop
;
653 /* activation-mode */
654 if ((err
= nwamd_get_ncu_uint(ncuh
, &ncu_prop
, &uintval
, &numvalues
,
655 NWAM_NCU_PROP_ACTIVATION_MODE
)) != NWAM_SUCCESS
) {
657 "populate_link_ncu_properties: could not get %s value: %s",
658 NWAM_NCU_PROP_ACTIVATION_MODE
, nwam_strerror(err
));
660 ncu_data
->ncu_link
.nwamd_link_activation_mode
= uintval
[0];
661 nwam_value_free(ncu_prop
);
664 /* priority-group and priority-mode for prioritized activation */
665 if (ncu_data
->ncu_link
.nwamd_link_activation_mode
==
666 NWAM_ACTIVATION_MODE_PRIORITIZED
) {
667 /* ncus with prioritized activation are always enabled */
668 ncu_data
->ncu_enabled
= B_TRUE
;
669 if ((err
= nwamd_get_ncu_uint(ncuh
, &ncu_prop
, &uintval
,
670 &numvalues
, NWAM_NCU_PROP_PRIORITY_MODE
))
672 nlog(LOG_ERR
, "populate_link_ncu_properties: "
673 "could not get %s value: %s",
674 NWAM_NCU_PROP_PRIORITY_MODE
, nwam_strerror(err
));
676 ncu_data
->ncu_link
.nwamd_link_priority_mode
=
678 nwam_value_free(ncu_prop
);
681 if ((err
= nwamd_get_ncu_uint(ncuh
, &ncu_prop
, &uintval
,
682 &numvalues
, NWAM_NCU_PROP_PRIORITY_GROUP
))
684 nlog(LOG_ERR
, "populate_link_ncu_properties: "
685 "could not get %s value: %s",
686 NWAM_NCU_PROP_PRIORITY_GROUP
, nwam_strerror(err
));
688 ncu_data
->ncu_link
.nwamd_link_priority_group
=
690 nwam_value_free(ncu_prop
);
695 if ((err
= nwamd_get_ncu_string(ncuh
, &ncu_prop
, &mac_addr
, &numvalues
,
696 NWAM_NCU_PROP_LINK_MAC_ADDR
)) != NWAM_SUCCESS
) {
698 "populate_link_ncu_properties: could not get %s value: %s",
699 NWAM_NCU_PROP_LINK_MAC_ADDR
, nwam_strerror(err
));
700 ncu_data
->ncu_link
.nwamd_link_mac_addr
= NULL
;
702 ncu_data
->ncu_link
.nwamd_link_mac_addr
= strdup(*mac_addr
);
703 ncu_data
->ncu_link
.nwamd_link_mac_addr_len
= strlen(*mac_addr
);
704 nwam_value_free(ncu_prop
);
708 if ((err
= nwamd_get_ncu_uint(ncuh
, &ncu_prop
, &uintval
, &numvalues
,
709 NWAM_NCU_PROP_LINK_MTU
)) != NWAM_SUCCESS
) {
711 "populate_link_ncu_properties: could not get %s value: %s",
712 NWAM_NCU_PROP_LINK_MTU
, nwam_strerror(err
));
713 ncu_data
->ncu_link
.nwamd_link_mtu
= 0;
715 ncu_data
->ncu_link
.nwamd_link_mtu
= uintval
[0];
716 nwam_value_free(ncu_prop
);
720 if ((err
= nwamd_get_ncu_string(ncuh
, &ncu_prop
,
721 &ncu_data
->ncu_link
.nwamd_link_autopush
,
722 &ncu_data
->ncu_link
.nwamd_link_num_autopush
,
723 NWAM_NCU_PROP_LINK_AUTOPUSH
)) != NWAM_SUCCESS
) {
725 "populate_link_ncu_properties: could not get %s value: %s",
726 NWAM_NCU_PROP_LINK_AUTOPUSH
, nwam_strerror(err
));
727 ncu_data
->ncu_link
.nwamd_link_num_autopush
= 0;
732 populate_ip_ncu_properties(nwam_ncu_handle_t ncuh
, nwamd_ncu_t
*ncu_data
)
734 nwamd_if_t
*nif
= &ncu_data
->ncu_if
;
735 struct nwamd_if_address
**nifa
, *nifai
, *nifait
;
736 boolean_t static_addr
= B_FALSE
;
737 uint64_t *addrsrcvalue
;
738 nwam_value_t ncu_prop
;
740 ipadm_addrobj_t ipaddr
;
741 ipadm_status_t ipstatus
;
747 nif
->nwamd_if_ipv4
= B_FALSE
;
748 nif
->nwamd_if_ipv6
= B_FALSE
;
749 nif
->nwamd_if_dhcp_requested
= B_FALSE
;
750 nif
->nwamd_if_stateful_requested
= B_FALSE
;
751 nif
->nwamd_if_stateless_requested
= B_FALSE
;
752 nif
->nwamd_if_ipv4_default_route_set
= B_FALSE
;
753 nif
->nwamd_if_ipv6_default_route_set
= B_FALSE
;
756 if ((err
= nwamd_get_ncu_uint(ncuh
, &ncu_prop
, &ipversion
, &numvalues
,
757 NWAM_NCU_PROP_IP_VERSION
)) != NWAM_SUCCESS
) {
759 "populate_ip_ncu_properties: could not get %s value: %s",
760 NWAM_NCU_PROP_IP_VERSION
, nwam_strerror(err
));
762 for (i
= 0; i
< numvalues
; i
++) {
763 switch (ipversion
[i
]) {
765 nif
->nwamd_if_ipv4
= B_TRUE
;
768 nif
->nwamd_if_ipv6
= B_TRUE
;
771 nlog(LOG_ERR
, "bogus ip version %lld",
776 nwam_value_free(ncu_prop
);
779 /* Free the old list. */
780 for (nifai
= nif
->nwamd_if_list
; nifai
!= NULL
; nifai
= nifait
) {
781 nifait
= nifai
->next
;
783 ipadm_destroy_addrobj(nifai
->ipaddr
);
786 nif
->nwamd_if_list
= NULL
;
787 nifa
= &(nif
->nwamd_if_list
);
789 if (!nif
->nwamd_if_ipv4
)
793 if ((err
= nwamd_get_ncu_uint(ncuh
, &ncu_prop
, &addrsrcvalue
,
794 &numvalues
, NWAM_NCU_PROP_IPV4_ADDRSRC
)) != NWAM_SUCCESS
) {
795 nlog(nif
->nwamd_if_ipv4
? LOG_ERR
: LOG_DEBUG
,
796 "populate_ip_ncu_properties: could not get %s value: %s",
797 NWAM_NCU_PROP_IPV4_ADDRSRC
, nwam_strerror(err
));
799 for (i
= 0; i
< numvalues
; i
++) {
800 switch (addrsrcvalue
[i
]) {
801 case NWAM_ADDRSRC_DHCP
:
802 nif
->nwamd_if_dhcp_requested
= B_TRUE
;
804 case NWAM_ADDRSRC_STATIC
:
805 static_addr
= B_TRUE
;
811 nwam_value_free(ncu_prop
);
813 if (nif
->nwamd_if_dhcp_requested
) {
814 ipstatus
= ipadm_create_addrobj(IPADM_ADDR_DHCP
,
815 ncu_data
->ncu_name
, &ipaddr
);
816 if (ipstatus
!= IPADM_SUCCESS
) {
817 nlog(LOG_ERR
, "populate_ip_ncu_properties: "
818 "ipadm_create_addrobj failed for v4 dhcp: %s",
819 ipadm_status2str(ipstatus
));
823 ipstatus
= ipadm_set_wait_time(ipaddr
, ncu_wait_time
);
824 if (ipstatus
!= IPADM_SUCCESS
) {
825 nlog(LOG_ERR
, "populate_ip_ncu_properties: "
826 "ipadm_set_wait_time failed for v4 dhcp: %s",
827 ipadm_status2str(ipstatus
));
828 ipadm_destroy_addrobj(ipaddr
);
831 if ((*nifa
= calloc(sizeof (**nifa
), 1)) != NULL
) {
832 (*nifa
)->family
= AF_INET
;
833 (*nifa
)->ipaddr_atype
= IPADM_ADDR_DHCP
;
834 (*nifa
)->ipaddr
= ipaddr
;
835 nifa
= &((*nifa
)->next
);
838 nlog(LOG_ERR
, "populate_ip_ncu_properties: "
839 "couldn't allocate nwamd address for v4 dhcp: %s",
841 ipadm_destroy_addrobj(ipaddr
);
848 if ((err
= nwamd_get_ncu_string(ncuh
, &ncu_prop
, &addrvalue
,
849 &numvalues
, NWAM_NCU_PROP_IPV4_ADDR
)) != NWAM_SUCCESS
) {
850 nlog(LOG_ERR
, "populate_ip_ncu_properties: "
851 "could not get %s value; %s",
852 NWAM_NCU_PROP_IPV4_ADDR
, nwam_strerror(err
));
854 for (i
= 0; i
< numvalues
; i
++) {
855 ipstatus
= ipadm_create_addrobj(
856 IPADM_ADDR_STATIC
, ncu_data
->ncu_name
,
858 if (ipstatus
!= IPADM_SUCCESS
) {
860 "populate_ip_ncu_properties: "
861 "ipadm_create_addrobj failed "
862 "for %s: %s", addrvalue
[i
],
863 ipadm_status2str(ipstatus
));
866 /* ipadm_set_addr takes <addr>[/<mask>] */
867 ipstatus
= ipadm_set_addr(ipaddr
, addrvalue
[i
],
869 if (ipstatus
!= IPADM_SUCCESS
) {
871 "populate_ip_ncu_properties: "
872 "ipadm_set_addr failed for %s: %s",
874 ipadm_status2str(ipstatus
));
875 ipadm_destroy_addrobj(ipaddr
);
879 if ((*nifa
= calloc(sizeof (**nifa
), 1))
881 (*nifa
)->family
= AF_INET
;
882 (*nifa
)->ipaddr_atype
=
884 (*nifa
)->ipaddr
= ipaddr
;
885 nifa
= &((*nifa
)->next
);
888 "populate_ip_ncu_properties: "
889 "couldn't allocate nwamd address "
890 "for %s: %s", addrvalue
[i
],
892 ipadm_destroy_addrobj(ipaddr
);
897 nwam_value_free(ncu_prop
);
901 /* get default route, if any */
902 if ((err
= nwamd_get_ncu_string(ncuh
, &ncu_prop
, &addrvalue
,
903 &numvalues
, NWAM_NCU_PROP_IPV4_DEFAULT_ROUTE
)) == NWAM_SUCCESS
) {
904 /* Only one default route is allowed. */
905 nif
->nwamd_if_ipv4_default_route
.sin_family
= AF_INET
;
906 (void) inet_pton(AF_INET
, addrvalue
[0],
907 &(nif
->nwamd_if_ipv4_default_route
.sin_addr
));
908 nif
->nwamd_if_ipv4_default_route_set
= B_TRUE
;
909 nwam_value_free(ncu_prop
);
913 if (!nif
->nwamd_if_ipv6
)
917 static_addr
= B_FALSE
;
918 if ((err
= nwamd_get_ncu_uint(ncuh
, &ncu_prop
, &addrsrcvalue
,
919 &numvalues
, NWAM_NCU_PROP_IPV6_ADDRSRC
)) != NWAM_SUCCESS
) {
920 nlog(nif
->nwamd_if_ipv6
? LOG_ERR
: LOG_DEBUG
,
921 "populate_ip_ncu_properties: could not get %s value: %s",
922 NWAM_NCU_PROP_IPV6_ADDRSRC
, nwam_strerror(err
));
924 for (i
= 0; i
< numvalues
; i
++) {
925 switch (addrsrcvalue
[i
]) {
926 case NWAM_ADDRSRC_DHCP
:
927 nif
->nwamd_if_stateful_requested
= B_TRUE
;
929 case NWAM_ADDRSRC_AUTOCONF
:
930 nif
->nwamd_if_stateless_requested
= B_TRUE
;
932 case NWAM_ADDRSRC_STATIC
:
933 static_addr
= B_TRUE
;
939 nwam_value_free(ncu_prop
);
942 * Both stateful and stateless share the same nwamd_if_address because
943 * only one ipaddr for both of these addresses can be created.
944 * ipadm_create_addr() adds both addresses from the same ipaddr.
946 if (nif
->nwamd_if_stateful_requested
||
947 nif
->nwamd_if_stateless_requested
) {
948 ipstatus
= ipadm_create_addrobj(IPADM_ADDR_IPV6_ADDRCONF
,
949 ncu_data
->ncu_name
, &ipaddr
);
950 if (ipstatus
!= IPADM_SUCCESS
) {
951 nlog(LOG_ERR
, "populate_ip_ncu_properties: "
952 "ipadm_create_addrobj failed for v6 "
953 "stateless/stateful: %s",
954 ipadm_status2str(ipstatus
));
955 goto skip_ipv6_addrconf
;
957 /* create_addrobj sets both stateless and stateful to B_TRUE */
958 if (!nif
->nwamd_if_stateful_requested
) {
959 ipstatus
= ipadm_set_stateful(ipaddr
, B_FALSE
);
960 if (ipstatus
!= IPADM_SUCCESS
) {
961 nlog(LOG_ERR
, "populate_ip_ncu_properties: "
962 "ipadm_set_stateful failed for v6: %s",
963 ipadm_status2str(ipstatus
));
964 ipadm_destroy_addrobj(ipaddr
);
965 goto skip_ipv6_addrconf
;
968 if (!nif
->nwamd_if_stateless_requested
) {
969 ipstatus
= ipadm_set_stateless(ipaddr
, B_FALSE
);
970 if (ipstatus
!= IPADM_SUCCESS
) {
971 nlog(LOG_ERR
, "populate_ip_ncu_properties: "
972 "ipadm_set_stateless failed for v6: %s",
973 ipadm_status2str(ipstatus
));
974 ipadm_destroy_addrobj(ipaddr
);
975 goto skip_ipv6_addrconf
;
978 if ((*nifa
= calloc(sizeof (**nifa
), 1)) != NULL
) {
979 (*nifa
)->family
= AF_INET6
;
980 (*nifa
)->ipaddr_atype
= IPADM_ADDR_IPV6_ADDRCONF
;
981 (*nifa
)->ipaddr
= ipaddr
;
982 nifa
= &((*nifa
)->next
);
985 nlog(LOG_ERR
, "populate_ip_ncu_properties: "
986 "couldn't allocate nwamd address for "
987 "v6 stateless/stateful: %s", strerror(errno
));
988 ipadm_destroy_addrobj(ipaddr
);
995 if ((err
= nwamd_get_ncu_string(ncuh
, &ncu_prop
, &addrvalue
,
996 &numvalues
, NWAM_NCU_PROP_IPV6_ADDR
)) != NWAM_SUCCESS
) {
997 nlog(LOG_ERR
, "populate_ip_ncu_properties: "
998 "could not get %s value; %s",
999 NWAM_NCU_PROP_IPV6_ADDR
, nwam_strerror(err
));
1001 for (i
= 0; i
< numvalues
; i
++) {
1002 ipstatus
= ipadm_create_addrobj(
1003 IPADM_ADDR_STATIC
, ncu_data
->ncu_name
,
1005 if (ipstatus
!= IPADM_SUCCESS
) {
1007 "populate_ip_ncu_properties: "
1008 "ipadm_create_addrobj failed "
1009 "for %s: %s", addrvalue
[i
],
1010 ipadm_status2str(ipstatus
));
1013 /* ipadm_set_addr takes <addr>[/<mask>] */
1014 ipstatus
= ipadm_set_addr(ipaddr
, addrvalue
[i
],
1016 if (ipstatus
!= IPADM_SUCCESS
) {
1018 "populate_ip_ncu_properties: "
1019 "ipadm_set_addr failed for %s: %s",
1021 ipadm_status2str(ipstatus
));
1022 ipadm_destroy_addrobj(ipaddr
);
1026 if ((*nifa
= calloc(sizeof (**nifa
), 1))
1028 (*nifa
)->family
= AF_INET6
;
1029 (*nifa
)->ipaddr_atype
=
1031 (*nifa
)->ipaddr
= ipaddr
;
1032 nifa
= &((*nifa
)->next
);
1035 "populate_ip_ncu_properties: "
1036 "couldn't allocate nwamd address "
1037 "for %s: %s", addrvalue
[i
],
1039 ipadm_destroy_addrobj(ipaddr
);
1044 nwam_value_free(ncu_prop
);
1048 /* get default route, if any */
1049 if ((err
= nwamd_get_ncu_string(ncuh
, &ncu_prop
, &addrvalue
,
1050 &numvalues
, NWAM_NCU_PROP_IPV6_DEFAULT_ROUTE
)) == NWAM_SUCCESS
) {
1051 /* Only one default route is allowed. */
1052 nif
->nwamd_if_ipv6_default_route
.sin6_family
= AF_INET6
;
1053 (void) inet_pton(AF_INET6
, addrvalue
[0],
1054 &(nif
->nwamd_if_ipv6_default_route
.sin6_addr
));
1055 nif
->nwamd_if_ipv6_default_route_set
= B_TRUE
;
1056 nwam_value_free(ncu_prop
);
1063 static nwamd_ncu_t
*
1064 nwamd_ncu_init(nwam_ncu_type_t ncu_type
, const char *name
)
1068 nlog(LOG_DEBUG
, "nwamd_ncu_init(%d, %s)", ncu_type
, name
);
1070 if ((rv
= calloc(1, sizeof (*rv
))) == NULL
)
1073 rv
->ncu_type
= ncu_type
;
1074 rv
->ncu_name
= strdup(name
);
1075 rv
->ncu_enabled
= B_FALSE
;
1077 /* Initialize link/interface-specific data */
1078 if (rv
->ncu_type
== NWAM_NCU_TYPE_LINK
) {
1079 (void) bzero(&rv
->ncu_link
, sizeof (nwamd_link_t
));
1080 (void) dladm_name2info(dld_handle
, name
,
1081 &rv
->ncu_link
.nwamd_link_id
, NULL
, NULL
,
1082 &rv
->ncu_link
.nwamd_link_media
);
1083 (void) pthread_mutex_init(
1084 &rv
->ncu_link
.nwamd_link_wifi_mutex
, NULL
);
1085 rv
->ncu_link
.nwamd_link_wifi_priority
= MAXINT
;
1087 (void) bzero(&rv
->ncu_if
, sizeof (nwamd_if_t
));
1094 nwamd_ncu_free(nwamd_ncu_t
*ncu
)
1097 assert(ncu
->ncu_type
== NWAM_NCU_TYPE_LINK
||
1098 ncu
->ncu_type
== NWAM_NCU_TYPE_INTERFACE
);
1099 if (ncu
->ncu_type
== NWAM_NCU_TYPE_LINK
) {
1100 struct nwamd_link
*l
= &ncu
->ncu_link
;
1103 free(l
->nwamd_link_wifi_key
);
1104 free(l
->nwamd_link_mac_addr
);
1105 for (i
= 0; i
< l
->nwamd_link_num_autopush
; i
++)
1106 free(l
->nwamd_link_autopush
[i
]);
1107 } else if (ncu
->ncu_type
== NWAM_NCU_TYPE_INTERFACE
) {
1108 struct nwamd_if_address
*nifa
;
1110 nifa
= ncu
->ncu_if
.nwamd_if_list
;
1111 while (nifa
!= NULL
) {
1112 struct nwamd_if_address
*n
;
1116 ipadm_destroy_addrobj(n
->ipaddr
);
1120 free(ncu
->ncu_name
);
1126 nwamd_ncu_display(nwamd_object_t ncu_obj
, void *data
)
1128 nwamd_ncu_t
*ncu
= (nwamd_ncu_t
*)ncu_obj
->nwamd_object_data
;
1130 nlog(LOG_DEBUG
, "NCU (%p) %s state %s, %s",
1131 (void *)ncu
, ncu_obj
->nwamd_object_name
,
1132 nwam_state_to_string(ncu_obj
->nwamd_object_state
),
1133 nwam_aux_state_to_string(ncu_obj
->nwamd_object_aux_state
));
1138 nwamd_log_ncus(void)
1140 nlog(LOG_DEBUG
, "NCP %s", active_ncp
);
1141 (void) nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU
, nwamd_ncu_display
,
1146 nwamd_ncu_action(const char *ncu
, const char *parent
, nwam_action_t action
)
1148 nwamd_event_t ncu_event
= nwamd_event_init_object_action
1149 (NWAM_OBJECT_TYPE_NCU
, ncu
, parent
, action
);
1150 if (ncu_event
== NULL
)
1152 nwamd_event_enqueue(ncu_event
);
1157 add_phys_ncu_to_ncp(nwam_ncp_handle_t ncph
, const char *name
)
1159 dladm_status_t dlrtn
;
1161 boolean_t is_wireless
;
1163 nwam_ncu_handle_t ncuh
;
1166 if ((dlrtn
= dladm_name2info(dld_handle
, name
, NULL
, NULL
, NULL
,
1167 &media
)) != DLADM_STATUS_OK
) {
1168 char errmsg
[DLADM_STRSIZE
];
1169 nlog(LOG_ERR
, "failed to get media type for %s: %s", name
,
1170 dladm_status2str(dlrtn
, errmsg
));
1173 is_wireless
= (media
== DL_WIFI
);
1175 if ((err
= nwam_ncu_create(ncph
, name
, NWAM_NCU_TYPE_LINK
,
1176 NWAM_NCU_CLASS_PHYS
, &ncuh
)) != NWAM_SUCCESS
) {
1177 nlog(LOG_ERR
, "failed to create link ncu for %s: %s", name
,
1178 nwam_strerror(err
));
1179 if (err
== NWAM_ENTITY_READ_ONLY
) {
1180 nwamd_event_t retry_event
;
1183 * Root filesystem may be read-only, retry in
1186 nlog(LOG_DEBUG
, "Retrying addition of phys ncu for %s",
1188 retry_event
= nwamd_event_init_link_action(name
,
1190 if (retry_event
!= NULL
) {
1191 nwamd_event_enqueue_timed(retry_event
,
1192 NWAMD_READONLY_RETRY_INTERVAL
);
1198 uintval
= NWAM_ACTIVATION_MODE_PRIORITIZED
;
1199 if ((err
= nwamd_set_ncu_uint(ncuh
, &uintval
, 1,
1200 NWAM_NCU_PROP_ACTIVATION_MODE
)) != NWAM_SUCCESS
) {
1204 uintval
= is_wireless
? 1 : 0;
1205 if ((err
= nwamd_set_ncu_uint(ncuh
, &uintval
, 1,
1206 NWAM_NCU_PROP_PRIORITY_GROUP
)) != NWAM_SUCCESS
) {
1210 uintval
= is_wireless
? NWAM_PRIORITY_MODE_EXCLUSIVE
:
1211 NWAM_PRIORITY_MODE_SHARED
;
1212 if ((err
= nwamd_set_ncu_uint(ncuh
, &uintval
, 1,
1213 NWAM_NCU_PROP_PRIORITY_MODE
)) != NWAM_SUCCESS
) {
1217 err
= nwam_ncu_commit(ncuh
, 0);
1220 nwam_ncu_free(ncuh
);
1221 if (err
!= NWAM_SUCCESS
) {
1223 "failed to create automatic link ncu for %s: %s",
1224 name
, nwam_strerror(err
));
1229 add_ip_ncu_to_ncp(nwam_ncp_handle_t ncph
, const char *name
)
1232 nwam_ncu_handle_t ncuh
;
1234 if ((err
= nwam_ncu_create(ncph
, name
, NWAM_NCU_TYPE_INTERFACE
,
1235 NWAM_NCU_CLASS_IP
, &ncuh
)) != NWAM_SUCCESS
) {
1236 nlog(LOG_ERR
, "failed to create ip ncu for %s: %s", name
,
1237 nwam_strerror(err
));
1239 * Root filesystem may be read-only, but no need to
1240 * retry here since add_phys_ncu_to_ncp() enqueues
1241 * a retry event which will lead to add_ip_ncu_to_ncp()
1247 /* IP NCU has the default values, so nothing else to do */
1248 err
= nwam_ncu_commit(ncuh
, 0);
1251 nwam_ncu_free(ncuh
);
1252 if (err
!= NWAM_SUCCESS
) {
1254 "failed to create ip ncu for %s: %s", name
,
1255 nwam_strerror(err
));
1260 remove_ncu_from_ncp(nwam_ncp_handle_t ncph
, const char *name
,
1261 nwam_ncu_type_t type
)
1264 nwam_ncu_handle_t ncuh
;
1266 if ((err
= nwam_ncu_read(ncph
, name
, type
, 0, &ncuh
)) != NWAM_SUCCESS
) {
1267 nlog(LOG_ERR
, "failed to read automatic ncu %s: %s", name
,
1268 nwam_strerror(err
));
1272 err
= nwam_ncu_destroy(ncuh
, 0);
1273 if (err
!= NWAM_SUCCESS
) {
1274 nlog(LOG_ERR
, "failed to delete automatic ncu %s: %s", name
,
1275 nwam_strerror(err
));
1280 * Device represented by NCU has been added or removed for the active
1281 * User NCP. If an associated NCU of the given type is found, transition it
1282 * to the appropriate state.
1285 ncu_action_change_state(nwam_action_t action
, nwam_ncu_type_t type
,
1288 nwamd_object_t ncu_obj
= NULL
;
1291 if ((ncu_obj
= nwamd_ncu_object_find(type
, name
)) == NULL
)
1294 ncu
= ncu_obj
->nwamd_object_data
;
1297 * If device has been added, transition from uninitialized to offline.
1298 * If device has been removed, transition to uninitialized (via online*
1299 * if the NCU is currently enabled in order to tear down config).
1301 if (action
== NWAM_ACTION_ADD
) {
1302 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU
,
1303 ncu_obj
->nwamd_object_name
,
1304 NWAM_STATE_OFFLINE
, NWAM_AUX_STATE_CONDITIONS_NOT_MET
);
1306 if (ncu
->ncu_enabled
) {
1307 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU
,
1308 ncu_obj
->nwamd_object_name
,
1309 NWAM_STATE_ONLINE_TO_OFFLINE
,
1310 NWAM_AUX_STATE_NOT_FOUND
);
1312 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU
,
1313 ncu_obj
->nwamd_object_name
,
1314 NWAM_STATE_UNINITIALIZED
,
1315 NWAM_AUX_STATE_NOT_FOUND
);
1318 nwamd_object_release(ncu_obj
);
1322 * Called with hotplug sysevent or when nwam is started and walking the
1323 * physical interfaces. Add/remove both link and interface NCUs from the
1324 * Automatic NCP. Assumes that both link and interface NCUs don't exist.
1327 nwamd_ncu_handle_link_action_event(nwamd_event_t event
)
1329 nwam_ncp_handle_t ncph
;
1330 nwam_ncu_type_t type
;
1331 nwam_action_t action
=
1332 event
->event_msg
->nwe_data
.nwe_link_action
.nwe_action
;
1335 boolean_t automatic_ncp_active
= B_FALSE
;
1337 if (action
!= NWAM_ACTION_ADD
&& action
!= NWAM_ACTION_REMOVE
) {
1338 nlog(LOG_ERR
, "nwamd_ncu_handle_link_action_event: "
1339 "invalid link action %s", nwam_action_to_string(action
));
1340 nwamd_event_do_not_send(event
);
1344 nlog(LOG_DEBUG
, "nwamd_ncu_handle_link_action_event: "
1345 "link action '%s' event on %s", nwam_action_to_string(action
),
1346 event
->event_object
[0] == 0 ? "n/a" : event
->event_object
);
1348 if ((err
= nwam_ncu_typed_name_to_name(event
->event_object
, &type
,
1349 &name
)) != NWAM_SUCCESS
) {
1350 nlog(LOG_ERR
, "nwamd_ncu_handle_link_action_event: "
1351 "translation from typedname error: %s", nwam_strerror(err
));
1352 nwamd_event_do_not_send(event
);
1356 (void) pthread_mutex_lock(&active_ncp_mutex
);
1357 if (strcmp(active_ncp
, NWAM_NCP_NAME_AUTOMATIC
) == 0 &&
1358 active_ncph
!= NULL
) {
1359 automatic_ncp_active
= B_TRUE
;
1361 (void) pthread_mutex_unlock(&active_ncp_mutex
);
1364 * We could use active_ncph for cases where the Automatic NCP is active,
1365 * but that would involve holding the active_ncp_mutex for too long.
1367 if ((err
= nwam_ncp_read(NWAM_NCP_NAME_AUTOMATIC
, 0, &ncph
))
1368 == NWAM_ENTITY_NOT_FOUND
) {
1369 /* Automatic NCP doesn't exist, create it */
1370 err
= nwam_ncp_create(NWAM_NCP_NAME_AUTOMATIC
, 0, &ncph
);
1372 if (err
!= NWAM_SUCCESS
)
1375 /* add or remove NCUs from Automatic NCP */
1376 if (action
== NWAM_ACTION_ADD
) {
1377 add_phys_ncu_to_ncp(ncph
, name
);
1378 add_ip_ncu_to_ncp(ncph
, name
);
1381 * Order is important here, remove IP NCU first to prevent
1382 * propogation of down event from link to IP. No need to
1383 * create REFRESH or DESTROY events. They are generated by
1384 * nwam_ncu_commit() and nwam_ncu_destroy().
1386 remove_ncu_from_ncp(ncph
, name
, NWAM_NCU_TYPE_INTERFACE
);
1387 remove_ncu_from_ncp(ncph
, name
, NWAM_NCU_TYPE_LINK
);
1389 nwam_ncp_free(ncph
);
1392 * If the Automatic NCP is not active, and the associated NCUs
1393 * exist, they must be moved into the appropriate states given the
1394 * action that has occurred.
1396 if (!automatic_ncp_active
) {
1397 ncu_action_change_state(action
, NWAM_NCU_TYPE_INTERFACE
, name
);
1398 ncu_action_change_state(action
, NWAM_NCU_TYPE_LINK
, name
);
1401 /* Need NCU check to evaluate state in light of added/removed NCUs */
1402 if (!nwamd_event_enqueued(NWAM_EVENT_TYPE_NCU_CHECK
,
1403 NWAM_OBJECT_TYPE_NCP
, NULL
)) {
1404 nwamd_create_ncu_check_event(NEXT_FEW_SECONDS
);
1409 if (err
!= NWAM_SUCCESS
) {
1410 nwamd_event_t retry_event
= nwamd_event_init_link_action(name
,
1412 if (retry_event
== NULL
) {
1413 nlog(LOG_ERR
, "nwamd_ncu_handle_link_action_event: "
1414 "could not create retry event to read/create "
1415 "%s NCP", NWAM_NCP_NAME_AUTOMATIC
);
1419 nlog(LOG_ERR
, "nwamd_ncu_handle_link_action_event: "
1420 "could not read/create %s NCP, retrying in %d seconds",
1421 NWAM_NCP_NAME_AUTOMATIC
, NWAMD_READONLY_RETRY_INTERVAL
);
1422 nwamd_event_enqueue_timed(retry_event
,
1423 NWAMD_READONLY_RETRY_INTERVAL
);
1428 * Figure out if this link is part of an aggregation. This is fairly
1429 * inefficient since we generate this list for every query and search
1430 * linearly. A better way would be to generate the list of links in an
1431 * aggregation once and then check each link against it.
1433 struct link_aggr_search_data
{
1434 datalink_id_t linkid
;
1439 ncu_aggr_search(const char *name
, void *data
)
1441 struct link_aggr_search_data
*lasd
= data
;
1442 dladm_aggr_grp_attr_t ginfo
;
1443 datalink_id_t linkid
;
1446 if (dladm_name2info(dld_handle
, name
, &linkid
, NULL
, NULL
, NULL
) !=
1448 return (DLADM_WALK_CONTINUE
);
1449 if (dladm_aggr_info(dld_handle
, linkid
, &ginfo
, DLADM_OPT_ACTIVE
)
1450 != DLADM_STATUS_OK
|| ginfo
.lg_nports
== 0)
1451 return (DLADM_WALK_CONTINUE
);
1453 for (i
= 0; i
< ginfo
.lg_nports
; i
++) {
1454 if (lasd
->linkid
== ginfo
.lg_ports
[i
].lp_linkid
) {
1455 lasd
->under
= B_TRUE
;
1456 return (DLADM_WALK_TERMINATE
);
1459 free(ginfo
.lg_ports
);
1460 return (DLADM_WALK_CONTINUE
);
1464 nwamd_link_belongs_to_an_aggr(const char *name
)
1466 struct link_aggr_search_data lasd
;
1468 if (dladm_name2info(dld_handle
, name
, &lasd
.linkid
, NULL
, NULL
, NULL
)
1471 lasd
.under
= B_FALSE
;
1472 (void) dladm_walk(ncu_aggr_search
, dld_handle
, &lasd
,
1473 DATALINK_CLASS_AGGR
, DATALINK_ANY_MEDIATYPE
, DLADM_OPT_ACTIVE
);
1474 return (lasd
.under
);
1478 * If NCU doesn't exist for interface with given name, enqueue a ADD
1479 * LINK_ACTION event.
1482 ncu_create_link_action_event(const char *name
, void *data
)
1484 nwam_ncp_handle_t ncph
= data
;
1485 nwam_ncu_handle_t ncuh
;
1486 nwamd_event_t link_event
;
1488 /* Do not generate an event if this is a VirtualBox interface. */
1489 if (strncmp(name
, VBOX_IFACE_PREFIX
, strlen(VBOX_IFACE_PREFIX
)) == 0)
1490 return (DLADM_WALK_CONTINUE
);
1492 /* Do not generate an event if this link belongs to another zone. */
1493 if (!nwamd_link_belongs_to_this_zone(name
))
1494 return (DLADM_WALK_CONTINUE
);
1496 /* Do not generate an event if this link belongs to an aggregation. */
1497 if (nwamd_link_belongs_to_an_aggr(name
)) {
1498 return (DLADM_WALK_CONTINUE
);
1501 /* Don't create an event if the NCU already exists. */
1502 if (ncph
!= NULL
&& nwam_ncu_read(ncph
, name
, NWAM_NCU_TYPE_LINK
, 0,
1503 &ncuh
) == NWAM_SUCCESS
) {
1504 nwam_ncu_free(ncuh
);
1505 return (DLADM_WALK_CONTINUE
);
1508 nlog(LOG_DEBUG
, "ncu_create_link_action_event: adding ncus for %s",
1511 link_event
= nwamd_event_init_link_action(name
, NWAM_ACTION_ADD
);
1512 if (link_event
!= NULL
)
1513 nwamd_event_enqueue(link_event
);
1515 return (DLADM_WALK_CONTINUE
);
1519 * Check if interface exists for this NCU. If not, enqueue a REMOVE
1520 * LINK_ACTION event.
1524 nwamd_destroy_ncu(nwam_ncu_handle_t ncuh
, void *data
)
1528 nwamd_event_t link_event
;
1530 if (nwam_ncu_get_name(ncuh
, &name
) != NWAM_SUCCESS
) {
1531 nlog(LOG_ERR
, "nwamd_destroy_ncu: could not get NCU name");
1535 /* Interfaces that exist return DLADM_OPT_ACTIVE flag */
1536 if ((dladm_name2info(dld_handle
, name
, NULL
, &flags
, NULL
, NULL
)
1537 == DLADM_STATUS_OK
&& (flags
& DLADM_OPT_ACTIVE
)) &&
1538 !nwamd_link_belongs_to_an_aggr(name
)) {
1543 nlog(LOG_DEBUG
, "nwamd_destroy_ncu: destroying ncus for %s", name
);
1545 link_event
= nwamd_event_init_link_action(name
, NWAM_ACTION_REMOVE
);
1546 if (link_event
!= NULL
)
1547 nwamd_event_enqueue(link_event
);
1553 * Called when nwamd is starting up.
1555 * Walk all NCUs and destroy any NCU from the Automatic NCP without an
1556 * underlying interface (assumption here is that the interface was removed
1557 * when nwam was disabled).
1559 * Walk the physical interfaces and create ADD LINK_ACTION event, which
1560 * will create appropriate interface and link NCUs in the Automatic NCP.
1563 nwamd_walk_physical_configuration(void)
1565 nwam_ncp_handle_t ncph
;
1566 datalink_class_t dlclass
= DATALINK_CLASS_PHYS
;
1567 zoneid_t zoneid
= getzoneid();
1569 (void) pthread_mutex_lock(&active_ncp_mutex
);
1570 if (strcmp(active_ncp
, NWAM_NCP_NAME_AUTOMATIC
) == 0 &&
1571 active_ncph
!= NULL
) {
1574 if (nwam_ncp_read(NWAM_NCP_NAME_AUTOMATIC
, 0, &ncph
)
1580 /* destroy NCUs for interfaces that don't exist */
1582 (void) nwam_ncp_walk_ncus(ncph
, nwamd_destroy_ncu
, NULL
,
1583 NWAM_FLAG_NCU_TYPE_LINK
, NULL
);
1586 /* In non-global zones NWAM can support VNICs */
1587 if (zoneid
!= GLOBAL_ZONEID
)
1588 dlclass
|= DATALINK_CLASS_VNIC
;
1590 /* create NCUs for interfaces without NCUs */
1591 (void) dladm_walk(ncu_create_link_action_event
, dld_handle
, ncph
,
1592 dlclass
, DATALINK_ANY_MEDIATYPE
, DLADM_OPT_ACTIVE
);
1594 if (strcmp(active_ncp
, NWAM_NCP_NAME_AUTOMATIC
) != 0 ||
1595 active_ncph
== NULL
) {
1596 nwam_ncp_free(ncph
);
1598 (void) pthread_mutex_unlock(&active_ncp_mutex
);
1602 * Handle NCU initialization/refresh event.
1605 nwamd_ncu_handle_init_event(nwamd_event_t event
)
1607 nwamd_object_t object
= NULL
;
1608 nwam_ncu_handle_t ncuh
;
1609 nwamd_ncu_t
*ncu
= NULL
;
1611 nwam_ncu_type_t type
;
1614 boolean_t
new = B_TRUE
;
1616 nlog(LOG_DEBUG
, "nwamd_ncu_handle_init_event(%s)",
1617 event
->event_object
);
1619 /* Get base linkname rather than interface:linkname or link:linkname */
1620 err
= nwam_ncu_typed_name_to_name(event
->event_object
,
1622 if (err
!= NWAM_SUCCESS
) {
1623 nlog(LOG_ERR
, "nwamd_ncu_handle_init_event: "
1624 "nwam_ncu_typed_name_to_name returned %s",
1625 nwam_strerror(err
));
1626 nwamd_event_do_not_send(event
);
1630 (void) pthread_mutex_lock(&active_ncp_mutex
);
1631 if (active_ncph
== NULL
) {
1633 "nwamd_ncu_handle_init_event: active NCP handle NULL");
1634 nwamd_event_do_not_send(event
);
1636 (void) pthread_mutex_unlock(&active_ncp_mutex
);
1639 err
= nwam_ncu_read(active_ncph
, event
->event_object
,
1641 (void) pthread_mutex_unlock(&active_ncp_mutex
);
1642 if (err
!= NWAM_SUCCESS
) {
1643 nlog(LOG_ERR
, "nwamd_ncu_handle_init_event: "
1644 "could not read object '%s': %s",
1645 event
->event_object
, nwam_strerror(err
));
1647 nwamd_event_do_not_send(event
);
1651 if ((object
= nwamd_object_find(NWAM_OBJECT_TYPE_NCU
,
1652 event
->event_object
)) != NULL
)
1656 * For new NCUs, or interface NCUs, we (re)initialize data from scratch.
1657 * For link NCUs, we want to retain object data.
1660 case NWAM_NCU_TYPE_LINK
:
1662 ncu
= nwamd_ncu_init(type
, name
);
1664 ncu
= object
->nwamd_object_data
;
1665 nwam_ncu_free(object
->nwamd_object_handle
);
1667 populate_common_ncu_properties(ncuh
, ncu
);
1668 populate_link_ncu_properties(ncuh
, ncu
);
1670 case NWAM_NCU_TYPE_INTERFACE
:
1672 nwam_ncu_free(object
->nwamd_object_handle
);
1673 nwamd_ncu_free(object
->nwamd_object_data
);
1675 ncu
= nwamd_ncu_init(type
, name
);
1676 populate_common_ncu_properties(ncuh
, ncu
);
1677 populate_ip_ncu_properties(ncuh
, ncu
);
1680 nlog(LOG_ERR
, "unknown ncu type %d", type
);
1682 nwam_ncu_free(ncuh
);
1683 nwamd_event_do_not_send(event
);
1684 nwamd_object_release(object
);
1689 nlog(LOG_DEBUG
, "nwamd_ncu_handle_init_event: didn't find "
1690 "ncu so create it %s", name
);
1691 object
= nwamd_object_init(NWAM_OBJECT_TYPE_NCU
,
1692 event
->event_object
, ncuh
, ncu
);
1694 nlog(LOG_DEBUG
, "nwamd_ncu_handle_init_event: refreshing "
1696 object
->nwamd_object_data
= ncu
;
1697 object
->nwamd_object_handle
= ncuh
;
1701 * If the physical link for this NCU doesn't exist in the system,
1702 * the state should be UNINITIALIZED/NOT_FOUND. Interfaces that
1703 * exist return DLADM_OPT_ACTIVE flag.
1705 if (dladm_name2info(dld_handle
, name
, NULL
, &flags
, NULL
, NULL
)
1706 != DLADM_STATUS_OK
|| !(flags
& DLADM_OPT_ACTIVE
)) {
1707 nlog(LOG_DEBUG
, "nwam_ncu_handle_init_event: "
1708 "interface for NCU %s doesn't exist",
1709 event
->event_object
);
1710 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU
,
1711 object
->nwamd_object_name
, NWAM_STATE_UNINITIALIZED
,
1712 NWAM_AUX_STATE_NOT_FOUND
);
1714 nwamd_object_release(object
);
1719 * If NCU is being initialized (rather than refreshed), the
1720 * object_state is INITIALIZED (from nwamd_object_init()).
1722 if (object
->nwamd_object_state
== NWAM_STATE_INITIALIZED
) {
1724 * If the NCU is disabled, initial state should be DISABLED.
1726 * Otherwise, the initial state will be
1727 * OFFLINE/CONDITIONS_NOT_MET, and the link selection
1728 * algorithm will do the rest.
1730 if (!ncu
->ncu_enabled
) {
1731 object
->nwamd_object_state
= NWAM_STATE_DISABLED
;
1732 object
->nwamd_object_aux_state
=
1733 NWAM_AUX_STATE_MANUAL_DISABLE
;
1735 object
->nwamd_object_state
= NWAM_STATE_OFFLINE
;
1736 object
->nwamd_object_aux_state
=
1737 NWAM_AUX_STATE_CONDITIONS_NOT_MET
;
1740 nwamd_link_t
*link
= &ncu
->ncu_link
;
1743 * Refresh NCU. Deal with disabled cases first, moving NCUs
1744 * that are not disabled - but have the enabled value set - to
1745 * the disabled state. Then handle cases where the NCU was
1746 * disabled but is no longer. Finally, deal with refresh of
1747 * link and interface NCUs, as these are handled differently.
1749 if (!ncu
->ncu_enabled
) {
1750 if (object
->nwamd_object_state
!= NWAM_STATE_DISABLED
) {
1751 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU
,
1752 object
->nwamd_object_name
,
1753 NWAM_STATE_ONLINE_TO_OFFLINE
,
1754 NWAM_AUX_STATE_MANUAL_DISABLE
);
1758 if (object
->nwamd_object_state
== NWAM_STATE_DISABLED
) {
1762 * Try to activate the NCU if manual or
1763 * prioritized (when priority <= current).
1765 (void) pthread_mutex_lock(&active_ncp_mutex
);
1766 c
= current_ncu_priority_group
;
1767 (void) pthread_mutex_unlock(&active_ncp_mutex
);
1768 if (link
->nwamd_link_activation_mode
==
1769 NWAM_ACTIVATION_MODE_MANUAL
||
1770 (link
->nwamd_link_activation_mode
==
1771 NWAM_ACTIVATION_MODE_PRIORITIZED
&&
1772 link
->nwamd_link_priority_mode
<= c
)) {
1773 nwamd_object_set_state
1774 (NWAM_OBJECT_TYPE_NCU
,
1775 object
->nwamd_object_name
,
1776 NWAM_STATE_OFFLINE_TO_ONLINE
,
1777 NWAM_AUX_STATE_INITIALIZED
);
1779 nwamd_object_set_state
1780 (NWAM_OBJECT_TYPE_NCU
,
1781 object
->nwamd_object_name
,
1782 NWAM_STATE_OFFLINE_TO_ONLINE
,
1783 NWAM_AUX_STATE_INITIALIZED
);
1790 case NWAM_NCU_TYPE_LINK
:
1791 if (ncu
->ncu_link
.nwamd_link_media
== DL_WIFI
) {
1793 * Do rescan. If the current state and the
1794 * active priority-group do not allow wireless
1795 * network selection, then it won't happen.
1797 (void) nwamd_wlan_scan(ncu
->ncu_name
);
1800 case NWAM_NCU_TYPE_INTERFACE
:
1802 * If interface NCU is offline*, online or in
1803 * maintenance, mark it down (from there, it will be
1804 * reinitialized to reapply addresses).
1806 if (object
->nwamd_object_state
!= NWAM_STATE_OFFLINE
) {
1807 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU
,
1808 object
->nwamd_object_name
,
1809 NWAM_STATE_ONLINE_TO_OFFLINE
,
1810 NWAM_AUX_STATE_DOWN
);
1812 object
->nwamd_object_state
= NWAM_STATE_OFFLINE
;
1813 object
->nwamd_object_aux_state
=
1814 NWAM_AUX_STATE_CONDITIONS_NOT_MET
;
1821 if (type
== NWAM_NCU_TYPE_LINK
&&
1822 !nwamd_event_enqueued(NWAM_EVENT_TYPE_NCU_CHECK
,
1823 NWAM_OBJECT_TYPE_NCP
, NULL
)) {
1824 nwamd_create_ncu_check_event(NEXT_FEW_SECONDS
);
1827 nwamd_object_release(object
);
1831 nwamd_ncu_handle_fini_event(nwamd_event_t event
)
1833 nwamd_object_t object
;
1834 nwamd_event_t state_event
;
1836 nlog(LOG_DEBUG
, "nwamd_ncu_handle_fini_event(%s)",
1837 event
->event_object
);
1840 * Simulate a state event so that the state machine can correctly
1841 * disable the NCU. Then free up allocated objects.
1843 state_event
= nwamd_event_init_object_state(NWAM_OBJECT_TYPE_NCU
,
1844 event
->event_object
, NWAM_STATE_ONLINE_TO_OFFLINE
,
1845 NWAM_AUX_STATE_UNINITIALIZED
);
1846 if (state_event
== NULL
) {
1847 nwamd_event_do_not_send(event
);
1850 nwamd_ncu_handle_state_event(state_event
);
1851 nwamd_event_fini(state_event
);
1853 if ((object
= nwamd_object_find(NWAM_OBJECT_TYPE_NCU
,
1854 event
->event_object
)) == NULL
) {
1855 nlog(LOG_INFO
, "nwamd_ncu_handle_fini_event: "
1856 "ncu %s not found", event
->event_object
);
1857 nwamd_event_do_not_send(event
);
1860 nwamd_object_release_and_destroy(object
);
1864 nwamd_ncu_handle_action_event(nwamd_event_t event
)
1866 nwamd_object_t object
;
1868 (void) pthread_mutex_lock(&active_ncp_mutex
);
1869 if (strcmp(event
->event_msg
->nwe_data
.nwe_object_action
.nwe_parent
,
1871 nlog(LOG_DEBUG
, "nwamd_ncu_handle_action_event: action for "
1872 "inactive NCP %s, nothing to do",
1873 event
->event_msg
->nwe_data
.nwe_object_action
.nwe_parent
);
1874 (void) pthread_mutex_unlock(&active_ncp_mutex
);
1877 (void) pthread_mutex_unlock(&active_ncp_mutex
);
1879 switch (event
->event_msg
->nwe_data
.nwe_object_action
.nwe_action
) {
1880 case NWAM_ACTION_ENABLE
:
1881 object
= nwamd_object_find(NWAM_OBJECT_TYPE_NCU
,
1882 event
->event_object
);
1883 if (object
== NULL
) {
1884 nlog(LOG_ERR
, "nwamd_ncu_handle_action_event: "
1885 "could not find ncu %s", event
->event_object
);
1886 nwamd_event_do_not_send(event
);
1889 if (object
->nwamd_object_state
== NWAM_STATE_ONLINE
) {
1890 nlog(LOG_DEBUG
, "nwamd_ncu_handle_action_event: "
1891 "ncu %s already online, nothing to do",
1892 event
->event_object
);
1893 nwamd_object_release(object
);
1896 nwamd_object_release(object
);
1898 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU
,
1899 event
->event_object
, NWAM_STATE_OFFLINE_TO_ONLINE
,
1900 NWAM_AUX_STATE_INITIALIZED
);
1902 case NWAM_ACTION_DISABLE
:
1903 object
= nwamd_object_find(NWAM_OBJECT_TYPE_NCU
,
1904 event
->event_object
);
1905 if (object
== NULL
) {
1906 nlog(LOG_ERR
, "nwamd_ncu_handle_action_event: "
1907 "could not find ncu %s", event
->event_object
);
1908 nwamd_event_do_not_send(event
);
1911 if (object
->nwamd_object_state
== NWAM_STATE_DISABLED
) {
1912 nlog(LOG_DEBUG
, "nwamd_ncu_handle_action_event: "
1913 "ncu %s already disabled, nothing to do",
1914 event
->event_object
);
1915 nwamd_object_release(object
);
1918 nwamd_object_release(object
);
1920 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU
,
1921 event
->event_object
, NWAM_STATE_ONLINE_TO_OFFLINE
,
1922 NWAM_AUX_STATE_MANUAL_DISABLE
);
1924 case NWAM_ACTION_ADD
:
1925 case NWAM_ACTION_REFRESH
:
1926 nwamd_ncu_handle_init_event(event
);
1928 case NWAM_ACTION_DESTROY
:
1929 nwamd_ncu_handle_fini_event(event
);
1932 nlog(LOG_INFO
, "nwam_ncu_handle_action_event: "
1933 "unexpected action");
1934 nwamd_event_do_not_send(event
);
1940 nwamd_ncu_handle_state_event(nwamd_event_t event
)
1942 nwamd_object_t object
;
1943 nwam_state_t old_state
, new_state
;
1944 nwam_aux_state_t new_aux_state
;
1946 boolean_t is_link
, enabled
, prioritized
= B_FALSE
;
1947 char linkname
[NWAM_MAX_NAME_LEN
];
1948 nwam_event_t m
= event
->event_msg
;
1950 if ((object
= nwamd_object_find(NWAM_OBJECT_TYPE_NCU
,
1951 event
->event_object
)) == NULL
) {
1952 nlog(LOG_INFO
, "nwamd_ncu_handle_state_event %lld: "
1953 "state event for nonexistent NCU %s", event
->event_id
,
1954 event
->event_object
);
1955 nwamd_event_do_not_send(event
);
1958 ncu
= object
->nwamd_object_data
;
1959 old_state
= object
->nwamd_object_state
;
1960 new_state
= event
->event_msg
->nwe_data
.nwe_object_state
.nwe_state
;
1962 event
->event_msg
->nwe_data
.nwe_object_state
.nwe_aux_state
;
1965 * For NCU state changes, we need to supply the parent NCP name also,
1966 * regardless of whether the event is handled or not. It is best to
1967 * fill this in here as we have the object lock - when we create
1968 * object state events we sometimes do not have the object lock, but
1969 * at this point in consuming the events (and prior to the associated
1970 * event message being sent out) we do.
1972 (void) strlcpy(m
->nwe_data
.nwe_object_state
.nwe_parent
, ncu
->ncu_parent
,
1973 sizeof (m
->nwe_data
.nwe_object_state
.nwe_parent
));
1976 * If we receive a state change event moving this NCU to
1977 * DHCP_TIMED_OUT or UP state but this NCU is already ONLINE, then
1978 * ignore this state change event.
1980 if ((new_aux_state
== NWAM_AUX_STATE_IF_DHCP_TIMED_OUT
||
1981 new_aux_state
== NWAM_AUX_STATE_UP
) &&
1982 object
->nwamd_object_state
== NWAM_STATE_ONLINE
) {
1983 nlog(LOG_INFO
, "nwamd_ncu_handle_state_event: "
1984 "NCU %s already online, not going to '%s' state",
1985 object
->nwamd_object_name
,
1986 nwam_aux_state_to_string(new_aux_state
));
1987 nwamd_event_do_not_send(event
);
1988 nwamd_object_release(object
);
1992 if (new_state
== object
->nwamd_object_state
&&
1993 new_aux_state
== object
->nwamd_object_aux_state
) {
1994 nlog(LOG_DEBUG
, "nwamd_ncu_handle_state_event: "
1995 "NCU %s already in state (%s, %s)",
1996 object
->nwamd_object_name
, nwam_state_to_string(new_state
),
1997 nwam_aux_state_to_string(new_aux_state
));
1998 nwamd_object_release(object
);
2002 if (old_state
== NWAM_STATE_MAINTENANCE
&&
2003 (new_state
== NWAM_STATE_ONLINE
||
2004 (new_state
== NWAM_STATE_OFFLINE_TO_ONLINE
&&
2005 new_aux_state
!= NWAM_AUX_STATE_INITIALIZED
))) {
2006 nlog(LOG_DEBUG
, "nwamd_ncu_handle_state_event: "
2007 "NCU %s cannot transition from state %s to state (%s, %s)",
2008 object
->nwamd_object_name
, nwam_state_to_string(old_state
),
2009 nwam_state_to_string(new_state
),
2010 nwam_aux_state_to_string(new_aux_state
));
2011 nwamd_event_do_not_send(event
);
2012 nwamd_object_release(object
);
2016 object
->nwamd_object_state
= new_state
;
2017 object
->nwamd_object_aux_state
= new_aux_state
;
2019 nlog(LOG_DEBUG
, "nwamd_ncu_handle_state_event: changing state for NCU "
2020 "%s to (%s, %s)", object
->nwamd_object_name
,
2021 nwam_state_to_string(object
->nwamd_object_state
),
2022 nwam_aux_state_to_string(object
->nwamd_object_aux_state
));
2024 is_link
= (ncu
->ncu_type
== NWAM_NCU_TYPE_LINK
);
2026 (void) strlcpy(linkname
, ncu
->ncu_name
, sizeof (linkname
));
2027 prioritized
= (ncu
->ncu_type
== NWAM_NCU_TYPE_LINK
&&
2028 ncu
->ncu_link
.nwamd_link_activation_mode
==
2029 NWAM_ACTIVATION_MODE_PRIORITIZED
);
2030 enabled
= ncu
->ncu_enabled
;
2032 nwamd_object_release(object
);
2035 * State machine for NCUs
2037 switch (new_state
) {
2038 case NWAM_STATE_OFFLINE_TO_ONLINE
:
2040 nwamd_ncu_state_machine(event
->event_object
);
2042 nlog(LOG_DEBUG
, "nwamd_ncu_handle_state_event: "
2043 "cannot move disabled NCU %s online",
2044 event
->event_object
);
2045 nwamd_event_do_not_send(event
);
2049 case NWAM_STATE_ONLINE_TO_OFFLINE
:
2050 nwamd_ncu_state_machine(event
->event_object
);
2053 case NWAM_STATE_ONLINE
:
2055 * We usually don't need to do anything when we're in the
2056 * ONLINE state. However, for WiFi we can be in INIT or
2057 * SCAN aux states while being ONLINE.
2059 nwamd_ncu_state_machine(event
->event_object
);
2062 case NWAM_STATE_OFFLINE
:
2063 /* Reassess priority group now member is offline */
2065 nwamd_create_ncu_check_event(0);
2069 case NWAM_STATE_DISABLED
:
2070 case NWAM_STATE_UNINITIALIZED
:
2071 case NWAM_STATE_MAINTENANCE
:
2072 case NWAM_STATE_DEGRADED
:
2079 if ((new_state
== NWAM_STATE_ONLINE_TO_OFFLINE
&&
2080 new_aux_state
!= NWAM_AUX_STATE_UNINITIALIZED
&&
2081 new_aux_state
!= NWAM_AUX_STATE_NOT_FOUND
) ||
2082 new_state
== NWAM_STATE_DISABLED
) {
2084 * Going offline, propogate down event to IP NCU. Do
2085 * not propogate event if new aux state is uninitialized
2086 * or not found as these auxiliary states signify
2087 * that an NCP switch/device removal is in progress.
2089 nwamd_propogate_link_up_down_to_ip(linkname
, B_FALSE
);
2091 if (new_state
== NWAM_STATE_ONLINE
) {
2092 /* gone online, propogate up event to IP NCU */
2093 nwamd_propogate_link_up_down_to_ip(linkname
, B_TRUE
);
2096 /* If IP NCU is online, reasses priority group */
2097 if (new_state
== NWAM_STATE_ONLINE
)
2098 nwamd_create_ncu_check_event(0);