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.
24 * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
27 #include <arpa/inet.h>
30 #include <libdlaggr.h>
31 #include <libdllink.h>
32 #include <libdlstat.h>
35 #include <netinet/in.h>
38 #include <sys/param.h>
39 #include <sys/socket.h>
41 #include <sys/types.h>
45 #include "conditions.h"
52 * ncu.c - handles various NCU tasks - intialization/refresh, state machine
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.
64 nwamd_ncu_object_find(nwam_ncu_type_t type
, const char *name
)
68 nwamd_object_t ncu_obj
= NULL
;
70 if ((err
= nwam_ncu_name_to_typed_name(name
, type
, &object_name
))
72 nlog(LOG_ERR
, "nwamd_ncu_find: nwam_ncu_name_to_typed_name "
73 "returned %s", nwam_strerror(err
));
76 ncu_obj
= nwamd_object_find(NWAM_OBJECT_TYPE_NCU
, object_name
);
83 nwamd_set_ncu_string(nwam_ncu_handle_t ncuh
, char **strval
, uint_t cnt
,
89 if ((err
= nwam_value_create_string_array(strval
, cnt
, &val
))
92 err
= nwam_ncu_set_prop_value(ncuh
, prop
, val
);
98 nwamd_set_ncu_uint(nwam_ncu_handle_t ncuh
, uint64_t *uintval
, uint_t cnt
,
104 if ((err
= nwam_value_create_uint64_array(uintval
, cnt
, &val
))
107 err
= nwam_ncu_set_prop_value(ncuh
, prop
, val
);
108 nwam_value_free(val
);
113 nwamd_get_ncu_string(nwam_ncu_handle_t ncuh
, nwam_value_t
*val
, char ***strval
,
114 uint_t
*cnt
, const char *prop
)
118 if ((err
= nwam_ncu_get_prop_value(ncuh
, prop
, val
)) != NWAM_SUCCESS
)
120 return (nwam_value_get_string_array(*val
, strval
, cnt
));
124 nwamd_get_ncu_uint(nwam_ncu_handle_t ncuh
, nwam_value_t
*val
,
125 uint64_t **uintval
, uint_t
*cnt
, const char *prop
)
129 if ((err
= nwam_ncu_get_prop_value(ncuh
, prop
, val
)) != NWAM_SUCCESS
)
131 return (nwam_value_get_uint64_array(*val
, uintval
, cnt
));
135 nwamd_get_ncu_boolean(nwam_ncu_handle_t ncuh
, nwam_value_t
*val
,
136 boolean_t
**boolval
, uint_t
*cnt
, const char *prop
)
140 if ((err
= nwam_ncu_get_prop_value(ncuh
, prop
, val
)) != NWAM_SUCCESS
)
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.
150 nwamd_ncu_state_machine(const char *object_name
)
152 nwamd_object_t object
;
154 link_state_t link_state
;
156 nwam_wlan_t key_wlan
, connected_wlan
;
158 char linkname
[NWAM_MAX_NAME_LEN
];
161 if ((object
= nwamd_object_find(NWAM_OBJECT_TYPE_NCU
, object_name
))
163 nlog(LOG_ERR
, "nwamd_ncu_state_machine: "
164 "request for nonexistent NCU %s", object_name
);
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
180 nwamd_dlpi_add_link(object
);
182 if (link
->nwamd_link_media
== DL_WIFI
) {
184 * First, if we're unexpectedly connected,
187 if (!link
->nwamd_link_wifi_connected
&&
188 nwamd_wlan_connected(object
)) {
190 "nwamd_ncu_state_machine: "
191 "WiFi unexpectedly connected, "
193 (void) dladm_wlan_disconnect(dld_handle
,
194 link
->nwamd_link_id
);
195 nwamd_set_selected_connected(ncu
,
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
);
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
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
,
217 nwamd_object_set_state
218 (NWAM_OBJECT_TYPE_NCU
,
220 NWAM_STATE_ONLINE_TO_OFFLINE
,
221 NWAM_AUX_STATE_DOWN
);
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
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
,
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
);
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.
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
);
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
);
294 nwamd_event_enqueue(event
);
295 nwamd_set_selected_connected(ncu
, B_FALSE
, B_FALSE
);
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
,
320 nwamd_event_enqueue(event
);
323 case NWAM_AUX_STATE_LINK_WIFI_CONNECTING
:
324 (void) strlcpy(linkname
, ncu
->ncu_name
, sizeof (linkname
));
325 nwamd_wlan_connect(linkname
);
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
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
350 NWAM_EVENT_TYPE_WLAN_CONNECTION_REPORT
, up
,
354 nwamd_event_enqueue(event
);
357 * If disconnected, restart the state machine
358 * for the WiFi link (WiFi is always trying
361 * If connected, start signal strength
364 if (!up
&& ncu
->ncu_enabled
) {
366 "nwamd_ncu_state_machine: "
367 "wifi disconnect - start over "
368 "after %dsec interval",
369 WIRELESS_RETRY_INTERVAL
);
370 link
->nwamd_link_wifi_connected
=
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
);
382 "nwamd_ncu_state_machine: "
383 "wifi connected, start monitoring");
384 (void) strlcpy(linkname
, ncu
->ncu_name
,
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
,
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
) {
405 * Moving online, add v4/v6 default
408 nwamd_add_default_routes(ncu
);
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
416 nwamd_object_set_state
417 (NWAM_OBJECT_TYPE_NCU
, object_name
,
418 NWAM_STATE_OFFLINE_TO_ONLINE
,
419 NWAM_AUX_STATE_INITIALIZED
);
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
432 nwamd_create_triggered_condition_check_event(NEXT_FEW_SECONDS
);
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
,
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
);
466 case NWAM_AUX_STATE_MANUAL_DISABLE
:
467 /* Manual disable, set enabled state appropriately. */
468 ncu
->ncu_enabled
= B_FALSE
;
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
,
484 nwamd_dlpi_delete_link(object
);
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
;
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
);
517 nlog(LOG_ERR
, "nwamd_ncu_state_machine: unexpected state");
521 nwamd_object_release(object
);
525 ncu_create_init_fini_event(nwam_ncu_handle_t ncuh
, void *data
)
527 boolean_t
*init
= data
;
528 char *name
, *typedname
;
530 nwam_value_t typeval
= NULL
;
533 nwamd_event_t ncu_event
;
535 if (nwam_ncu_get_name(ncuh
, &name
) != NWAM_SUCCESS
) {
537 "ncu_create_init_fini_event: could not get NCU name");
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
));
548 nwam_value_free(typeval
);
552 /* convert name to typedname for event */
553 if ((err
= nwam_ncu_name_to_typed_name(name
, *type
, &typedname
))
555 nlog(LOG_ERR
, "ncu_create_init_fini_event: "
556 "NCU name translation failed: %s", nwam_strerror(err
));
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
);
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.
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
,
591 (void) pthread_mutex_unlock(&active_ncp_mutex
);
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",
604 (void) nwam_ncp_walk_ncus(active_ncph
,
605 ncu_create_init_fini_event
, &init
, NWAM_FLAG_NCU_TYPE_ALL
,
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.
616 populate_common_ncu_properties(nwam_ncu_handle_t ncuh
, nwamd_ncu_t
*ncu_data
)
618 nwam_value_t ncu_prop
;
620 boolean_t enablevalue
;
624 if ((err
= nwam_ncu_get_prop_value(ncuh
, NWAM_NCU_PROP_ENABLED
,
625 &ncu_prop
)) != NWAM_SUCCESS
) {
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
));
632 ncu_data
->ncu_enabled
= B_TRUE
;
634 if ((err
= nwam_value_get_boolean(ncu_prop
, &enablevalue
)) !=
636 nlog(LOG_ERR
, "nwam_value_get_boolean ENABLED failed: "
637 "%s", nwam_strerror(err
));
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
));
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.
659 populate_link_ncu_properties(nwam_ncu_handle_t ncuh
, nwamd_ncu_t
*ncu_data
)
661 nwam_value_t ncu_prop
;
667 /* activation-mode */
668 if ((err
= nwamd_get_ncu_uint(ncuh
, &ncu_prop
, &uintval
, &numvalues
,
669 NWAM_NCU_PROP_ACTIVATION_MODE
)) != NWAM_SUCCESS
) {
671 "populate_link_ncu_properties: could not get %s value: %s",
672 NWAM_NCU_PROP_ACTIVATION_MODE
, nwam_strerror(err
));
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
))
686 nlog(LOG_ERR
, "populate_link_ncu_properties: "
687 "could not get %s value: %s",
688 NWAM_NCU_PROP_PRIORITY_MODE
, nwam_strerror(err
));
690 ncu_data
->ncu_link
.nwamd_link_priority_mode
=
692 nwam_value_free(ncu_prop
);
695 if ((err
= nwamd_get_ncu_uint(ncuh
, &ncu_prop
, &uintval
,
696 &numvalues
, NWAM_NCU_PROP_PRIORITY_GROUP
))
698 nlog(LOG_ERR
, "populate_link_ncu_properties: "
699 "could not get %s value: %s",
700 NWAM_NCU_PROP_PRIORITY_GROUP
, nwam_strerror(err
));
702 ncu_data
->ncu_link
.nwamd_link_priority_group
=
704 nwam_value_free(ncu_prop
);
709 if ((err
= nwamd_get_ncu_string(ncuh
, &ncu_prop
, &mac_addr
, &numvalues
,
710 NWAM_NCU_PROP_LINK_MAC_ADDR
)) != NWAM_SUCCESS
) {
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
;
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
);
722 if ((err
= nwamd_get_ncu_uint(ncuh
, &ncu_prop
, &uintval
, &numvalues
,
723 NWAM_NCU_PROP_LINK_MTU
)) != NWAM_SUCCESS
) {
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;
729 ncu_data
->ncu_link
.nwamd_link_mtu
= uintval
[0];
730 nwam_value_free(ncu_prop
);
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
) {
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;
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
;
754 ipadm_addrobj_t ipaddr
;
755 ipadm_status_t ipstatus
;
756 char **addrvalue
, ipreqhost
[MAXNAMELEN
];
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
;
770 if ((err
= nwamd_get_ncu_uint(ncuh
, &ncu_prop
, &ipversion
, &numvalues
,
771 NWAM_NCU_PROP_IP_VERSION
)) != NWAM_SUCCESS
) {
773 "populate_ip_ncu_properties: could not get %s value: %s",
774 NWAM_NCU_PROP_IP_VERSION
, nwam_strerror(err
));
776 for (i
= 0; i
< numvalues
; i
++) {
777 switch (ipversion
[i
]) {
779 nif
->nwamd_if_ipv4
= B_TRUE
;
782 nif
->nwamd_if_ipv6
= B_TRUE
;
785 nlog(LOG_ERR
, "bogus ip version %lld",
790 nwam_value_free(ncu_prop
);
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
));
802 dhcp_primary
= boolvalue
[0];
803 nwam_value_free(ncu_prop
);
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
));
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]);
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
;
830 ipadm_destroy_addrobj(nifai
->ipaddr
);
833 nif
->nwamd_if_list
= NULL
;
834 nifa
= &(nif
->nwamd_if_list
);
836 if (!nif
->nwamd_if_ipv4
)
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
));
846 for (i
= 0; i
< numvalues
; i
++) {
847 switch (addrsrcvalue
[i
]) {
848 case NWAM_ADDRSRC_DHCP
:
849 nif
->nwamd_if_dhcp_requested
= B_TRUE
;
851 case NWAM_ADDRSRC_STATIC
:
852 static_addr
= B_TRUE
;
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
));
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
);
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
);
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
);
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
);
901 nlog(LOG_ERR
, "populate_ip_ncu_properties: "
902 "couldn't allocate nwamd address for v4 dhcp: %s",
904 ipadm_destroy_addrobj(ipaddr
);
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
));
917 for (i
= 0; i
< numvalues
; i
++) {
918 ipstatus
= ipadm_create_addrobj(
919 IPADM_ADDR_STATIC
, ncu_data
->ncu_name
,
921 if (ipstatus
!= IPADM_SUCCESS
) {
923 "populate_ip_ncu_properties: "
924 "ipadm_create_addrobj failed "
925 "for %s: %s", addrvalue
[i
],
926 ipadm_status2str(ipstatus
));
929 /* ipadm_set_addr takes <addr>[/<mask>] */
930 ipstatus
= ipadm_set_addr(ipaddr
, addrvalue
[i
],
932 if (ipstatus
!= IPADM_SUCCESS
) {
934 "populate_ip_ncu_properties: "
935 "ipadm_set_addr failed for %s: %s",
937 ipadm_status2str(ipstatus
));
938 ipadm_destroy_addrobj(ipaddr
);
942 if ((*nifa
= calloc(sizeof (**nifa
), 1))
944 (*nifa
)->family
= AF_INET
;
945 (*nifa
)->ipaddr_atype
=
947 (*nifa
)->ipaddr
= ipaddr
;
948 nifa
= &((*nifa
)->next
);
951 "populate_ip_ncu_properties: "
952 "couldn't allocate nwamd address "
953 "for %s: %s", addrvalue
[i
],
955 ipadm_destroy_addrobj(ipaddr
);
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
);
976 if (!nif
->nwamd_if_ipv6
)
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
));
987 for (i
= 0; i
< numvalues
; i
++) {
988 switch (addrsrcvalue
[i
]) {
989 case NWAM_ADDRSRC_DHCP
:
990 nif
->nwamd_if_stateful_requested
= B_TRUE
;
992 case NWAM_ADDRSRC_AUTOCONF
:
993 nif
->nwamd_if_stateless_requested
= B_TRUE
;
995 case NWAM_ADDRSRC_STATIC
:
996 static_addr
= B_TRUE
;
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
);
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
);
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
));
1064 for (i
= 0; i
< numvalues
; i
++) {
1065 ipstatus
= ipadm_create_addrobj(
1066 IPADM_ADDR_STATIC
, ncu_data
->ncu_name
,
1068 if (ipstatus
!= IPADM_SUCCESS
) {
1070 "populate_ip_ncu_properties: "
1071 "ipadm_create_addrobj failed "
1072 "for %s: %s", addrvalue
[i
],
1073 ipadm_status2str(ipstatus
));
1076 /* ipadm_set_addr takes <addr>[/<mask>] */
1077 ipstatus
= ipadm_set_addr(ipaddr
, addrvalue
[i
],
1079 if (ipstatus
!= IPADM_SUCCESS
) {
1081 "populate_ip_ncu_properties: "
1082 "ipadm_set_addr failed for %s: %s",
1084 ipadm_status2str(ipstatus
));
1085 ipadm_destroy_addrobj(ipaddr
);
1089 if ((*nifa
= calloc(sizeof (**nifa
), 1))
1091 (*nifa
)->family
= AF_INET6
;
1092 (*nifa
)->ipaddr_atype
=
1094 (*nifa
)->ipaddr
= ipaddr
;
1095 nifa
= &((*nifa
)->next
);
1098 "populate_ip_ncu_properties: "
1099 "couldn't allocate nwamd address "
1100 "for %s: %s", addrvalue
[i
],
1102 ipadm_destroy_addrobj(ipaddr
);
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
);
1126 static nwamd_ncu_t
*
1127 nwamd_ncu_init(nwam_ncu_type_t ncu_type
, const char *name
)
1131 nlog(LOG_DEBUG
, "nwamd_ncu_init(%d, %s)", ncu_type
, name
);
1133 if ((rv
= calloc(1, sizeof (*rv
))) == 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
;
1150 (void) bzero(&rv
->ncu_if
, sizeof (nwamd_if_t
));
1157 nwamd_ncu_free(nwamd_ncu_t
*ncu
)
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
;
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
;
1179 ipadm_destroy_addrobj(n
->ipaddr
);
1183 free(ncu
->ncu_name
);
1189 nwamd_ncu_display(nwamd_object_t ncu_obj
, void *data
)
1191 nwamd_ncu_t
*ncu
= (nwamd_ncu_t
*)ncu_obj
->nwamd_object_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
));
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
,
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
)
1215 nwamd_event_enqueue(ncu_event
);
1220 add_phys_ncu_to_ncp(nwam_ncp_handle_t ncph
, const char *name
)
1222 dladm_status_t dlrtn
;
1224 boolean_t is_wireless
;
1226 nwam_ncu_handle_t ncuh
;
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
));
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
1249 nlog(LOG_DEBUG
, "Retrying addition of phys ncu for %s",
1251 retry_event
= nwamd_event_init_link_action(name
,
1253 if (retry_event
!= NULL
) {
1254 nwamd_event_enqueue_timed(retry_event
,
1255 NWAMD_READONLY_RETRY_INTERVAL
);
1261 uintval
= NWAM_ACTIVATION_MODE_PRIORITIZED
;
1262 if ((err
= nwamd_set_ncu_uint(ncuh
, &uintval
, 1,
1263 NWAM_NCU_PROP_ACTIVATION_MODE
)) != NWAM_SUCCESS
) {
1267 uintval
= is_wireless
? 1 : 0;
1268 if ((err
= nwamd_set_ncu_uint(ncuh
, &uintval
, 1,
1269 NWAM_NCU_PROP_PRIORITY_GROUP
)) != NWAM_SUCCESS
) {
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
) {
1280 err
= nwam_ncu_commit(ncuh
, 0);
1283 nwam_ncu_free(ncuh
);
1284 if (err
!= NWAM_SUCCESS
) {
1286 "failed to create automatic link ncu for %s: %s",
1287 name
, nwam_strerror(err
));
1292 add_ip_ncu_to_ncp(nwam_ncp_handle_t ncph
, const char *name
)
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()
1310 /* IP NCU has the default values, so nothing else to do */
1311 err
= nwam_ncu_commit(ncuh
, 0);
1314 nwam_ncu_free(ncuh
);
1315 if (err
!= NWAM_SUCCESS
) {
1317 "failed to create ip ncu for %s: %s", name
,
1318 nwam_strerror(err
));
1323 remove_ncu_from_ncp(nwam_ncp_handle_t ncph
, const char *name
,
1324 nwam_ncu_type_t type
)
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
));
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.
1348 ncu_action_change_state(nwam_action_t action
, nwam_ncu_type_t type
,
1351 nwamd_object_t ncu_obj
= NULL
;
1354 if ((ncu_obj
= nwamd_ncu_object_find(type
, name
)) == NULL
)
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
);
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
);
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.
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
;
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
);
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
);
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
)
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
);
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
);
1472 if (err
!= NWAM_SUCCESS
) {
1473 nwamd_event_t retry_event
= nwamd_event_init_link_action(name
,
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
);
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
;
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
;
1509 if (dladm_name2info(dld_handle
, name
, &linkid
, NULL
, NULL
, NULL
) !=
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
);
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
)
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.
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",
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.
1587 nwamd_destroy_ncu(nwam_ncu_handle_t ncuh
, void *data
)
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");
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
)) {
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
);
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.
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
) {
1637 if (nwam_ncp_read(NWAM_NCP_NAME_AUTOMATIC
, 0, &ncph
)
1643 /* destroy NCUs for interfaces that don't exist */
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.
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
;
1674 nwam_ncu_type_t type
;
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
,
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
);
1693 (void) pthread_mutex_lock(&active_ncp_mutex
);
1694 if (active_ncph
== NULL
) {
1696 "nwamd_ncu_handle_init_event: active NCP handle NULL");
1697 nwamd_event_do_not_send(event
);
1699 (void) pthread_mutex_unlock(&active_ncp_mutex
);
1702 err
= nwam_ncu_read(active_ncph
, event
->event_object
,
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
));
1710 nwamd_event_do_not_send(event
);
1714 if ((object
= nwamd_object_find(NWAM_OBJECT_TYPE_NCU
,
1715 event
->event_object
)) != NULL
)
1719 * For new NCUs, or interface NCUs, we (re)initialize data from scratch.
1720 * For link NCUs, we want to retain object data.
1723 case NWAM_NCU_TYPE_LINK
:
1725 ncu
= nwamd_ncu_init(type
, name
);
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
);
1733 case NWAM_NCU_TYPE_INTERFACE
:
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
);
1743 nlog(LOG_ERR
, "unknown ncu type %d", type
);
1745 nwam_ncu_free(ncuh
);
1746 nwamd_event_do_not_send(event
);
1747 nwamd_object_release(object
);
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
);
1757 nlog(LOG_DEBUG
, "nwamd_ncu_handle_init_event: refreshing "
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
);
1777 nwamd_object_release(object
);
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
;
1798 object
->nwamd_object_state
= NWAM_STATE_OFFLINE
;
1799 object
->nwamd_object_aux_state
=
1800 NWAM_AUX_STATE_CONDITIONS_NOT_MET
;
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
);
1821 if (object
->nwamd_object_state
== NWAM_STATE_DISABLED
) {
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
);
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
);
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
);
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
);
1875 object
->nwamd_object_state
= NWAM_STATE_OFFLINE
;
1876 object
->nwamd_object_aux_state
=
1877 NWAM_AUX_STATE_CONDITIONS_NOT_MET
;
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
);
1890 nwamd_object_release(object
);
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
);
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
);
1923 nwamd_object_release_and_destroy(object
);
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
,
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
);
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
);
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
);
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
);
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
);
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
);
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
);
1987 case NWAM_ACTION_ADD
:
1988 case NWAM_ACTION_REFRESH
:
1989 nwamd_ncu_handle_init_event(event
);
1991 case NWAM_ACTION_DESTROY
:
1992 nwamd_ncu_handle_fini_event(event
);
1995 nlog(LOG_INFO
, "nwam_ncu_handle_action_event: "
1996 "unexpected action");
1997 nwamd_event_do_not_send(event
);
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
;
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
);
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
;
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
);
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
);
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
);
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
);
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
:
2103 nwamd_ncu_state_machine(event
->event_object
);
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
);
2112 case NWAM_STATE_ONLINE_TO_OFFLINE
:
2113 nwamd_ncu_state_machine(event
->event_object
);
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
);
2125 case NWAM_STATE_OFFLINE
:
2126 /* Reassess priority group now member is offline */
2128 nwamd_create_ncu_check_event(0);
2132 case NWAM_STATE_DISABLED
:
2133 case NWAM_STATE_UNINITIALIZED
:
2134 case NWAM_STATE_MAINTENANCE
:
2135 case NWAM_STATE_DEGRADED
:
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
);
2159 /* If IP NCU is online, reasses priority group */
2160 if (new_state
== NWAM_STATE_ONLINE
)
2161 nwamd_create_ncu_check_event(0);