xref: /illumos-gate/usr/src/cmd/cmd-inet/lib/nwamd/ncu.c (revision 6ba597c5)
1*6ba597c5SAnurag S. Maskey /*
2*6ba597c5SAnurag S. Maskey  * CDDL HEADER START
3*6ba597c5SAnurag S. Maskey  *
4*6ba597c5SAnurag S. Maskey  * The contents of this file are subject to the terms of the
5*6ba597c5SAnurag S. Maskey  * Common Development and Distribution License (the "License").
6*6ba597c5SAnurag S. Maskey  * You may not use this file except in compliance with the License.
7*6ba597c5SAnurag S. Maskey  *
8*6ba597c5SAnurag S. Maskey  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*6ba597c5SAnurag S. Maskey  * or http://www.opensolaris.org/os/licensing.
10*6ba597c5SAnurag S. Maskey  * See the License for the specific language governing permissions
11*6ba597c5SAnurag S. Maskey  * and limitations under the License.
12*6ba597c5SAnurag S. Maskey  *
13*6ba597c5SAnurag S. Maskey  * When distributing Covered Code, include this CDDL HEADER in each
14*6ba597c5SAnurag S. Maskey  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*6ba597c5SAnurag S. Maskey  * If applicable, add the following below this CDDL HEADER, with the
16*6ba597c5SAnurag S. Maskey  * fields enclosed by brackets "[]" replaced with your own identifying
17*6ba597c5SAnurag S. Maskey  * information: Portions Copyright [yyyy] [name of copyright owner]
18*6ba597c5SAnurag S. Maskey  *
19*6ba597c5SAnurag S. Maskey  * CDDL HEADER END
20*6ba597c5SAnurag S. Maskey  */
21*6ba597c5SAnurag S. Maskey 
22*6ba597c5SAnurag S. Maskey /*
23*6ba597c5SAnurag S. Maskey  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24*6ba597c5SAnurag S. Maskey  * Use is subject to license terms.
25*6ba597c5SAnurag S. Maskey  */
26*6ba597c5SAnurag S. Maskey 
27*6ba597c5SAnurag S. Maskey #include <arpa/inet.h>
28*6ba597c5SAnurag S. Maskey #include <assert.h>
29*6ba597c5SAnurag S. Maskey #include <libdlaggr.h>
30*6ba597c5SAnurag S. Maskey #include <libdllink.h>
31*6ba597c5SAnurag S. Maskey #include <libdlstat.h>
32*6ba597c5SAnurag S. Maskey #include <libnwam.h>
33*6ba597c5SAnurag S. Maskey #include <libscf.h>
34*6ba597c5SAnurag S. Maskey #include <netinet/in.h>
35*6ba597c5SAnurag S. Maskey #include <stdlib.h>
36*6ba597c5SAnurag S. Maskey #include <strings.h>
37*6ba597c5SAnurag S. Maskey #include <sys/socket.h>
38*6ba597c5SAnurag S. Maskey #include <sys/time.h>
39*6ba597c5SAnurag S. Maskey #include <sys/types.h>
40*6ba597c5SAnurag S. Maskey #include <values.h>
41*6ba597c5SAnurag S. Maskey 
42*6ba597c5SAnurag S. Maskey #include "conditions.h"
43*6ba597c5SAnurag S. Maskey #include "events.h"
44*6ba597c5SAnurag S. Maskey #include "objects.h"
45*6ba597c5SAnurag S. Maskey #include "ncp.h"
46*6ba597c5SAnurag S. Maskey #include "util.h"
47*6ba597c5SAnurag S. Maskey 
48*6ba597c5SAnurag S. Maskey /*
49*6ba597c5SAnurag S. Maskey  * ncu.c - handles various NCU tasks - intialization/refresh, state machine
50*6ba597c5SAnurag S. Maskey  * for NCUs etc.
51*6ba597c5SAnurag S. Maskey  */
52*6ba597c5SAnurag S. Maskey 
53*6ba597c5SAnurag S. Maskey #define	VBOX_IFACE_PREFIX	"vboxnet"
54*6ba597c5SAnurag S. Maskey 
55*6ba597c5SAnurag S. Maskey /*
56*6ba597c5SAnurag S. Maskey  * Find ncu of specified type for link/interface name.
57*6ba597c5SAnurag S. Maskey  */
58*6ba597c5SAnurag S. Maskey nwamd_object_t
59*6ba597c5SAnurag S. Maskey nwamd_ncu_object_find(nwam_ncu_type_t type, const char *name)
60*6ba597c5SAnurag S. Maskey {
61*6ba597c5SAnurag S. Maskey 	nwam_error_t err;
62*6ba597c5SAnurag S. Maskey 	char *object_name;
63*6ba597c5SAnurag S. Maskey 	nwamd_object_t ncu_obj = NULL;
64*6ba597c5SAnurag S. Maskey 
65*6ba597c5SAnurag S. Maskey 	if ((err = nwam_ncu_name_to_typed_name(name, type, &object_name))
66*6ba597c5SAnurag S. Maskey 	    != NWAM_SUCCESS) {
67*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_ncu_find: nwam_ncu_name_to_typed_name "
68*6ba597c5SAnurag S. Maskey 		    "returned %s", nwam_strerror(err));
69*6ba597c5SAnurag S. Maskey 		return (NULL);
70*6ba597c5SAnurag S. Maskey 	}
71*6ba597c5SAnurag S. Maskey 	ncu_obj = nwamd_object_find(NWAM_OBJECT_TYPE_NCU, object_name);
72*6ba597c5SAnurag S. Maskey 
73*6ba597c5SAnurag S. Maskey 	free(object_name);
74*6ba597c5SAnurag S. Maskey 	return (ncu_obj);
75*6ba597c5SAnurag S. Maskey }
76*6ba597c5SAnurag S. Maskey 
77*6ba597c5SAnurag S. Maskey nwam_error_t
78*6ba597c5SAnurag S. Maskey nwamd_set_ncu_string(nwam_ncu_handle_t ncuh, char **strval, uint_t cnt,
79*6ba597c5SAnurag S. Maskey     const char *prop)
80*6ba597c5SAnurag S. Maskey {
81*6ba597c5SAnurag S. Maskey 	nwam_error_t err;
82*6ba597c5SAnurag S. Maskey 	nwam_value_t val;
83*6ba597c5SAnurag S. Maskey 
84*6ba597c5SAnurag S. Maskey 	if ((err = nwam_value_create_string_array(strval, cnt, &val))
85*6ba597c5SAnurag S. Maskey 	    != NWAM_SUCCESS)
86*6ba597c5SAnurag S. Maskey 		return (err);
87*6ba597c5SAnurag S. Maskey 	err = nwam_ncu_set_prop_value(ncuh, prop, val);
88*6ba597c5SAnurag S. Maskey 	nwam_value_free(val);
89*6ba597c5SAnurag S. Maskey 	return (err);
90*6ba597c5SAnurag S. Maskey }
91*6ba597c5SAnurag S. Maskey 
92*6ba597c5SAnurag S. Maskey nwam_error_t
93*6ba597c5SAnurag S. Maskey nwamd_set_ncu_uint(nwam_ncu_handle_t ncuh, uint64_t *uintval, uint_t cnt,
94*6ba597c5SAnurag S. Maskey     const char *prop)
95*6ba597c5SAnurag S. Maskey {
96*6ba597c5SAnurag S. Maskey 	nwam_error_t err;
97*6ba597c5SAnurag S. Maskey 	nwam_value_t val;
98*6ba597c5SAnurag S. Maskey 
99*6ba597c5SAnurag S. Maskey 	if ((err = nwam_value_create_uint64_array(uintval, cnt, &val))
100*6ba597c5SAnurag S. Maskey 	    != NWAM_SUCCESS)
101*6ba597c5SAnurag S. Maskey 		return (err);
102*6ba597c5SAnurag S. Maskey 	err = nwam_ncu_set_prop_value(ncuh, prop, val);
103*6ba597c5SAnurag S. Maskey 	nwam_value_free(val);
104*6ba597c5SAnurag S. Maskey 	return (err);
105*6ba597c5SAnurag S. Maskey }
106*6ba597c5SAnurag S. Maskey 
107*6ba597c5SAnurag S. Maskey nwam_error_t
108*6ba597c5SAnurag S. Maskey nwamd_get_ncu_string(nwam_ncu_handle_t ncuh, nwam_value_t *val, char ***strval,
109*6ba597c5SAnurag S. Maskey     uint_t *cnt, const char *prop)
110*6ba597c5SAnurag S. Maskey {
111*6ba597c5SAnurag S. Maskey 	nwam_error_t err;
112*6ba597c5SAnurag S. Maskey 
113*6ba597c5SAnurag S. Maskey 	if ((err = nwam_ncu_get_prop_value(ncuh, prop, val)) != NWAM_SUCCESS)
114*6ba597c5SAnurag S. Maskey 		return (err);
115*6ba597c5SAnurag S. Maskey 	return (nwam_value_get_string_array(*val, strval, cnt));
116*6ba597c5SAnurag S. Maskey }
117*6ba597c5SAnurag S. Maskey 
118*6ba597c5SAnurag S. Maskey nwam_error_t
119*6ba597c5SAnurag S. Maskey nwamd_get_ncu_uint(nwam_ncu_handle_t ncuh, nwam_value_t *val,
120*6ba597c5SAnurag S. Maskey     uint64_t **uintval, uint_t *cnt, const char *prop)
121*6ba597c5SAnurag S. Maskey {
122*6ba597c5SAnurag S. Maskey 	nwam_error_t err;
123*6ba597c5SAnurag S. Maskey 
124*6ba597c5SAnurag S. Maskey 	if ((err = nwam_ncu_get_prop_value(ncuh, prop, val)) != NWAM_SUCCESS)
125*6ba597c5SAnurag S. Maskey 		return (err);
126*6ba597c5SAnurag S. Maskey 	return (nwam_value_get_uint64_array(*val, uintval, cnt));
127*6ba597c5SAnurag S. Maskey }
128*6ba597c5SAnurag S. Maskey 
129*6ba597c5SAnurag S. Maskey /*
130*6ba597c5SAnurag S. Maskey  * Run link/interface state machine in response to a state change
131*6ba597c5SAnurag S. Maskey  * or enable/disable action event.
132*6ba597c5SAnurag S. Maskey  */
133*6ba597c5SAnurag S. Maskey static void
134*6ba597c5SAnurag S. Maskey nwamd_ncu_state_machine(const char *object_name)
135*6ba597c5SAnurag S. Maskey {
136*6ba597c5SAnurag S. Maskey 	nwamd_object_t object;
137*6ba597c5SAnurag S. Maskey 	nwamd_ncu_t *ncu;
138*6ba597c5SAnurag S. Maskey 	link_state_t link_state;
139*6ba597c5SAnurag S. Maskey 	nwamd_event_t event;
140*6ba597c5SAnurag S. Maskey 	nwam_wlan_t key_wlan, connected_wlan;
141*6ba597c5SAnurag S. Maskey 	nwamd_link_t *link;
142*6ba597c5SAnurag S. Maskey 	char linkname[NWAM_MAX_NAME_LEN];
143*6ba597c5SAnurag S. Maskey 	boolean_t up;
144*6ba597c5SAnurag S. Maskey 
145*6ba597c5SAnurag S. Maskey 	if ((object = nwamd_object_find(NWAM_OBJECT_TYPE_NCU, object_name))
146*6ba597c5SAnurag S. Maskey 	    == NULL) {
147*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_ncu_state_machine: "
148*6ba597c5SAnurag S. Maskey 		    "request for nonexistent NCU %s", object_name);
149*6ba597c5SAnurag S. Maskey 		return;
150*6ba597c5SAnurag S. Maskey 	}
151*6ba597c5SAnurag S. Maskey 
152*6ba597c5SAnurag S. Maskey 	ncu = object->nwamd_object_data;
153*6ba597c5SAnurag S. Maskey 	link = &ncu->ncu_node.u_link;
154*6ba597c5SAnurag S. Maskey 
155*6ba597c5SAnurag S. Maskey 	switch (object->nwamd_object_aux_state) {
156*6ba597c5SAnurag S. Maskey 	case NWAM_AUX_STATE_INITIALIZED:
157*6ba597c5SAnurag S. Maskey 		if (ncu->ncu_type == NWAM_NCU_TYPE_LINK) {
158*6ba597c5SAnurag S. Maskey 			/*
159*6ba597c5SAnurag S. Maskey 			 * For wired/wireless links, need to get link
160*6ba597c5SAnurag S. Maskey 			 * up/down events and even if these are not supported,
161*6ba597c5SAnurag S. Maskey 			 * dlpi_open()ing the link prevents the driver from
162*6ba597c5SAnurag S. Maskey 			 * being unloaded.
163*6ba597c5SAnurag S. Maskey 			 */
164*6ba597c5SAnurag S. Maskey 			nwamd_dlpi_add_link(object);
165*6ba597c5SAnurag S. Maskey 
166*6ba597c5SAnurag S. Maskey 			if (link->nwamd_link_media == DL_WIFI) {
167*6ba597c5SAnurag S. Maskey 				/*
168*6ba597c5SAnurag S. Maskey 				 * First, if we're unexpectedly connected,
169*6ba597c5SAnurag S. Maskey 				 * disconnect.
170*6ba597c5SAnurag S. Maskey 				 */
171*6ba597c5SAnurag S. Maskey 				if (!link->nwamd_link_wifi_connected &&
172*6ba597c5SAnurag S. Maskey 				    nwamd_wlan_connected(object)) {
173*6ba597c5SAnurag S. Maskey 					nlog(LOG_DEBUG,
174*6ba597c5SAnurag S. Maskey 					    "nwamd_ncu_state_machine: "
175*6ba597c5SAnurag S. Maskey 					    "WiFi unexpectedly connected, "
176*6ba597c5SAnurag S. Maskey 					    "disconnecting...");
177*6ba597c5SAnurag S. Maskey 					(void) dladm_wlan_disconnect(dld_handle,
178*6ba597c5SAnurag S. Maskey 					    link->nwamd_link_id);
179*6ba597c5SAnurag S. Maskey 					nwamd_set_selected_connected(ncu,
180*6ba597c5SAnurag S. Maskey 					    B_FALSE, B_FALSE);
181*6ba597c5SAnurag S. Maskey 				}
182*6ba597c5SAnurag S. Maskey 				/* move to scanning aux state */
183*6ba597c5SAnurag S. Maskey 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
184*6ba597c5SAnurag S. Maskey 				    object_name, object->nwamd_object_state,
185*6ba597c5SAnurag S. Maskey 				    NWAM_AUX_STATE_LINK_WIFI_SCANNING);
186*6ba597c5SAnurag S. Maskey 			} else {
187*6ba597c5SAnurag S. Maskey 				/*
188*6ba597c5SAnurag S. Maskey 				 * If initial wired link state is unknown, we
189*6ba597c5SAnurag S. Maskey 				 * will need to assume the link is up, since
190*6ba597c5SAnurag S. Maskey 				 * we won´t get DL_NOTE_LINK_UP/DOWN events.
191*6ba597c5SAnurag S. Maskey 				 */
192*6ba597c5SAnurag S. Maskey 				link_state = nwamd_get_link_state
193*6ba597c5SAnurag S. Maskey 				    (ncu->ncu_name);
194*6ba597c5SAnurag S. Maskey 				if (link_state == LINK_STATE_UP ||
195*6ba597c5SAnurag S. Maskey 				    link_state == LINK_STATE_UNKNOWN) {
196*6ba597c5SAnurag S. Maskey 					nwamd_object_set_state
197*6ba597c5SAnurag S. Maskey 					    (NWAM_OBJECT_TYPE_NCU,
198*6ba597c5SAnurag S. Maskey 					    object_name, NWAM_STATE_ONLINE,
199*6ba597c5SAnurag S. Maskey 					    NWAM_AUX_STATE_UP);
200*6ba597c5SAnurag S. Maskey 				} else {
201*6ba597c5SAnurag S. Maskey 					nwamd_object_set_state
202*6ba597c5SAnurag S. Maskey 					    (NWAM_OBJECT_TYPE_NCU,
203*6ba597c5SAnurag S. Maskey 					    object_name,
204*6ba597c5SAnurag S. Maskey 					    NWAM_STATE_ONLINE_TO_OFFLINE,
205*6ba597c5SAnurag S. Maskey 					    NWAM_AUX_STATE_DOWN);
206*6ba597c5SAnurag S. Maskey 				}
207*6ba597c5SAnurag S. Maskey 			}
208*6ba597c5SAnurag S. Maskey 		} else {
209*6ba597c5SAnurag S. Maskey 			/*
210*6ba597c5SAnurag S. Maskey 			 * In the current implementation, initialization has to
211*6ba597c5SAnurag S. Maskey 			 * start from scratch since the complexity of minimizing
212*6ba597c5SAnurag S. Maskey 			 * configuration change is considerable (e.g. if we
213*6ba597c5SAnurag S. Maskey 			 * refresh and had DHCP running on the physical
214*6ba597c5SAnurag S. Maskey 			 * interface, and now have changed to static assignment,
215*6ba597c5SAnurag S. Maskey 			 * we need to remove DHCP etc).  To avoid all this,
216*6ba597c5SAnurag S. Maskey 			 * unplumb before re-plumbing the protocols and
217*6ba597c5SAnurag S. Maskey 			 * addresses we wish to configure.  In the future, it
218*6ba597c5SAnurag S. Maskey 			 * would be good to try and minimize configuration
219*6ba597c5SAnurag S. Maskey 			 * changes.
220*6ba597c5SAnurag S. Maskey 			 */
221*6ba597c5SAnurag S. Maskey 			nwamd_unplumb_interface(ncu, 0, AF_INET);
222*6ba597c5SAnurag S. Maskey 			nwamd_unplumb_interface(ncu, 0, AF_INET6);
223*6ba597c5SAnurag S. Maskey 
224*6ba597c5SAnurag S. Maskey 			/*
225*6ba597c5SAnurag S. Maskey 			 * Enqueue a WAITING_FOR_ADDR aux state change so that
226*6ba597c5SAnurag S. Maskey 			 * we are eligible to receive the IF_STATE events
227*6ba597c5SAnurag S. Maskey 			 * associated with static, DHCP, DHCPv6 and autoconf
228*6ba597c5SAnurag S. Maskey 			 * address assignment.  The latter two can happen
229*6ba597c5SAnurag S. Maskey 			 * quite quickly after plumbing so we need to be ready.
230*6ba597c5SAnurag S. Maskey 			 */
231*6ba597c5SAnurag S. Maskey 			nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
232*6ba597c5SAnurag S. Maskey 			    object_name, NWAM_STATE_OFFLINE_TO_ONLINE,
233*6ba597c5SAnurag S. Maskey 			    NWAM_AUX_STATE_IF_WAITING_FOR_ADDR);
234*6ba597c5SAnurag S. Maskey 
235*6ba597c5SAnurag S. Maskey 			if (ncu->ncu_node.u_if.nwamd_if_ipv4)
236*6ba597c5SAnurag S. Maskey 				nwamd_plumb_interface(ncu, 0, AF_INET);
237*6ba597c5SAnurag S. Maskey 
238*6ba597c5SAnurag S. Maskey 			if (ncu->ncu_node.u_if.nwamd_if_ipv6)
239*6ba597c5SAnurag S. Maskey 				nwamd_plumb_interface(ncu, 0, AF_INET6);
240*6ba597c5SAnurag S. Maskey 
241*6ba597c5SAnurag S. Maskey 			/*
242*6ba597c5SAnurag S. Maskey 			 * Configure addresses.  Configure any static addresses
243*6ba597c5SAnurag S. Maskey 			 * and start DHCP if required.  If DHCP is not required,
244*6ba597c5SAnurag S. Maskey 			 * do a DHCPINFORM to get other networking config
245*6ba597c5SAnurag S. Maskey 			 * parameters.  RTM_NEWADDRs - translated into IF_STATE
246*6ba597c5SAnurag S. Maskey 			 * events - will then finish the job of bringing us
247*6ba597c5SAnurag S. Maskey 			 * online.
248*6ba597c5SAnurag S. Maskey 			 */
249*6ba597c5SAnurag S. Maskey 			nwamd_configure_interface_addresses(ncu);
250*6ba597c5SAnurag S. Maskey 
251*6ba597c5SAnurag S. Maskey 			if (ncu->ncu_node.u_if.nwamd_if_dhcp_requested)
252*6ba597c5SAnurag S. Maskey 				nwamd_start_dhcp(ncu);
253*6ba597c5SAnurag S. Maskey 			else
254*6ba597c5SAnurag S. Maskey 				nwamd_dhcp_inform(ncu);
255*6ba597c5SAnurag S. Maskey 		}
256*6ba597c5SAnurag S. Maskey 		break;
257*6ba597c5SAnurag S. Maskey 
258*6ba597c5SAnurag S. Maskey 	case NWAM_AUX_STATE_IF_DHCP_TIMED_OUT:
259*6ba597c5SAnurag S. Maskey 	case NWAM_AUX_STATE_IF_WAITING_FOR_ADDR:
260*6ba597c5SAnurag S. Maskey 		/*
261*6ba597c5SAnurag S. Maskey 		 * nothing to do here - RTM_NEWADDRs will trigger IF_STATE
262*6ba597c5SAnurag S. Maskey 		 * events to move us online.
263*6ba597c5SAnurag S. Maskey 		 */
264*6ba597c5SAnurag S. Maskey 		break;
265*6ba597c5SAnurag S. Maskey 
266*6ba597c5SAnurag S. Maskey 	case NWAM_AUX_STATE_LINK_WIFI_SCANNING:
267*6ba597c5SAnurag S. Maskey 		/* launch scan thread */
268*6ba597c5SAnurag S. Maskey 		(void) strlcpy(linkname, ncu->ncu_name, sizeof (linkname));
269*6ba597c5SAnurag S. Maskey 		(void) nwamd_wlan_scan(linkname);
270*6ba597c5SAnurag S. Maskey 		/* Create periodic scan event */
271*6ba597c5SAnurag S. Maskey 		nwamd_ncu_create_periodic_scan_event(object);
272*6ba597c5SAnurag S. Maskey 		break;
273*6ba597c5SAnurag S. Maskey 
274*6ba597c5SAnurag S. Maskey 	case NWAM_AUX_STATE_LINK_WIFI_NEED_SELECTION:
275*6ba597c5SAnurag S. Maskey 		/* send "need choice" event */
276*6ba597c5SAnurag S. Maskey 		event = nwamd_event_init_wlan
277*6ba597c5SAnurag S. Maskey 		    (ncu->ncu_name, NWAM_EVENT_TYPE_WLAN_NEED_CHOICE, B_FALSE,
278*6ba597c5SAnurag S. Maskey 		    link->nwamd_link_wifi_scan.nwamd_wifi_scan_curr,
279*6ba597c5SAnurag S. Maskey 		    link->nwamd_link_wifi_scan.nwamd_wifi_scan_curr_num);
280*6ba597c5SAnurag S. Maskey 		if (event == NULL)
281*6ba597c5SAnurag S. Maskey 			break;
282*6ba597c5SAnurag S. Maskey 		nwamd_event_enqueue(event);
283*6ba597c5SAnurag S. Maskey 		nwamd_set_selected_connected(ncu, B_FALSE, B_FALSE);
284*6ba597c5SAnurag S. Maskey 		break;
285*6ba597c5SAnurag S. Maskey 
286*6ba597c5SAnurag S. Maskey 	case NWAM_AUX_STATE_LINK_WIFI_NEED_KEY:
287*6ba597c5SAnurag S. Maskey 		/*
288*6ba597c5SAnurag S. Maskey 		 * Send "need key" event.  Set selected to true, connected
289*6ba597c5SAnurag S. Maskey 		 * and have_key to false.  Do not fill in WLAN details as
290*6ba597c5SAnurag S. Maskey 		 * multiple WLANs may match the ESSID name, and each may
291*6ba597c5SAnurag S. Maskey 		 * have a different speed and channel.
292*6ba597c5SAnurag S. Maskey 		 */
293*6ba597c5SAnurag S. Maskey 		bzero(&key_wlan, sizeof (key_wlan));
294*6ba597c5SAnurag S. Maskey 		(void) strlcpy(key_wlan.nww_essid, link->nwamd_link_wifi_essid,
295*6ba597c5SAnurag S. Maskey 		    sizeof (key_wlan.nww_essid));
296*6ba597c5SAnurag S. Maskey 		(void) strlcpy(key_wlan.nww_bssid, link->nwamd_link_wifi_bssid,
297*6ba597c5SAnurag S. Maskey 		    sizeof (key_wlan.nww_bssid));
298*6ba597c5SAnurag S. Maskey 		key_wlan.nww_security_mode =
299*6ba597c5SAnurag S. Maskey 		    link->nwamd_link_wifi_security_mode;
300*6ba597c5SAnurag S. Maskey 		key_wlan.nww_selected = B_TRUE;
301*6ba597c5SAnurag S. Maskey 		key_wlan.nww_connected = B_FALSE;
302*6ba597c5SAnurag S. Maskey 		key_wlan.nww_have_key = B_FALSE;
303*6ba597c5SAnurag S. Maskey 		event = nwamd_event_init_wlan
304*6ba597c5SAnurag S. Maskey 		    (ncu->ncu_name, NWAM_EVENT_TYPE_WLAN_NEED_KEY, B_FALSE,
305*6ba597c5SAnurag S. Maskey 		    &key_wlan, 1);
306*6ba597c5SAnurag S. Maskey 		if (event == NULL)
307*6ba597c5SAnurag S. Maskey 			break;
308*6ba597c5SAnurag S. Maskey 		nwamd_event_enqueue(event);
309*6ba597c5SAnurag S. Maskey 		break;
310*6ba597c5SAnurag S. Maskey 
311*6ba597c5SAnurag S. Maskey 	case NWAM_AUX_STATE_LINK_WIFI_CONNECTING:
312*6ba597c5SAnurag S. Maskey 		(void) strlcpy(linkname, ncu->ncu_name, sizeof (linkname));
313*6ba597c5SAnurag S. Maskey 		nwamd_wlan_connect(linkname);
314*6ba597c5SAnurag S. Maskey 		break;
315*6ba597c5SAnurag S. Maskey 
316*6ba597c5SAnurag S. Maskey 	case NWAM_AUX_STATE_UP:
317*6ba597c5SAnurag S. Maskey 	case NWAM_AUX_STATE_DOWN:
318*6ba597c5SAnurag S. Maskey 		up = (object->nwamd_object_aux_state == NWAM_AUX_STATE_UP);
319*6ba597c5SAnurag S. Maskey 		if (ncu->ncu_type == NWAM_NCU_TYPE_LINK) {
320*6ba597c5SAnurag S. Maskey 			if (link->nwamd_link_media == DL_WIFI) {
321*6ba597c5SAnurag S. Maskey 				/*
322*6ba597c5SAnurag S. Maskey 				 * Connected/disconnected - send WLAN
323*6ba597c5SAnurag S. Maskey 				 * connection report.
324*6ba597c5SAnurag S. Maskey 				 */
325*6ba597c5SAnurag S. Maskey 				link->nwamd_link_wifi_connected = up;
326*6ba597c5SAnurag S. Maskey 				nwamd_set_selected_connected(ncu, B_TRUE, up);
327*6ba597c5SAnurag S. Maskey 
328*6ba597c5SAnurag S. Maskey 				(void) strlcpy(connected_wlan.nww_essid,
329*6ba597c5SAnurag S. Maskey 				    link->nwamd_link_wifi_essid,
330*6ba597c5SAnurag S. Maskey 				    sizeof (connected_wlan.nww_essid));
331*6ba597c5SAnurag S. Maskey 				(void) strlcpy(connected_wlan.nww_bssid,
332*6ba597c5SAnurag S. Maskey 				    link->nwamd_link_wifi_bssid,
333*6ba597c5SAnurag S. Maskey 				    sizeof (connected_wlan.nww_bssid));
334*6ba597c5SAnurag S. Maskey 				connected_wlan.nww_security_mode =
335*6ba597c5SAnurag S. Maskey 				    link->nwamd_link_wifi_security_mode;
336*6ba597c5SAnurag S. Maskey 				event = nwamd_event_init_wlan
337*6ba597c5SAnurag S. Maskey 				    (ncu->ncu_name,
338*6ba597c5SAnurag S. Maskey 				    NWAM_EVENT_TYPE_WLAN_CONNECTION_REPORT, up,
339*6ba597c5SAnurag S. Maskey 				    &connected_wlan, 1);
340*6ba597c5SAnurag S. Maskey 				if (event == NULL)
341*6ba597c5SAnurag S. Maskey 					break;
342*6ba597c5SAnurag S. Maskey 				nwamd_event_enqueue(event);
343*6ba597c5SAnurag S. Maskey 
344*6ba597c5SAnurag S. Maskey 				/*
345*6ba597c5SAnurag S. Maskey 				 * If disconnected, restart the state machine
346*6ba597c5SAnurag S. Maskey 				 * for the WiFi link (WiFi is always trying
347*6ba597c5SAnurag S. Maskey 				 * to connect).
348*6ba597c5SAnurag S. Maskey 				 *
349*6ba597c5SAnurag S. Maskey 				 * If connected, start signal strength
350*6ba597c5SAnurag S. Maskey 				 * monitoring thread.
351*6ba597c5SAnurag S. Maskey 				 */
352*6ba597c5SAnurag S. Maskey 				if (!up && ncu->ncu_enabled) {
353*6ba597c5SAnurag S. Maskey 					nlog(LOG_DEBUG,
354*6ba597c5SAnurag S. Maskey 					    "nwamd_ncu_state_machine: "
355*6ba597c5SAnurag S. Maskey 					    "wifi disconnect - start over "
356*6ba597c5SAnurag S. Maskey 					    "after %dsec interval",
357*6ba597c5SAnurag S. Maskey 					    WIRELESS_RETRY_INTERVAL);
358*6ba597c5SAnurag S. Maskey 					link->nwamd_link_wifi_connected =
359*6ba597c5SAnurag S. Maskey 					    B_FALSE;
360*6ba597c5SAnurag S. Maskey 					/* propogate down event to IP NCU */
361*6ba597c5SAnurag S. Maskey 					nwamd_propogate_link_up_down_to_ip
362*6ba597c5SAnurag S. Maskey 					    (ncu->ncu_name, B_FALSE);
363*6ba597c5SAnurag S. Maskey 					nwamd_object_set_state_timed
364*6ba597c5SAnurag S. Maskey 					    (NWAM_OBJECT_TYPE_NCU, object_name,
365*6ba597c5SAnurag S. Maskey 					    NWAM_STATE_OFFLINE_TO_ONLINE,
366*6ba597c5SAnurag S. Maskey 					    NWAM_AUX_STATE_INITIALIZED,
367*6ba597c5SAnurag S. Maskey 					    WIRELESS_RETRY_INTERVAL);
368*6ba597c5SAnurag S. Maskey 				} else {
369*6ba597c5SAnurag S. Maskey 					nlog(LOG_DEBUG,
370*6ba597c5SAnurag S. Maskey 					    "nwamd_ncu_state_machine: "
371*6ba597c5SAnurag S. Maskey 					    "wifi connected, start monitoring");
372*6ba597c5SAnurag S. Maskey 					(void) strlcpy(linkname, ncu->ncu_name,
373*6ba597c5SAnurag S. Maskey 					    sizeof (linkname));
374*6ba597c5SAnurag S. Maskey 					nwamd_wlan_monitor_signal(linkname);
375*6ba597c5SAnurag S. Maskey 				}
376*6ba597c5SAnurag S. Maskey 			}
377*6ba597c5SAnurag S. Maskey 		}
378*6ba597c5SAnurag S. Maskey 
379*6ba597c5SAnurag S. Maskey 		/* If not in ONLINE/OFFLINE state yet, change state */
380*6ba597c5SAnurag S. Maskey 		if ((up && object->nwamd_object_state != NWAM_STATE_ONLINE) ||
381*6ba597c5SAnurag S. Maskey 		    (!up && object->nwamd_object_state != NWAM_STATE_OFFLINE)) {
382*6ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG, "nwamd_ncu_state_machine: "
383*6ba597c5SAnurag S. Maskey 			    "%s is moving %s", object_name,
384*6ba597c5SAnurag S. Maskey 			    up ? "online" : "offline");
385*6ba597c5SAnurag S. Maskey 			nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
386*6ba597c5SAnurag S. Maskey 			    object_name,
387*6ba597c5SAnurag S. Maskey 			    up ? NWAM_STATE_ONLINE : NWAM_STATE_OFFLINE,
388*6ba597c5SAnurag S. Maskey 			    up ? NWAM_AUX_STATE_UP : NWAM_AUX_STATE_DOWN);
389*6ba597c5SAnurag S. Maskey 
390*6ba597c5SAnurag S. Maskey 			if (ncu->ncu_type == NWAM_NCU_TYPE_INTERFACE) {
391*6ba597c5SAnurag S. Maskey 				if (up) {
392*6ba597c5SAnurag S. Maskey 					/*
393*6ba597c5SAnurag S. Maskey 					 * Moving online, add v4/v6 default
394*6ba597c5SAnurag S. Maskey 					 * routes (if any).
395*6ba597c5SAnurag S. Maskey 					 */
396*6ba597c5SAnurag S. Maskey 					nwamd_add_default_routes(ncu);
397*6ba597c5SAnurag S. Maskey 				} else {
398*6ba597c5SAnurag S. Maskey 					/*
399*6ba597c5SAnurag S. Maskey 					 * If this is an interface NCU and we
400*6ba597c5SAnurag S. Maskey 					 * got a down event, it is a consequence
401*6ba597c5SAnurag S. Maskey 					 * of NCU refresh, so reapply addresses
402*6ba597c5SAnurag S. Maskey 					 * by reinitializing.
403*6ba597c5SAnurag S. Maskey 					 */
404*6ba597c5SAnurag S. Maskey 					nwamd_object_set_state
405*6ba597c5SAnurag S. Maskey 					    (NWAM_OBJECT_TYPE_NCU, object_name,
406*6ba597c5SAnurag S. Maskey 					    NWAM_STATE_OFFLINE_TO_ONLINE,
407*6ba597c5SAnurag S. Maskey 					    NWAM_AUX_STATE_INITIALIZED);
408*6ba597c5SAnurag S. Maskey 				}
409*6ba597c5SAnurag S. Maskey 			}
410*6ba597c5SAnurag S. Maskey 		} else {
411*6ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG, "nwamd_ncu_state_machine: "
412*6ba597c5SAnurag S. Maskey 			    "%s is %s", object_name,
413*6ba597c5SAnurag S. Maskey 			    up ? "online" : "offline");
414*6ba597c5SAnurag S. Maskey 		}
415*6ba597c5SAnurag S. Maskey 		/*
416*6ba597c5SAnurag S. Maskey 		 * NCU is UP or DOWN, trigger all condition checking, even if
417*6ba597c5SAnurag S. Maskey 		 * the NCU is already in the ONLINE state - an ENM may depend
418*6ba597c5SAnurag S. Maskey 		 * on NCU activity.
419*6ba597c5SAnurag S. Maskey 		 */
420*6ba597c5SAnurag S. Maskey 		nwamd_create_triggered_condition_check_event(NEXT_FEW_SECONDS);
421*6ba597c5SAnurag S. Maskey 		break;
422*6ba597c5SAnurag S. Maskey 
423*6ba597c5SAnurag S. Maskey 	case NWAM_AUX_STATE_CONDITIONS_NOT_MET:
424*6ba597c5SAnurag S. Maskey 		/*
425*6ba597c5SAnurag S. Maskey 		 * Link/interface is moving offline.  Nothing to do except
426*6ba597c5SAnurag S. Maskey 		 * for WiFi, where we disconnect.  Don't unplumb IP on
427*6ba597c5SAnurag S. Maskey 		 * a link since it may be a transient change.
428*6ba597c5SAnurag S. Maskey 		 */
429*6ba597c5SAnurag S. Maskey 		if (ncu->ncu_type == NWAM_NCU_TYPE_LINK) {
430*6ba597c5SAnurag S. Maskey 			if (link->nwamd_link_media == DL_WIFI) {
431*6ba597c5SAnurag S. Maskey 				(void) dladm_wlan_disconnect(dld_handle,
432*6ba597c5SAnurag S. Maskey 				    link->nwamd_link_id);
433*6ba597c5SAnurag S. Maskey 				link->nwamd_link_wifi_connected = B_FALSE;
434*6ba597c5SAnurag S. Maskey 				nwamd_set_selected_connected(ncu, B_FALSE,
435*6ba597c5SAnurag S. Maskey 				    B_FALSE);
436*6ba597c5SAnurag S. Maskey 			}
437*6ba597c5SAnurag S. Maskey 		} else {
438*6ba597c5SAnurag S. Maskey 			/*
439*6ba597c5SAnurag S. Maskey 			 * Unplumb here. In the future we may elaborate on
440*6ba597c5SAnurag S. Maskey 			 * the approach used and not unplumb for WiFi
441*6ba597c5SAnurag S. Maskey 			 * until we reconnect to a different WLAN (i.e. with
442*6ba597c5SAnurag S. Maskey 			 * a different ESSID).
443*6ba597c5SAnurag S. Maskey 			 */
444*6ba597c5SAnurag S. Maskey 			nwamd_unplumb_interface(ncu, 0, AF_INET);
445*6ba597c5SAnurag S. Maskey 			nwamd_unplumb_interface(ncu, 0, AF_INET6);
446*6ba597c5SAnurag S. Maskey 		}
447*6ba597c5SAnurag S. Maskey 		if (object->nwamd_object_state != NWAM_STATE_OFFLINE) {
448*6ba597c5SAnurag S. Maskey 			nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
449*6ba597c5SAnurag S. Maskey 			    object_name, NWAM_STATE_OFFLINE,
450*6ba597c5SAnurag S. Maskey 			    NWAM_AUX_STATE_CONDITIONS_NOT_MET);
451*6ba597c5SAnurag S. Maskey 		}
452*6ba597c5SAnurag S. Maskey 		break;
453*6ba597c5SAnurag S. Maskey 
454*6ba597c5SAnurag S. Maskey 	case NWAM_AUX_STATE_MANUAL_DISABLE:
455*6ba597c5SAnurag S. Maskey 		/* Manual disable, set enabled state appropriately. */
456*6ba597c5SAnurag S. Maskey 		ncu->ncu_enabled = B_FALSE;
457*6ba597c5SAnurag S. Maskey 		/* FALLTHROUGH */
458*6ba597c5SAnurag S. Maskey 	case NWAM_AUX_STATE_UNINITIALIZED:
459*6ba597c5SAnurag S. Maskey 	case NWAM_AUX_STATE_NOT_FOUND:
460*6ba597c5SAnurag S. Maskey 		/*
461*6ba597c5SAnurag S. Maskey 		 * Link/interface NCU has been disabled/deactivated/removed.
462*6ba597c5SAnurag S. Maskey 		 * For WiFi links disconnect, and for IP interfaces we unplumb.
463*6ba597c5SAnurag S. Maskey 		 */
464*6ba597c5SAnurag S. Maskey 		if (ncu->ncu_type == NWAM_NCU_TYPE_LINK) {
465*6ba597c5SAnurag S. Maskey 			if (link->nwamd_link_media == DL_WIFI) {
466*6ba597c5SAnurag S. Maskey 				(void) dladm_wlan_disconnect(dld_handle,
467*6ba597c5SAnurag S. Maskey 				    link->nwamd_link_id);
468*6ba597c5SAnurag S. Maskey 				link->nwamd_link_wifi_connected = B_FALSE;
469*6ba597c5SAnurag S. Maskey 				nwamd_set_selected_connected(ncu, B_FALSE,
470*6ba597c5SAnurag S. Maskey 				    B_FALSE);
471*6ba597c5SAnurag S. Maskey 			}
472*6ba597c5SAnurag S. Maskey 			nwamd_dlpi_delete_link(object);
473*6ba597c5SAnurag S. Maskey 		} else {
474*6ba597c5SAnurag S. Maskey 			/* Unplumb here. */
475*6ba597c5SAnurag S. Maskey 			if (ncu->ncu_node.u_if.nwamd_if_ipv4) {
476*6ba597c5SAnurag S. Maskey 				nwamd_unplumb_interface(ncu, 0, AF_INET);
477*6ba597c5SAnurag S. Maskey 			}
478*6ba597c5SAnurag S. Maskey 			if (ncu->ncu_node.u_if.nwamd_if_ipv6) {
479*6ba597c5SAnurag S. Maskey 				nwamd_unplumb_interface(ncu, 0, AF_INET6);
480*6ba597c5SAnurag S. Maskey 			}
481*6ba597c5SAnurag S. Maskey 			/* trigger location condition checking */
482*6ba597c5SAnurag S. Maskey 			nwamd_create_triggered_condition_check_event(0);
483*6ba597c5SAnurag S. Maskey 		}
484*6ba597c5SAnurag S. Maskey 
485*6ba597c5SAnurag S. Maskey 		switch (object->nwamd_object_aux_state) {
486*6ba597c5SAnurag S. Maskey 		case NWAM_AUX_STATE_MANUAL_DISABLE:
487*6ba597c5SAnurag S. Maskey 			/* Change state to DISABLED if manually disabled */
488*6ba597c5SAnurag S. Maskey 			nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
489*6ba597c5SAnurag S. Maskey 			    object_name, NWAM_STATE_DISABLED,
490*6ba597c5SAnurag S. Maskey 			    NWAM_AUX_STATE_MANUAL_DISABLE);
491*6ba597c5SAnurag S. Maskey 			/* Note that NCU has been disabled */
492*6ba597c5SAnurag S. Maskey 			ncu->ncu_enabled = B_FALSE;
493*6ba597c5SAnurag S. Maskey 			break;
494*6ba597c5SAnurag S. Maskey 		case NWAM_AUX_STATE_NOT_FOUND:
495*6ba597c5SAnurag S. Maskey 			/* Change state to UNINITIALIZED for device removal */
496*6ba597c5SAnurag S. Maskey 			nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
497*6ba597c5SAnurag S. Maskey 			    object_name, NWAM_STATE_UNINITIALIZED,
498*6ba597c5SAnurag S. Maskey 			    NWAM_AUX_STATE_NOT_FOUND);
499*6ba597c5SAnurag S. Maskey 			break;
500*6ba597c5SAnurag S. Maskey 		default:
501*6ba597c5SAnurag S. Maskey 			break;
502*6ba597c5SAnurag S. Maskey 		}
503*6ba597c5SAnurag S. Maskey 		break;
504*6ba597c5SAnurag S. Maskey 	default:
505*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_ncu_state_machine: unexpected state");
506*6ba597c5SAnurag S. Maskey 		break;
507*6ba597c5SAnurag S. Maskey 	}
508*6ba597c5SAnurag S. Maskey 
509*6ba597c5SAnurag S. Maskey 	nwamd_object_release(object);
510*6ba597c5SAnurag S. Maskey }
511*6ba597c5SAnurag S. Maskey 
512*6ba597c5SAnurag S. Maskey static int
513*6ba597c5SAnurag S. Maskey ncu_create_init_fini_event(nwam_ncu_handle_t ncuh, void *data)
514*6ba597c5SAnurag S. Maskey {
515*6ba597c5SAnurag S. Maskey 	boolean_t *init = data;
516*6ba597c5SAnurag S. Maskey 	char *name, *typedname;
517*6ba597c5SAnurag S. Maskey 	nwam_error_t err;
518*6ba597c5SAnurag S. Maskey 	nwam_value_t typeval = NULL;
519*6ba597c5SAnurag S. Maskey 	uint64_t *type;
520*6ba597c5SAnurag S. Maskey 	uint_t numvalues;
521*6ba597c5SAnurag S. Maskey 	nwamd_event_t ncu_event;
522*6ba597c5SAnurag S. Maskey 
523*6ba597c5SAnurag S. Maskey 	if (nwam_ncu_get_name(ncuh, &name) != NWAM_SUCCESS) {
524*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR,
525*6ba597c5SAnurag S. Maskey 		    "ncu_create_init_fini_event: could not get NCU name");
526*6ba597c5SAnurag S. Maskey 		return (0);
527*6ba597c5SAnurag S. Maskey 	}
528*6ba597c5SAnurag S. Maskey 
529*6ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "ncu_create_init_fini_event(%s, %p)", name, data);
530*6ba597c5SAnurag S. Maskey 
531*6ba597c5SAnurag S. Maskey 	if ((err = nwamd_get_ncu_uint(ncuh, &typeval, &type, &numvalues,
532*6ba597c5SAnurag S. Maskey 	    NWAM_NCU_PROP_TYPE)) != NWAM_SUCCESS) {
533*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "ncu_create_init_fini_event: "
534*6ba597c5SAnurag S. Maskey 		    "could not get NCU type: %s", nwam_strerror(err));
535*6ba597c5SAnurag S. Maskey 		free(name);
536*6ba597c5SAnurag S. Maskey 		nwam_value_free(typeval);
537*6ba597c5SAnurag S. Maskey 		return (0);
538*6ba597c5SAnurag S. Maskey 	}
539*6ba597c5SAnurag S. Maskey 
540*6ba597c5SAnurag S. Maskey 	/* convert name to typedname for event */
541*6ba597c5SAnurag S. Maskey 	if ((err = nwam_ncu_name_to_typed_name(name, *type, &typedname))
542*6ba597c5SAnurag S. Maskey 	    != NWAM_SUCCESS) {
543*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "ncu_create_init_fini_event: "
544*6ba597c5SAnurag S. Maskey 		    "NCU name translation failed: %s", nwam_strerror(err));
545*6ba597c5SAnurag S. Maskey 		free(name);
546*6ba597c5SAnurag S. Maskey 		return (0);
547*6ba597c5SAnurag S. Maskey 	}
548*6ba597c5SAnurag S. Maskey 	free(name);
549*6ba597c5SAnurag S. Maskey 	nwam_value_free(typeval);
550*6ba597c5SAnurag S. Maskey 
551*6ba597c5SAnurag S. Maskey 	ncu_event = nwamd_event_init(*init ?
552*6ba597c5SAnurag S. Maskey 	    NWAM_EVENT_TYPE_OBJECT_INIT : NWAM_EVENT_TYPE_OBJECT_FINI,
553*6ba597c5SAnurag S. Maskey 	    NWAM_OBJECT_TYPE_NCU, 0, typedname);
554*6ba597c5SAnurag S. Maskey 	if (ncu_event != NULL)
555*6ba597c5SAnurag S. Maskey 		nwamd_event_enqueue(ncu_event);
556*6ba597c5SAnurag S. Maskey 	free(typedname);
557*6ba597c5SAnurag S. Maskey 
558*6ba597c5SAnurag S. Maskey 	return (0);
559*6ba597c5SAnurag S. Maskey }
560*6ba597c5SAnurag S. Maskey 
561*6ba597c5SAnurag S. Maskey /*
562*6ba597c5SAnurag S. Maskey  * Initialization - walk the NCUs, creating initialization events for each
563*6ba597c5SAnurag S. Maskey  * NCU.  nwamd_ncu_handle_init_event() will check if the associated
564*6ba597c5SAnurag S. Maskey  * physical link exists or not.
565*6ba597c5SAnurag S. Maskey  */
566*6ba597c5SAnurag S. Maskey void
567*6ba597c5SAnurag S. Maskey nwamd_init_ncus(void)
568*6ba597c5SAnurag S. Maskey {
569*6ba597c5SAnurag S. Maskey 	boolean_t init = B_TRUE;
570*6ba597c5SAnurag S. Maskey 
571*6ba597c5SAnurag S. Maskey 	(void) pthread_mutex_lock(&active_ncp_mutex);
572*6ba597c5SAnurag S. Maskey 	if (active_ncph != NULL) {
573*6ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "nwamd_init_ncus: "
574*6ba597c5SAnurag S. Maskey 		    "(re)intializing NCUs for NCP %s", active_ncp);
575*6ba597c5SAnurag S. Maskey 		(void) nwam_ncp_walk_ncus(active_ncph,
576*6ba597c5SAnurag S. Maskey 		    ncu_create_init_fini_event, &init, NWAM_FLAG_NCU_TYPE_ALL,
577*6ba597c5SAnurag S. Maskey 		    NULL);
578*6ba597c5SAnurag S. Maskey 	}
579*6ba597c5SAnurag S. Maskey 	(void) pthread_mutex_unlock(&active_ncp_mutex);
580*6ba597c5SAnurag S. Maskey }
581*6ba597c5SAnurag S. Maskey 
582*6ba597c5SAnurag S. Maskey void
583*6ba597c5SAnurag S. Maskey nwamd_fini_ncus(void)
584*6ba597c5SAnurag S. Maskey {
585*6ba597c5SAnurag S. Maskey 	boolean_t init = B_FALSE;
586*6ba597c5SAnurag S. Maskey 
587*6ba597c5SAnurag S. Maskey 	/* We may not have an active NCP on initialization, so skip fini */
588*6ba597c5SAnurag S. Maskey 	(void) pthread_mutex_lock(&active_ncp_mutex);
589*6ba597c5SAnurag S. Maskey 	if (active_ncph != NULL) {
590*6ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "nwamd_fini_ncus: deinitializing NCUs for %s",
591*6ba597c5SAnurag S. Maskey 		    active_ncp);
592*6ba597c5SAnurag S. Maskey 		(void) nwam_ncp_walk_ncus(active_ncph,
593*6ba597c5SAnurag S. Maskey 		    ncu_create_init_fini_event, &init, NWAM_FLAG_NCU_TYPE_ALL,
594*6ba597c5SAnurag S. Maskey 		    NULL);
595*6ba597c5SAnurag S. Maskey 	}
596*6ba597c5SAnurag S. Maskey 	(void) pthread_mutex_unlock(&active_ncp_mutex);
597*6ba597c5SAnurag S. Maskey }
598*6ba597c5SAnurag S. Maskey 
599*6ba597c5SAnurag S. Maskey /*
600*6ba597c5SAnurag S. Maskey  * Most properties of this type don't need to be cached locally.  Only those
601*6ba597c5SAnurag S. Maskey  * interesting to the daemon are stored in an nwamd_ncu_t.
602*6ba597c5SAnurag S. Maskey  */
603*6ba597c5SAnurag S. Maskey static void
604*6ba597c5SAnurag S. Maskey populate_common_ncu_properties(nwam_ncu_handle_t ncuh, nwamd_ncu_t *ncu_data)
605*6ba597c5SAnurag S. Maskey {
606*6ba597c5SAnurag S. Maskey 	nwam_value_t ncu_prop;
607*6ba597c5SAnurag S. Maskey 	nwam_error_t err;
608*6ba597c5SAnurag S. Maskey 	boolean_t enablevalue;
609*6ba597c5SAnurag S. Maskey 	uint_t numvalues;
610*6ba597c5SAnurag S. Maskey 	char **parent;
611*6ba597c5SAnurag S. Maskey 
612*6ba597c5SAnurag S. Maskey 	if ((err = nwam_ncu_get_prop_value(ncuh, NWAM_NCU_PROP_ENABLED,
613*6ba597c5SAnurag S. Maskey 	    &ncu_prop)) != NWAM_SUCCESS) {
614*6ba597c5SAnurag S. Maskey 		char *name;
615*6ba597c5SAnurag S. Maskey 		(void) nwam_ncu_name_to_typed_name(ncu_data->ncu_name,
616*6ba597c5SAnurag S. Maskey 		    ncu_data->ncu_type, &name);
617*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwam_ncu_get_prop_value %s ENABLED failed: %s",
618*6ba597c5SAnurag S. Maskey 		    name, nwam_strerror(err));
619*6ba597c5SAnurag S. Maskey 		free(name);
620*6ba597c5SAnurag S. Maskey 		ncu_data->ncu_enabled = B_TRUE;
621*6ba597c5SAnurag S. Maskey 	} else {
622*6ba597c5SAnurag S. Maskey 		if ((err = nwam_value_get_boolean(ncu_prop, &enablevalue)) !=
623*6ba597c5SAnurag S. Maskey 		    NWAM_SUCCESS) {
624*6ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "nwam_value_get_boolean ENABLED failed: "
625*6ba597c5SAnurag S. Maskey 			    "%s", nwam_strerror(err));
626*6ba597c5SAnurag S. Maskey 		} else {
627*6ba597c5SAnurag S. Maskey 			ncu_data->ncu_enabled = enablevalue;
628*6ba597c5SAnurag S. Maskey 		}
629*6ba597c5SAnurag S. Maskey 		nwam_value_free(ncu_prop);
630*6ba597c5SAnurag S. Maskey 	}
631*6ba597c5SAnurag S. Maskey 
632*6ba597c5SAnurag S. Maskey 	if ((err = nwamd_get_ncu_string(ncuh, &ncu_prop, &parent,
633*6ba597c5SAnurag S. Maskey 	    &numvalues, NWAM_NCU_PROP_PARENT_NCP)) != NWAM_SUCCESS) {
634*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwam_ncu_get_prop_value %s PARENT failed: %s",
635*6ba597c5SAnurag S. Maskey 		    ncu_data->ncu_name, nwam_strerror(err));
636*6ba597c5SAnurag S. Maskey 	} else {
637*6ba597c5SAnurag S. Maskey 		(void) strlcpy(ncu_data->ncu_parent, parent[0],
638*6ba597c5SAnurag S. Maskey 		    sizeof (ncu_data->ncu_parent));
639*6ba597c5SAnurag S. Maskey 		nwam_value_free(ncu_prop);
640*6ba597c5SAnurag S. Maskey 	}
641*6ba597c5SAnurag S. Maskey }
642*6ba597c5SAnurag S. Maskey 
643*6ba597c5SAnurag S. Maskey /*
644*6ba597c5SAnurag S. Maskey  * Read in link properties.
645*6ba597c5SAnurag S. Maskey  */
646*6ba597c5SAnurag S. Maskey static void
647*6ba597c5SAnurag S. Maskey populate_link_ncu_properties(nwam_ncu_handle_t ncuh, nwamd_ncu_t *ncu_data)
648*6ba597c5SAnurag S. Maskey {
649*6ba597c5SAnurag S. Maskey 	nwam_value_t ncu_prop;
650*6ba597c5SAnurag S. Maskey 	nwam_error_t err;
651*6ba597c5SAnurag S. Maskey 	char **mac_addr;
652*6ba597c5SAnurag S. Maskey 	uint64_t *uintval;
653*6ba597c5SAnurag S. Maskey 	uint_t numvalues;
654*6ba597c5SAnurag S. Maskey 
655*6ba597c5SAnurag S. Maskey 	/* activation-mode */
656*6ba597c5SAnurag S. Maskey 	if ((err = nwamd_get_ncu_uint(ncuh, &ncu_prop, &uintval, &numvalues,
657*6ba597c5SAnurag S. Maskey 	    NWAM_NCU_PROP_ACTIVATION_MODE)) != NWAM_SUCCESS) {
658*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR,
659*6ba597c5SAnurag S. Maskey 		    "populate_link_ncu_properties: could not get %s value: %s",
660*6ba597c5SAnurag S. Maskey 		    NWAM_NCU_PROP_ACTIVATION_MODE, nwam_strerror(err));
661*6ba597c5SAnurag S. Maskey 	} else {
662*6ba597c5SAnurag S. Maskey 		ncu_data->ncu_node.u_link.nwamd_link_activation_mode =
663*6ba597c5SAnurag S. Maskey 		    uintval[0];
664*6ba597c5SAnurag S. Maskey 		nwam_value_free(ncu_prop);
665*6ba597c5SAnurag S. Maskey 	}
666*6ba597c5SAnurag S. Maskey 
667*6ba597c5SAnurag S. Maskey 	/* priority-group and priority-mode for prioritized activation */
668*6ba597c5SAnurag S. Maskey 	if (ncu_data->ncu_node.u_link.nwamd_link_activation_mode ==
669*6ba597c5SAnurag S. Maskey 	    NWAM_ACTIVATION_MODE_PRIORITIZED) {
670*6ba597c5SAnurag S. Maskey 		/* ncus with prioritized activation are always enabled */
671*6ba597c5SAnurag S. Maskey 		ncu_data->ncu_enabled = B_TRUE;
672*6ba597c5SAnurag S. Maskey 		if ((err = nwamd_get_ncu_uint(ncuh, &ncu_prop, &uintval,
673*6ba597c5SAnurag S. Maskey 		    &numvalues, NWAM_NCU_PROP_PRIORITY_MODE))
674*6ba597c5SAnurag S. Maskey 		    != NWAM_SUCCESS) {
675*6ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "populate_link_ncu_properties: "
676*6ba597c5SAnurag S. Maskey 			    "could not get %s value: %s",
677*6ba597c5SAnurag S. Maskey 			    NWAM_NCU_PROP_PRIORITY_MODE, nwam_strerror(err));
678*6ba597c5SAnurag S. Maskey 		} else {
679*6ba597c5SAnurag S. Maskey 			ncu_data->ncu_node.u_link.nwamd_link_priority_mode =
680*6ba597c5SAnurag S. Maskey 			    uintval[0];
681*6ba597c5SAnurag S. Maskey 			nwam_value_free(ncu_prop);
682*6ba597c5SAnurag S. Maskey 		}
683*6ba597c5SAnurag S. Maskey 
684*6ba597c5SAnurag S. Maskey 		if ((err = nwamd_get_ncu_uint(ncuh, &ncu_prop, &uintval,
685*6ba597c5SAnurag S. Maskey 		    &numvalues, NWAM_NCU_PROP_PRIORITY_GROUP))
686*6ba597c5SAnurag S. Maskey 		    != NWAM_SUCCESS) {
687*6ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "populate_link_ncu_properties: "
688*6ba597c5SAnurag S. Maskey 			    "could not get %s value: %s",
689*6ba597c5SAnurag S. Maskey 			    NWAM_NCU_PROP_PRIORITY_GROUP, nwam_strerror(err));
690*6ba597c5SAnurag S. Maskey 		} else {
691*6ba597c5SAnurag S. Maskey 			ncu_data->ncu_node.u_link.nwamd_link_priority_group =
692*6ba597c5SAnurag S. Maskey 			    uintval[0];
693*6ba597c5SAnurag S. Maskey 			nwam_value_free(ncu_prop);
694*6ba597c5SAnurag S. Maskey 		}
695*6ba597c5SAnurag S. Maskey 	}
696*6ba597c5SAnurag S. Maskey 
697*6ba597c5SAnurag S. Maskey 	/* link-mac-addr */
698*6ba597c5SAnurag S. Maskey 	if ((err = nwamd_get_ncu_string(ncuh, &ncu_prop, &mac_addr, &numvalues,
699*6ba597c5SAnurag S. Maskey 	    NWAM_NCU_PROP_LINK_MAC_ADDR)) != NWAM_SUCCESS) {
700*6ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG,
701*6ba597c5SAnurag S. Maskey 		    "populate_link_ncu_properties: could not get %s value: %s",
702*6ba597c5SAnurag S. Maskey 		    NWAM_NCU_PROP_LINK_MAC_ADDR, nwam_strerror(err));
703*6ba597c5SAnurag S. Maskey 		ncu_data->ncu_node.u_link.nwamd_link_mac_addr = NULL;
704*6ba597c5SAnurag S. Maskey 	} else {
705*6ba597c5SAnurag S. Maskey 		ncu_data->ncu_node.u_link.nwamd_link_mac_addr =
706*6ba597c5SAnurag S. Maskey 		    strdup(*mac_addr);
707*6ba597c5SAnurag S. Maskey 		ncu_data->ncu_node.u_link.nwamd_link_mac_addr_len =
708*6ba597c5SAnurag S. Maskey 		    strlen(*mac_addr);
709*6ba597c5SAnurag S. Maskey 		nwam_value_free(ncu_prop);
710*6ba597c5SAnurag S. Maskey 	}
711*6ba597c5SAnurag S. Maskey 
712*6ba597c5SAnurag S. Maskey 	/* link-mtu */
713*6ba597c5SAnurag S. Maskey 	if ((err = nwamd_get_ncu_uint(ncuh, &ncu_prop, &uintval, &numvalues,
714*6ba597c5SAnurag S. Maskey 	    NWAM_NCU_PROP_LINK_MTU)) != NWAM_SUCCESS) {
715*6ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG,
716*6ba597c5SAnurag S. Maskey 		    "populate_link_ncu_properties: could not get %s value: %s",
717*6ba597c5SAnurag S. Maskey 		    NWAM_NCU_PROP_LINK_MTU, nwam_strerror(err));
718*6ba597c5SAnurag S. Maskey 		ncu_data->ncu_node.u_link.nwamd_link_mtu = 0;
719*6ba597c5SAnurag S. Maskey 	} else {
720*6ba597c5SAnurag S. Maskey 		ncu_data->ncu_node.u_link.nwamd_link_mtu = uintval[0];
721*6ba597c5SAnurag S. Maskey 		nwam_value_free(ncu_prop);
722*6ba597c5SAnurag S. Maskey 	}
723*6ba597c5SAnurag S. Maskey 
724*6ba597c5SAnurag S. Maskey 	/* link-autopush */
725*6ba597c5SAnurag S. Maskey 	if ((err = nwamd_get_ncu_string(ncuh, &ncu_prop,
726*6ba597c5SAnurag S. Maskey 	    &ncu_data->ncu_node.u_link.nwamd_link_autopush,
727*6ba597c5SAnurag S. Maskey 	    &ncu_data->ncu_node.u_link.nwamd_link_num_autopush,
728*6ba597c5SAnurag S. Maskey 	    NWAM_NCU_PROP_LINK_AUTOPUSH)) != NWAM_SUCCESS) {
729*6ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG,
730*6ba597c5SAnurag S. Maskey 		    "populate_link_ncu_properties: could not get %s value: %s",
731*6ba597c5SAnurag S. Maskey 		    NWAM_NCU_PROP_LINK_AUTOPUSH, nwam_strerror(err));
732*6ba597c5SAnurag S. Maskey 		ncu_data->ncu_node.u_link.nwamd_link_num_autopush = 0;
733*6ba597c5SAnurag S. Maskey 	}
734*6ba597c5SAnurag S. Maskey }
735*6ba597c5SAnurag S. Maskey 
736*6ba597c5SAnurag S. Maskey static void
737*6ba597c5SAnurag S. Maskey populate_ip_ncu_properties(nwam_ncu_handle_t ncuh, nwamd_ncu_t *ncu_data)
738*6ba597c5SAnurag S. Maskey {
739*6ba597c5SAnurag S. Maskey 	nwamd_if_t *nif = &ncu_data->ncu_node.u_if;
740*6ba597c5SAnurag S. Maskey 	struct nwamd_if_address **nifa, *nifai, *nifait;
741*6ba597c5SAnurag S. Maskey 	char *prefix;
742*6ba597c5SAnurag S. Maskey 	boolean_t static_addr = B_FALSE;
743*6ba597c5SAnurag S. Maskey 	uint64_t *addrsrcvalue;
744*6ba597c5SAnurag S. Maskey 	nwam_value_t ncu_prop;
745*6ba597c5SAnurag S. Maskey 	nwam_error_t err;
746*6ba597c5SAnurag S. Maskey 	char **addrvalue;
747*6ba597c5SAnurag S. Maskey 	uint_t numvalues;
748*6ba597c5SAnurag S. Maskey 	uint64_t *ipversion;
749*6ba597c5SAnurag S. Maskey 	int i;
750*6ba597c5SAnurag S. Maskey 
751*6ba597c5SAnurag S. Maskey 	nif->nwamd_if_ipv4 = B_FALSE;
752*6ba597c5SAnurag S. Maskey 	nif->nwamd_if_ipv6 = B_FALSE;
753*6ba597c5SAnurag S. Maskey 	nif->nwamd_if_dhcp_requested = B_FALSE;
754*6ba597c5SAnurag S. Maskey 	nif->nwamd_if_stateful_requested = B_FALSE;
755*6ba597c5SAnurag S. Maskey 	nif->nwamd_if_stateless_requested = B_FALSE;
756*6ba597c5SAnurag S. Maskey 	nif->nwamd_if_ipv4_default_route_set = B_FALSE;
757*6ba597c5SAnurag S. Maskey 	nif->nwamd_if_ipv6_default_route_set = B_FALSE;
758*6ba597c5SAnurag S. Maskey 
759*6ba597c5SAnurag S. Maskey 	/* ip-version */
760*6ba597c5SAnurag S. Maskey 	if ((err = nwamd_get_ncu_uint(ncuh, &ncu_prop, &ipversion, &numvalues,
761*6ba597c5SAnurag S. Maskey 	    NWAM_NCU_PROP_IP_VERSION)) != NWAM_SUCCESS) {
762*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR,
763*6ba597c5SAnurag S. Maskey 		    "populate_ip_ncu_properties: could not get %s value: %s",
764*6ba597c5SAnurag S. Maskey 		    NWAM_NCU_PROP_IP_VERSION, nwam_strerror(err));
765*6ba597c5SAnurag S. Maskey 	} else {
766*6ba597c5SAnurag S. Maskey 		for (i = 0; i < numvalues; i++) {
767*6ba597c5SAnurag S. Maskey 			switch (ipversion[i]) {
768*6ba597c5SAnurag S. Maskey 			case IPV4_VERSION:
769*6ba597c5SAnurag S. Maskey 				nif->nwamd_if_ipv4 = B_TRUE;
770*6ba597c5SAnurag S. Maskey 				break;
771*6ba597c5SAnurag S. Maskey 			case IPV6_VERSION:
772*6ba597c5SAnurag S. Maskey 				nif->nwamd_if_ipv6 = B_TRUE;
773*6ba597c5SAnurag S. Maskey 				break;
774*6ba597c5SAnurag S. Maskey 			default:
775*6ba597c5SAnurag S. Maskey 				nlog(LOG_ERR, "bogus ip version %lld",
776*6ba597c5SAnurag S. Maskey 				    ipversion[i]);
777*6ba597c5SAnurag S. Maskey 				break;
778*6ba597c5SAnurag S. Maskey 			}
779*6ba597c5SAnurag S. Maskey 		}
780*6ba597c5SAnurag S. Maskey 		nwam_value_free(ncu_prop);
781*6ba597c5SAnurag S. Maskey 	}
782*6ba597c5SAnurag S. Maskey 
783*6ba597c5SAnurag S. Maskey 	/* Free the old list. */
784*6ba597c5SAnurag S. Maskey 	for (nifai = nif->nwamd_if_list; nifai != NULL; nifai = nifait) {
785*6ba597c5SAnurag S. Maskey 		nifait = nifai->next;
786*6ba597c5SAnurag S. Maskey 		nifai->next = NULL;
787*6ba597c5SAnurag S. Maskey 		free(nifai);
788*6ba597c5SAnurag S. Maskey 	}
789*6ba597c5SAnurag S. Maskey 	nif->nwamd_if_list = NULL;
790*6ba597c5SAnurag S. Maskey 	nifa = &(nif->nwamd_if_list);
791*6ba597c5SAnurag S. Maskey 
792*6ba597c5SAnurag S. Maskey 	if (!nif->nwamd_if_ipv4)
793*6ba597c5SAnurag S. Maskey 		goto skip_ipv4;
794*6ba597c5SAnurag S. Maskey 
795*6ba597c5SAnurag S. Maskey 	/* ipv4-addrsrc */
796*6ba597c5SAnurag S. Maskey 	if ((err = nwamd_get_ncu_uint(ncuh, &ncu_prop, &addrsrcvalue,
797*6ba597c5SAnurag S. Maskey 	    &numvalues, NWAM_NCU_PROP_IPV4_ADDRSRC)) != NWAM_SUCCESS) {
798*6ba597c5SAnurag S. Maskey 		nlog(nif->nwamd_if_ipv4 ? LOG_ERR : LOG_DEBUG,
799*6ba597c5SAnurag S. Maskey 		    "populate_ip_ncu_properties: could not get %s value: %s",
800*6ba597c5SAnurag S. Maskey 		    NWAM_NCU_PROP_IPV4_ADDRSRC, nwam_strerror(err));
801*6ba597c5SAnurag S. Maskey 	} else {
802*6ba597c5SAnurag S. Maskey 		for (i = 0; i < numvalues; i++) {
803*6ba597c5SAnurag S. Maskey 			switch (addrsrcvalue[i]) {
804*6ba597c5SAnurag S. Maskey 			case NWAM_ADDRSRC_DHCP:
805*6ba597c5SAnurag S. Maskey 				nif->nwamd_if_dhcp_requested = B_TRUE;
806*6ba597c5SAnurag S. Maskey 				break;
807*6ba597c5SAnurag S. Maskey 			case NWAM_ADDRSRC_STATIC:
808*6ba597c5SAnurag S. Maskey 				static_addr = B_TRUE;
809*6ba597c5SAnurag S. Maskey 				break;
810*6ba597c5SAnurag S. Maskey 			default:
811*6ba597c5SAnurag S. Maskey 				break;
812*6ba597c5SAnurag S. Maskey 			}
813*6ba597c5SAnurag S. Maskey 		}
814*6ba597c5SAnurag S. Maskey 		nwam_value_free(ncu_prop);
815*6ba597c5SAnurag S. Maskey 	}
816*6ba597c5SAnurag S. Maskey 	if (nif->nwamd_if_dhcp_requested) {
817*6ba597c5SAnurag S. Maskey 		if ((*nifa = calloc(sizeof (**nifa), 1)) != NULL) {
818*6ba597c5SAnurag S. Maskey 			(*nifa)->address.sa_family = AF_INET;
819*6ba597c5SAnurag S. Maskey 			(*nifa)->dhcp_if = B_TRUE;
820*6ba597c5SAnurag S. Maskey 			nifa = &((*nifa)->next);
821*6ba597c5SAnurag S. Maskey 			*nifa = NULL;
822*6ba597c5SAnurag S. Maskey 		}
823*6ba597c5SAnurag S. Maskey 	}
824*6ba597c5SAnurag S. Maskey 
825*6ba597c5SAnurag S. Maskey 	/* ipv4-addr */
826*6ba597c5SAnurag S. Maskey 	if (static_addr) {
827*6ba597c5SAnurag S. Maskey 		if ((err = nwamd_get_ncu_string(ncuh, &ncu_prop, &addrvalue,
828*6ba597c5SAnurag S. Maskey 		    &numvalues, NWAM_NCU_PROP_IPV4_ADDR)) != NWAM_SUCCESS) {
829*6ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "populate_ip_ncu_properties: "
830*6ba597c5SAnurag S. Maskey 			    "could not get %s value; %s",
831*6ba597c5SAnurag S. Maskey 			    NWAM_NCU_PROP_IPV4_ADDR, nwam_strerror(err));
832*6ba597c5SAnurag S. Maskey 		} else {
833*6ba597c5SAnurag S. Maskey 			struct sockaddr_in *s;
834*6ba597c5SAnurag S. Maskey 
835*6ba597c5SAnurag S. Maskey 			for (i = 0; i < numvalues; i++) {
836*6ba597c5SAnurag S. Maskey 				if ((*nifa = calloc(sizeof (**nifa), 1))
837*6ba597c5SAnurag S. Maskey 				    == NULL) {
838*6ba597c5SAnurag S. Maskey 					nlog(LOG_ERR, "couldn't allocate nwamd"
839*6ba597c5SAnurag S. Maskey 					    "address");
840*6ba597c5SAnurag S. Maskey 					continue;
841*6ba597c5SAnurag S. Maskey 				}
842*6ba597c5SAnurag S. Maskey 				(*nifa)->address.sa_family = AF_INET;
843*6ba597c5SAnurag S. Maskey 				/*LINTED*/
844*6ba597c5SAnurag S. Maskey 				s = (struct sockaddr_in *)&(*nifa)->address;
845*6ba597c5SAnurag S. Maskey 				s->sin_family = AF_INET;
846*6ba597c5SAnurag S. Maskey 				s->sin_port = 0;
847*6ba597c5SAnurag S. Maskey 				prefix = strchr(addrvalue[i], '/');
848*6ba597c5SAnurag S. Maskey 				if (prefix != NULL) {
849*6ba597c5SAnurag S. Maskey 					*prefix++ = 0;
850*6ba597c5SAnurag S. Maskey 					(*nifa)->prefix = atoi(prefix);
851*6ba597c5SAnurag S. Maskey 				}
852*6ba597c5SAnurag S. Maskey 				(void) inet_pton(AF_INET, addrvalue[i],
853*6ba597c5SAnurag S. Maskey 				    &(s->sin_addr));
854*6ba597c5SAnurag S. Maskey 				nifa = &((*nifa)->next);
855*6ba597c5SAnurag S. Maskey 			}
856*6ba597c5SAnurag S. Maskey 			*nifa = NULL;
857*6ba597c5SAnurag S. Maskey 
858*6ba597c5SAnurag S. Maskey 			nwam_value_free(ncu_prop);
859*6ba597c5SAnurag S. Maskey 		}
860*6ba597c5SAnurag S. Maskey 	}
861*6ba597c5SAnurag S. Maskey 
862*6ba597c5SAnurag S. Maskey 	/* get default route, if any */
863*6ba597c5SAnurag S. Maskey 	if ((err = nwamd_get_ncu_string(ncuh, &ncu_prop, &addrvalue,
864*6ba597c5SAnurag S. Maskey 	    &numvalues, NWAM_NCU_PROP_IPV4_DEFAULT_ROUTE)) == NWAM_SUCCESS) {
865*6ba597c5SAnurag S. Maskey 		/* Only one default route is allowed. */
866*6ba597c5SAnurag S. Maskey 		nif->nwamd_if_ipv4_default_route.sin_family = AF_INET;
867*6ba597c5SAnurag S. Maskey 		(void) inet_pton(AF_INET, addrvalue[0],
868*6ba597c5SAnurag S. Maskey 		    &(nif->nwamd_if_ipv4_default_route.sin_addr));
869*6ba597c5SAnurag S. Maskey 		nif->nwamd_if_ipv4_default_route_set = B_TRUE;
870*6ba597c5SAnurag S. Maskey 		nwam_value_free(ncu_prop);
871*6ba597c5SAnurag S. Maskey 	}
872*6ba597c5SAnurag S. Maskey 
873*6ba597c5SAnurag S. Maskey skip_ipv4:
874*6ba597c5SAnurag S. Maskey 
875*6ba597c5SAnurag S. Maskey 	if (!nif->nwamd_if_ipv6)
876*6ba597c5SAnurag S. Maskey 		goto skip_ipv6;
877*6ba597c5SAnurag S. Maskey 
878*6ba597c5SAnurag S. Maskey 	/* ipv6-addrsrc */
879*6ba597c5SAnurag S. Maskey 	static_addr = B_FALSE;
880*6ba597c5SAnurag S. Maskey 	if ((err = nwamd_get_ncu_uint(ncuh, &ncu_prop, &addrsrcvalue,
881*6ba597c5SAnurag S. Maskey 	    &numvalues, NWAM_NCU_PROP_IPV6_ADDRSRC)) != NWAM_SUCCESS) {
882*6ba597c5SAnurag S. Maskey 		nlog(nif->nwamd_if_ipv6 ? LOG_ERR : LOG_DEBUG,
883*6ba597c5SAnurag S. Maskey 		    "populate_ip_ncu_properties: could not get %s value: %s",
884*6ba597c5SAnurag S. Maskey 		    NWAM_NCU_PROP_IPV6_ADDRSRC, nwam_strerror(err));
885*6ba597c5SAnurag S. Maskey 	} else {
886*6ba597c5SAnurag S. Maskey 		for (i = 0; i < numvalues; i++) {
887*6ba597c5SAnurag S. Maskey 			switch (addrsrcvalue[i]) {
888*6ba597c5SAnurag S. Maskey 			case NWAM_ADDRSRC_DHCP:
889*6ba597c5SAnurag S. Maskey 				nif->nwamd_if_stateful_requested = B_TRUE;
890*6ba597c5SAnurag S. Maskey 				break;
891*6ba597c5SAnurag S. Maskey 			case NWAM_ADDRSRC_AUTOCONF:
892*6ba597c5SAnurag S. Maskey 				nif->nwamd_if_stateless_requested = B_TRUE;
893*6ba597c5SAnurag S. Maskey 				break;
894*6ba597c5SAnurag S. Maskey 			case NWAM_ADDRSRC_STATIC:
895*6ba597c5SAnurag S. Maskey 				static_addr = B_TRUE;
896*6ba597c5SAnurag S. Maskey 				break;
897*6ba597c5SAnurag S. Maskey 			default:
898*6ba597c5SAnurag S. Maskey 				break;
899*6ba597c5SAnurag S. Maskey 			}
900*6ba597c5SAnurag S. Maskey 		}
901*6ba597c5SAnurag S. Maskey 		nwam_value_free(ncu_prop);
902*6ba597c5SAnurag S. Maskey 	}
903*6ba597c5SAnurag S. Maskey 	if (nif->nwamd_if_stateful_requested) {
904*6ba597c5SAnurag S. Maskey 		if ((*nifa = calloc(sizeof (**nifa), 1)) != NULL) {
905*6ba597c5SAnurag S. Maskey 			(*nifa)->address.sa_family = AF_INET6;
906*6ba597c5SAnurag S. Maskey 			(*nifa)->dhcp_if = B_TRUE;
907*6ba597c5SAnurag S. Maskey 			nifa = &((*nifa)->next);
908*6ba597c5SAnurag S. Maskey 			*nifa = NULL;
909*6ba597c5SAnurag S. Maskey 		}
910*6ba597c5SAnurag S. Maskey 	}
911*6ba597c5SAnurag S. Maskey 	if (nif->nwamd_if_stateless_requested) {
912*6ba597c5SAnurag S. Maskey 		if ((*nifa = calloc(sizeof (**nifa), 1)) != NULL) {
913*6ba597c5SAnurag S. Maskey 			(*nifa)->address.sa_family = AF_INET6;
914*6ba597c5SAnurag S. Maskey 			(*nifa)->stateless_if = B_TRUE;
915*6ba597c5SAnurag S. Maskey 			nifa = &((*nifa)->next);
916*6ba597c5SAnurag S. Maskey 			*nifa = NULL;
917*6ba597c5SAnurag S. Maskey 		}
918*6ba597c5SAnurag S. Maskey 	}
919*6ba597c5SAnurag S. Maskey 
920*6ba597c5SAnurag S. Maskey 	/* ipv6-addr */
921*6ba597c5SAnurag S. Maskey 	if (static_addr) {
922*6ba597c5SAnurag S. Maskey 		if ((err = nwamd_get_ncu_string(ncuh, &ncu_prop, &addrvalue,
923*6ba597c5SAnurag S. Maskey 		    &numvalues, NWAM_NCU_PROP_IPV6_ADDR)) != NWAM_SUCCESS) {
924*6ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "populate_ip_ncu_properties: "
925*6ba597c5SAnurag S. Maskey 			    "could not get %s value; %s",
926*6ba597c5SAnurag S. Maskey 			    NWAM_NCU_PROP_IPV6_ADDR, nwam_strerror(err));
927*6ba597c5SAnurag S. Maskey 		} else {
928*6ba597c5SAnurag S. Maskey 			struct sockaddr_in6 *s;
929*6ba597c5SAnurag S. Maskey 
930*6ba597c5SAnurag S. Maskey 			for (i = 0; i < numvalues; i++) {
931*6ba597c5SAnurag S. Maskey 				if ((*nifa = calloc(sizeof (**nifa), 1))
932*6ba597c5SAnurag S. Maskey 				    == NULL) {
933*6ba597c5SAnurag S. Maskey 					nlog(LOG_ERR, "couldn't allocate nwamd"
934*6ba597c5SAnurag S. Maskey 					    "address");
935*6ba597c5SAnurag S. Maskey 					continue;
936*6ba597c5SAnurag S. Maskey 				}
937*6ba597c5SAnurag S. Maskey 				(*nifa)->address.sa_family = AF_INET6;
938*6ba597c5SAnurag S. Maskey 				/*LINTED*/
939*6ba597c5SAnurag S. Maskey 				s = (struct sockaddr_in6 *)&(*nifa)->address;
940*6ba597c5SAnurag S. Maskey 				s->sin6_family = AF_INET6;
941*6ba597c5SAnurag S. Maskey 				s->sin6_port = 0;
942*6ba597c5SAnurag S. Maskey 				prefix = strchr(addrvalue[i], '/');
943*6ba597c5SAnurag S. Maskey 				if (prefix != NULL) {
944*6ba597c5SAnurag S. Maskey 					*prefix++ = 0;
945*6ba597c5SAnurag S. Maskey 					(*nifa)->prefix = atoi(prefix);
946*6ba597c5SAnurag S. Maskey 				}
947*6ba597c5SAnurag S. Maskey 				(void) inet_pton(AF_INET6, addrvalue[i],
948*6ba597c5SAnurag S. Maskey 				    &(s->sin6_addr));
949*6ba597c5SAnurag S. Maskey 				nifa = &((*nifa)->next);
950*6ba597c5SAnurag S. Maskey 			}
951*6ba597c5SAnurag S. Maskey 			*nifa = NULL;
952*6ba597c5SAnurag S. Maskey 
953*6ba597c5SAnurag S. Maskey 			nwam_value_free(ncu_prop);
954*6ba597c5SAnurag S. Maskey 		}
955*6ba597c5SAnurag S. Maskey 	}
956*6ba597c5SAnurag S. Maskey 
957*6ba597c5SAnurag S. Maskey 	/* get default route, if any */
958*6ba597c5SAnurag S. Maskey 	if ((err = nwamd_get_ncu_string(ncuh, &ncu_prop, &addrvalue,
959*6ba597c5SAnurag S. Maskey 	    &numvalues, NWAM_NCU_PROP_IPV6_DEFAULT_ROUTE)) == NWAM_SUCCESS) {
960*6ba597c5SAnurag S. Maskey 		/* Only one default route is allowed. */
961*6ba597c5SAnurag S. Maskey 		nif->nwamd_if_ipv6_default_route.sin6_family = AF_INET6;
962*6ba597c5SAnurag S. Maskey 		(void) inet_pton(AF_INET6, addrvalue[0],
963*6ba597c5SAnurag S. Maskey 		    &(nif->nwamd_if_ipv6_default_route.sin6_addr));
964*6ba597c5SAnurag S. Maskey 		nif->nwamd_if_ipv6_default_route_set = B_TRUE;
965*6ba597c5SAnurag S. Maskey 		nwam_value_free(ncu_prop);
966*6ba597c5SAnurag S. Maskey 	}
967*6ba597c5SAnurag S. Maskey 
968*6ba597c5SAnurag S. Maskey skip_ipv6:
969*6ba597c5SAnurag S. Maskey 	;
970*6ba597c5SAnurag S. Maskey }
971*6ba597c5SAnurag S. Maskey 
972*6ba597c5SAnurag S. Maskey static nwamd_ncu_t *
973*6ba597c5SAnurag S. Maskey nwamd_ncu_init(nwam_ncu_type_t ncu_type, const char *name)
974*6ba597c5SAnurag S. Maskey {
975*6ba597c5SAnurag S. Maskey 	nwamd_ncu_t *rv;
976*6ba597c5SAnurag S. Maskey 
977*6ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "nwamd_ncu_init(%d, %s)", ncu_type, name);
978*6ba597c5SAnurag S. Maskey 
979*6ba597c5SAnurag S. Maskey 	if ((rv = calloc(1, sizeof (*rv))) == NULL)
980*6ba597c5SAnurag S. Maskey 		return (NULL);
981*6ba597c5SAnurag S. Maskey 
982*6ba597c5SAnurag S. Maskey 	rv->ncu_type = ncu_type;
983*6ba597c5SAnurag S. Maskey 	rv->ncu_name = strdup(name);
984*6ba597c5SAnurag S. Maskey 	rv->ncu_enabled = B_FALSE;
985*6ba597c5SAnurag S. Maskey 
986*6ba597c5SAnurag S. Maskey 	/* Initialize link/interface-specific data */
987*6ba597c5SAnurag S. Maskey 	if (rv->ncu_type == NWAM_NCU_TYPE_LINK) {
988*6ba597c5SAnurag S. Maskey 		(void) bzero(&rv->ncu_node.u_link, sizeof (nwamd_link_t));
989*6ba597c5SAnurag S. Maskey 		(void) dladm_name2info(dld_handle, name,
990*6ba597c5SAnurag S. Maskey 		    &rv->ncu_node.u_link.nwamd_link_id, NULL, NULL,
991*6ba597c5SAnurag S. Maskey 		    &rv->ncu_node.u_link.nwamd_link_media);
992*6ba597c5SAnurag S. Maskey 		(void) pthread_mutex_init(
993*6ba597c5SAnurag S. Maskey 		    &rv->ncu_node.u_link.nwamd_link_wifi_mutex, NULL);
994*6ba597c5SAnurag S. Maskey 		rv->ncu_node.u_link.nwamd_link_wifi_priority = MAXINT;
995*6ba597c5SAnurag S. Maskey 	} else {
996*6ba597c5SAnurag S. Maskey 		(void) bzero(&rv->ncu_node.u_if, sizeof (nwamd_if_t));
997*6ba597c5SAnurag S. Maskey 	}
998*6ba597c5SAnurag S. Maskey 
999*6ba597c5SAnurag S. Maskey 	return (rv);
1000*6ba597c5SAnurag S. Maskey }
1001*6ba597c5SAnurag S. Maskey 
1002*6ba597c5SAnurag S. Maskey void
1003*6ba597c5SAnurag S. Maskey nwamd_ncu_free(nwamd_ncu_t *ncu)
1004*6ba597c5SAnurag S. Maskey {
1005*6ba597c5SAnurag S. Maskey 	if (ncu != NULL) {
1006*6ba597c5SAnurag S. Maskey 		assert(ncu->ncu_type == NWAM_NCU_TYPE_LINK ||
1007*6ba597c5SAnurag S. Maskey 		    ncu->ncu_type == NWAM_NCU_TYPE_INTERFACE);
1008*6ba597c5SAnurag S. Maskey 		if (ncu->ncu_type == NWAM_NCU_TYPE_LINK) {
1009*6ba597c5SAnurag S. Maskey 			struct nwamd_link *l = &ncu->ncu_node.u_link;
1010*6ba597c5SAnurag S. Maskey 			int i;
1011*6ba597c5SAnurag S. Maskey 
1012*6ba597c5SAnurag S. Maskey 			free(l->nwamd_link_wifi_key);
1013*6ba597c5SAnurag S. Maskey 			free(l->nwamd_link_mac_addr);
1014*6ba597c5SAnurag S. Maskey 			for (i = 0; i < l->nwamd_link_num_autopush; i++)
1015*6ba597c5SAnurag S. Maskey 				free(l->nwamd_link_autopush[i]);
1016*6ba597c5SAnurag S. Maskey 		} else if (ncu->ncu_type == NWAM_NCU_TYPE_INTERFACE) {
1017*6ba597c5SAnurag S. Maskey 			struct nwamd_if_address *nifa;
1018*6ba597c5SAnurag S. Maskey 
1019*6ba597c5SAnurag S. Maskey 			nifa = ncu->ncu_node.u_if.nwamd_if_list;
1020*6ba597c5SAnurag S. Maskey 			while (nifa != NULL) {
1021*6ba597c5SAnurag S. Maskey 				struct nwamd_if_address *n;
1022*6ba597c5SAnurag S. Maskey 
1023*6ba597c5SAnurag S. Maskey 				n = nifa;
1024*6ba597c5SAnurag S. Maskey 				nifa = nifa->next;
1025*6ba597c5SAnurag S. Maskey 				free(n);
1026*6ba597c5SAnurag S. Maskey 			}
1027*6ba597c5SAnurag S. Maskey 		}
1028*6ba597c5SAnurag S. Maskey 		free(ncu->ncu_name);
1029*6ba597c5SAnurag S. Maskey 		free(ncu);
1030*6ba597c5SAnurag S. Maskey 	}
1031*6ba597c5SAnurag S. Maskey }
1032*6ba597c5SAnurag S. Maskey 
1033*6ba597c5SAnurag S. Maskey static int
1034*6ba597c5SAnurag S. Maskey nwamd_ncu_display(nwamd_object_t ncu_obj, void *data)
1035*6ba597c5SAnurag S. Maskey {
1036*6ba597c5SAnurag S. Maskey 	nwamd_ncu_t *ncu = (nwamd_ncu_t *)ncu_obj->nwamd_object_data;
1037*6ba597c5SAnurag S. Maskey 	data = data;
1038*6ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "NCU (%p) %s state %s, %s",
1039*6ba597c5SAnurag S. Maskey 	    (void *)ncu, ncu_obj->nwamd_object_name,
1040*6ba597c5SAnurag S. Maskey 	    nwam_state_to_string(ncu_obj->nwamd_object_state),
1041*6ba597c5SAnurag S. Maskey 	    nwam_aux_state_to_string(ncu_obj->nwamd_object_aux_state));
1042*6ba597c5SAnurag S. Maskey 	return (0);
1043*6ba597c5SAnurag S. Maskey }
1044*6ba597c5SAnurag S. Maskey 
1045*6ba597c5SAnurag S. Maskey void
1046*6ba597c5SAnurag S. Maskey nwamd_log_ncus(void)
1047*6ba597c5SAnurag S. Maskey {
1048*6ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "NCP %s", active_ncp);
1049*6ba597c5SAnurag S. Maskey 	(void) nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU, nwamd_ncu_display,
1050*6ba597c5SAnurag S. Maskey 	    NULL);
1051*6ba597c5SAnurag S. Maskey }
1052*6ba597c5SAnurag S. Maskey 
1053*6ba597c5SAnurag S. Maskey int
1054*6ba597c5SAnurag S. Maskey nwamd_ncu_action(const char *ncu, const char *parent, nwam_action_t action)
1055*6ba597c5SAnurag S. Maskey {
1056*6ba597c5SAnurag S. Maskey 	nwamd_event_t ncu_event = nwamd_event_init_object_action
1057*6ba597c5SAnurag S. Maskey 	    (NWAM_OBJECT_TYPE_NCU, ncu, parent, action);
1058*6ba597c5SAnurag S. Maskey 	if (ncu_event == NULL)
1059*6ba597c5SAnurag S. Maskey 		return (1);
1060*6ba597c5SAnurag S. Maskey 	nwamd_event_enqueue(ncu_event);
1061*6ba597c5SAnurag S. Maskey 	return (0);
1062*6ba597c5SAnurag S. Maskey }
1063*6ba597c5SAnurag S. Maskey 
1064*6ba597c5SAnurag S. Maskey static void
1065*6ba597c5SAnurag S. Maskey add_phys_ncu_to_ncp(nwam_ncp_handle_t ncph, const char *name)
1066*6ba597c5SAnurag S. Maskey {
1067*6ba597c5SAnurag S. Maskey 	dladm_status_t dlrtn;
1068*6ba597c5SAnurag S. Maskey 	uint32_t media;
1069*6ba597c5SAnurag S. Maskey 	boolean_t is_wireless;
1070*6ba597c5SAnurag S. Maskey 	nwam_error_t err;
1071*6ba597c5SAnurag S. Maskey 	nwam_ncu_handle_t ncuh;
1072*6ba597c5SAnurag S. Maskey 	uint64_t uintval;
1073*6ba597c5SAnurag S. Maskey 
1074*6ba597c5SAnurag S. Maskey 	if ((dlrtn = dladm_name2info(dld_handle, name, NULL, NULL, NULL,
1075*6ba597c5SAnurag S. Maskey 	    &media)) != DLADM_STATUS_OK) {
1076*6ba597c5SAnurag S. Maskey 		char errmsg[DLADM_STRSIZE];
1077*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "failed to get media type for %s: %s", name,
1078*6ba597c5SAnurag S. Maskey 		    dladm_status2str(dlrtn, errmsg));
1079*6ba597c5SAnurag S. Maskey 		return;
1080*6ba597c5SAnurag S. Maskey 	}
1081*6ba597c5SAnurag S. Maskey 	is_wireless = (media == DL_WIFI);
1082*6ba597c5SAnurag S. Maskey 
1083*6ba597c5SAnurag S. Maskey 	if ((err = nwam_ncu_create(ncph, name, NWAM_NCU_TYPE_LINK,
1084*6ba597c5SAnurag S. Maskey 	    NWAM_NCU_CLASS_PHYS, &ncuh)) != NWAM_SUCCESS) {
1085*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "failed to create link ncu for %s: %s", name,
1086*6ba597c5SAnurag S. Maskey 		    nwam_strerror(err));
1087*6ba597c5SAnurag S. Maskey 		if (err == NWAM_ENTITY_READ_ONLY) {
1088*6ba597c5SAnurag S. Maskey 			nwamd_event_t retry_event;
1089*6ba597c5SAnurag S. Maskey 
1090*6ba597c5SAnurag S. Maskey 			/*
1091*6ba597c5SAnurag S. Maskey 			 * Root filesystem may be read-only, retry in
1092*6ba597c5SAnurag S. Maskey 			 * a few seconds.
1093*6ba597c5SAnurag S. Maskey 			 */
1094*6ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG, "Retrying addition of phys ncu for %s",
1095*6ba597c5SAnurag S. Maskey 			    name);
1096*6ba597c5SAnurag S. Maskey 			retry_event = nwamd_event_init_link_action(name,
1097*6ba597c5SAnurag S. Maskey 			    NWAM_ACTION_ADD);
1098*6ba597c5SAnurag S. Maskey 			if (retry_event != NULL) {
1099*6ba597c5SAnurag S. Maskey 				nwamd_event_enqueue_timed(retry_event,
1100*6ba597c5SAnurag S. Maskey 				    NWAMD_READONLY_RETRY_INTERVAL);
1101*6ba597c5SAnurag S. Maskey 			}
1102*6ba597c5SAnurag S. Maskey 		}
1103*6ba597c5SAnurag S. Maskey 		return;
1104*6ba597c5SAnurag S. Maskey 	}
1105*6ba597c5SAnurag S. Maskey 
1106*6ba597c5SAnurag S. Maskey 	uintval = NWAM_ACTIVATION_MODE_PRIORITIZED;
1107*6ba597c5SAnurag S. Maskey 	if ((err = nwamd_set_ncu_uint(ncuh, &uintval, 1,
1108*6ba597c5SAnurag S. Maskey 	    NWAM_NCU_PROP_ACTIVATION_MODE)) != NWAM_SUCCESS) {
1109*6ba597c5SAnurag S. Maskey 		goto finish;
1110*6ba597c5SAnurag S. Maskey 	}
1111*6ba597c5SAnurag S. Maskey 
1112*6ba597c5SAnurag S. Maskey 	uintval = is_wireless ? 1 : 0;
1113*6ba597c5SAnurag S. Maskey 	if ((err = nwamd_set_ncu_uint(ncuh, &uintval, 1,
1114*6ba597c5SAnurag S. Maskey 	    NWAM_NCU_PROP_PRIORITY_GROUP)) != NWAM_SUCCESS) {
1115*6ba597c5SAnurag S. Maskey 		goto finish;
1116*6ba597c5SAnurag S. Maskey 	}
1117*6ba597c5SAnurag S. Maskey 
1118*6ba597c5SAnurag S. Maskey 	uintval = is_wireless ? NWAM_PRIORITY_MODE_EXCLUSIVE :
1119*6ba597c5SAnurag S. Maskey 	    NWAM_PRIORITY_MODE_SHARED;
1120*6ba597c5SAnurag S. Maskey 	if ((err = nwamd_set_ncu_uint(ncuh, &uintval, 1,
1121*6ba597c5SAnurag S. Maskey 	    NWAM_NCU_PROP_PRIORITY_MODE)) != NWAM_SUCCESS) {
1122*6ba597c5SAnurag S. Maskey 		goto finish;
1123*6ba597c5SAnurag S. Maskey 	}
1124*6ba597c5SAnurag S. Maskey 
1125*6ba597c5SAnurag S. Maskey 	err = nwam_ncu_commit(ncuh, 0);
1126*6ba597c5SAnurag S. Maskey 
1127*6ba597c5SAnurag S. Maskey finish:
1128*6ba597c5SAnurag S. Maskey 	nwam_ncu_free(ncuh);
1129*6ba597c5SAnurag S. Maskey 	if (err != NWAM_SUCCESS) {
1130*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR,
1131*6ba597c5SAnurag S. Maskey 		    "failed to create automatic link ncu for %s: %s",
1132*6ba597c5SAnurag S. Maskey 		    name, nwam_strerror(err));
1133*6ba597c5SAnurag S. Maskey 	}
1134*6ba597c5SAnurag S. Maskey }
1135*6ba597c5SAnurag S. Maskey 
1136*6ba597c5SAnurag S. Maskey static void
1137*6ba597c5SAnurag S. Maskey add_ip_ncu_to_ncp(nwam_ncp_handle_t ncph, const char *name)
1138*6ba597c5SAnurag S. Maskey {
1139*6ba597c5SAnurag S. Maskey 	nwam_error_t err;
1140*6ba597c5SAnurag S. Maskey 	nwam_ncu_handle_t ncuh;
1141*6ba597c5SAnurag S. Maskey 
1142*6ba597c5SAnurag S. Maskey 	if ((err = nwam_ncu_create(ncph, name, NWAM_NCU_TYPE_INTERFACE,
1143*6ba597c5SAnurag S. Maskey 	    NWAM_NCU_CLASS_IP, &ncuh)) != NWAM_SUCCESS) {
1144*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "failed to create ip ncu for %s: %s", name,
1145*6ba597c5SAnurag S. Maskey 		    nwam_strerror(err));
1146*6ba597c5SAnurag S. Maskey 		/*
1147*6ba597c5SAnurag S. Maskey 		 * Root filesystem may be read-only, but no need to
1148*6ba597c5SAnurag S. Maskey 		 * retry here since add_phys_ncu_to_ncp() enqueues
1149*6ba597c5SAnurag S. Maskey 		 * a retry event which will lead to add_ip_ncu_to_ncp()
1150*6ba597c5SAnurag S. Maskey 		 * being called.
1151*6ba597c5SAnurag S. Maskey 		 */
1152*6ba597c5SAnurag S. Maskey 		return;
1153*6ba597c5SAnurag S. Maskey 	}
1154*6ba597c5SAnurag S. Maskey 
1155*6ba597c5SAnurag S. Maskey 	/* IP NCU has the default values, so nothing else to do */
1156*6ba597c5SAnurag S. Maskey 	err = nwam_ncu_commit(ncuh, 0);
1157*6ba597c5SAnurag S. Maskey 
1158*6ba597c5SAnurag S. Maskey finish:
1159*6ba597c5SAnurag S. Maskey 	nwam_ncu_free(ncuh);
1160*6ba597c5SAnurag S. Maskey 	if (err != NWAM_SUCCESS) {
1161*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR,
1162*6ba597c5SAnurag S. Maskey 		    "failed to create ip ncu for %s: %s", name,
1163*6ba597c5SAnurag S. Maskey 		    nwam_strerror(err));
1164*6ba597c5SAnurag S. Maskey 	}
1165*6ba597c5SAnurag S. Maskey }
1166*6ba597c5SAnurag S. Maskey 
1167*6ba597c5SAnurag S. Maskey static void
1168*6ba597c5SAnurag S. Maskey remove_ncu_from_ncp(nwam_ncp_handle_t ncph, const char *name,
1169*6ba597c5SAnurag S. Maskey     nwam_ncu_type_t type)
1170*6ba597c5SAnurag S. Maskey {
1171*6ba597c5SAnurag S. Maskey 	nwam_error_t err;
1172*6ba597c5SAnurag S. Maskey 	nwam_ncu_handle_t ncuh;
1173*6ba597c5SAnurag S. Maskey 
1174*6ba597c5SAnurag S. Maskey 	if ((err = nwam_ncu_read(ncph, name, type, 0, &ncuh)) != NWAM_SUCCESS) {
1175*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "failed to read automatic ncu %s: %s", name,
1176*6ba597c5SAnurag S. Maskey 		    nwam_strerror(err));
1177*6ba597c5SAnurag S. Maskey 		return;
1178*6ba597c5SAnurag S. Maskey 	}
1179*6ba597c5SAnurag S. Maskey 
1180*6ba597c5SAnurag S. Maskey 	err = nwam_ncu_destroy(ncuh, 0);
1181*6ba597c5SAnurag S. Maskey 	if (err != NWAM_SUCCESS) {
1182*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "failed to delete automatic ncu %s: %s", name,
1183*6ba597c5SAnurag S. Maskey 		    nwam_strerror(err));
1184*6ba597c5SAnurag S. Maskey 	}
1185*6ba597c5SAnurag S. Maskey }
1186*6ba597c5SAnurag S. Maskey 
1187*6ba597c5SAnurag S. Maskey /*
1188*6ba597c5SAnurag S. Maskey  * Device represented by NCU has been added or removed for the active
1189*6ba597c5SAnurag S. Maskey  * User NCP.  If an associated NCU of the given type is found, transition it
1190*6ba597c5SAnurag S. Maskey  * to the appropriate state.
1191*6ba597c5SAnurag S. Maskey  */
1192*6ba597c5SAnurag S. Maskey void
1193*6ba597c5SAnurag S. Maskey ncu_action_change_state(nwam_action_t action, nwam_ncu_type_t type,
1194*6ba597c5SAnurag S. Maskey     const char *name)
1195*6ba597c5SAnurag S. Maskey {
1196*6ba597c5SAnurag S. Maskey 	nwamd_object_t ncu_obj = NULL;
1197*6ba597c5SAnurag S. Maskey 	nwamd_ncu_t *ncu;
1198*6ba597c5SAnurag S. Maskey 
1199*6ba597c5SAnurag S. Maskey 	if ((ncu_obj = nwamd_ncu_object_find(type, name)) == NULL)
1200*6ba597c5SAnurag S. Maskey 		return;
1201*6ba597c5SAnurag S. Maskey 
1202*6ba597c5SAnurag S. Maskey 	ncu = ncu_obj->nwamd_object_data;
1203*6ba597c5SAnurag S. Maskey 
1204*6ba597c5SAnurag S. Maskey 	/*
1205*6ba597c5SAnurag S. Maskey 	 * If device has been added, transition from uninitialized to offline.
1206*6ba597c5SAnurag S. Maskey 	 * If device has been removed, transition to uninitialized (via online*
1207*6ba597c5SAnurag S. Maskey 	 * if the NCU is currently enabled in order to tear down config).
1208*6ba597c5SAnurag S. Maskey 	 */
1209*6ba597c5SAnurag S. Maskey 	if (action == NWAM_ACTION_ADD) {
1210*6ba597c5SAnurag S. Maskey 		nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
1211*6ba597c5SAnurag S. Maskey 		    ncu_obj->nwamd_object_name,
1212*6ba597c5SAnurag S. Maskey 		    NWAM_STATE_OFFLINE, NWAM_AUX_STATE_CONDITIONS_NOT_MET);
1213*6ba597c5SAnurag S. Maskey 	} else {
1214*6ba597c5SAnurag S. Maskey 		if (ncu->ncu_enabled) {
1215*6ba597c5SAnurag S. Maskey 			nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
1216*6ba597c5SAnurag S. Maskey 			    ncu_obj->nwamd_object_name,
1217*6ba597c5SAnurag S. Maskey 			    NWAM_STATE_ONLINE_TO_OFFLINE,
1218*6ba597c5SAnurag S. Maskey 			    NWAM_AUX_STATE_NOT_FOUND);
1219*6ba597c5SAnurag S. Maskey 		} else {
1220*6ba597c5SAnurag S. Maskey 			nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
1221*6ba597c5SAnurag S. Maskey 			    ncu_obj->nwamd_object_name,
1222*6ba597c5SAnurag S. Maskey 			    NWAM_STATE_UNINITIALIZED,
1223*6ba597c5SAnurag S. Maskey 			    NWAM_AUX_STATE_NOT_FOUND);
1224*6ba597c5SAnurag S. Maskey 		}
1225*6ba597c5SAnurag S. Maskey 	}
1226*6ba597c5SAnurag S. Maskey 	nwamd_object_release(ncu_obj);
1227*6ba597c5SAnurag S. Maskey }
1228*6ba597c5SAnurag S. Maskey 
1229*6ba597c5SAnurag S. Maskey /*
1230*6ba597c5SAnurag S. Maskey  * Called with hotplug sysevent or when nwam is started and walking the
1231*6ba597c5SAnurag S. Maskey  * physical interfaces.  Add/remove both link and interface NCUs from the
1232*6ba597c5SAnurag S. Maskey  * Automatic NCP.  Assumes that both link and interface NCUs don't exist.
1233*6ba597c5SAnurag S. Maskey  */
1234*6ba597c5SAnurag S. Maskey void
1235*6ba597c5SAnurag S. Maskey nwamd_ncu_handle_link_action_event(nwamd_event_t event)
1236*6ba597c5SAnurag S. Maskey {
1237*6ba597c5SAnurag S. Maskey 	nwam_ncp_handle_t ncph;
1238*6ba597c5SAnurag S. Maskey 	nwam_ncu_type_t type;
1239*6ba597c5SAnurag S. Maskey 	nwam_action_t action =
1240*6ba597c5SAnurag S. Maskey 	    event->event_msg->nwe_data.nwe_link_action.nwe_action;
1241*6ba597c5SAnurag S. Maskey 	nwam_error_t err;
1242*6ba597c5SAnurag S. Maskey 	char *name;
1243*6ba597c5SAnurag S. Maskey 	boolean_t automatic_ncp_active = B_FALSE;
1244*6ba597c5SAnurag S. Maskey 
1245*6ba597c5SAnurag S. Maskey 	if (action != NWAM_ACTION_ADD && action != NWAM_ACTION_REMOVE) {
1246*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_ncu_handle_link_action_event: "
1247*6ba597c5SAnurag S. Maskey 		    "invalid link action %s", nwam_action_to_string(action));
1248*6ba597c5SAnurag S. Maskey 		nwamd_event_do_not_send(event);
1249*6ba597c5SAnurag S. Maskey 		return;
1250*6ba597c5SAnurag S. Maskey 	}
1251*6ba597c5SAnurag S. Maskey 
1252*6ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "nwamd_ncu_handle_link_action_event: "
1253*6ba597c5SAnurag S. Maskey 	    "link action '%s' event on %s", nwam_action_to_string(action),
1254*6ba597c5SAnurag S. Maskey 	    event->event_object[0] == 0 ? "n/a" : event->event_object);
1255*6ba597c5SAnurag S. Maskey 
1256*6ba597c5SAnurag S. Maskey 	if ((err = nwam_ncu_typed_name_to_name(event->event_object, &type,
1257*6ba597c5SAnurag S. Maskey 	    &name)) != NWAM_SUCCESS) {
1258*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_ncu_handle_link_action_event: "
1259*6ba597c5SAnurag S. Maskey 		    "translation from typedname error: %s", nwam_strerror(err));
1260*6ba597c5SAnurag S. Maskey 		nwamd_event_do_not_send(event);
1261*6ba597c5SAnurag S. Maskey 		return;
1262*6ba597c5SAnurag S. Maskey 	}
1263*6ba597c5SAnurag S. Maskey 
1264*6ba597c5SAnurag S. Maskey 	(void) pthread_mutex_lock(&active_ncp_mutex);
1265*6ba597c5SAnurag S. Maskey 	if (strcmp(active_ncp, NWAM_NCP_NAME_AUTOMATIC) == 0 &&
1266*6ba597c5SAnurag S. Maskey 	    active_ncph != NULL) {
1267*6ba597c5SAnurag S. Maskey 		automatic_ncp_active = B_TRUE;
1268*6ba597c5SAnurag S. Maskey 	}
1269*6ba597c5SAnurag S. Maskey 	(void) pthread_mutex_unlock(&active_ncp_mutex);
1270*6ba597c5SAnurag S. Maskey 
1271*6ba597c5SAnurag S. Maskey 	/*
1272*6ba597c5SAnurag S. Maskey 	 * We could use active_ncph for cases where the Automatic NCP is active,
1273*6ba597c5SAnurag S. Maskey 	 * but that would involve holding the active_ncp_mutex for too long.
1274*6ba597c5SAnurag S. Maskey 	 */
1275*6ba597c5SAnurag S. Maskey 	if ((err = nwam_ncp_read(NWAM_NCP_NAME_AUTOMATIC, 0, &ncph))
1276*6ba597c5SAnurag S. Maskey 	    == NWAM_ENTITY_NOT_FOUND) {
1277*6ba597c5SAnurag S. Maskey 		/* Automatic NCP doesn't exist, create it */
1278*6ba597c5SAnurag S. Maskey 		if ((err = nwam_ncp_create(NWAM_NCP_NAME_AUTOMATIC, 0,
1279*6ba597c5SAnurag S. Maskey 		    &ncph)) != NWAM_SUCCESS) {
1280*6ba597c5SAnurag S. Maskey 			nlog(LOG_ERR,
1281*6ba597c5SAnurag S. Maskey 			    "nwamd_ncu_handle_link_action_event: "
1282*6ba597c5SAnurag S. Maskey 			    "could not create %s NCP: %s",
1283*6ba597c5SAnurag S. Maskey 			    NWAM_NCP_NAME_AUTOMATIC,
1284*6ba597c5SAnurag S. Maskey 			    nwam_strerror(err));
1285*6ba597c5SAnurag S. Maskey 			goto cleanup_exit;
1286*6ba597c5SAnurag S. Maskey 		}
1287*6ba597c5SAnurag S. Maskey 	} else if (err != NWAM_SUCCESS) {
1288*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_ncu_handle_link_action_event: "
1289*6ba597c5SAnurag S. Maskey 		    "failed to read Automatic NCP: %s",
1290*6ba597c5SAnurag S. Maskey 		    nwam_strerror(err));
1291*6ba597c5SAnurag S. Maskey 		goto cleanup_exit;
1292*6ba597c5SAnurag S. Maskey 	}
1293*6ba597c5SAnurag S. Maskey 
1294*6ba597c5SAnurag S. Maskey 	/* add or remove NCUs from Automatic NCP */
1295*6ba597c5SAnurag S. Maskey 	if (action == NWAM_ACTION_ADD) {
1296*6ba597c5SAnurag S. Maskey 		add_phys_ncu_to_ncp(ncph, name);
1297*6ba597c5SAnurag S. Maskey 		add_ip_ncu_to_ncp(ncph, name);
1298*6ba597c5SAnurag S. Maskey 	} else {
1299*6ba597c5SAnurag S. Maskey 		/*
1300*6ba597c5SAnurag S. Maskey 		 * Order is important here, remove IP NCU first to prevent
1301*6ba597c5SAnurag S. Maskey 		 * propogation of down event from link to IP.  No need to
1302*6ba597c5SAnurag S. Maskey 		 * create REFRESH or DESTROY events.  They are generated by
1303*6ba597c5SAnurag S. Maskey 		 * nwam_ncu_commit() and nwam_ncu_destroy().
1304*6ba597c5SAnurag S. Maskey 		 */
1305*6ba597c5SAnurag S. Maskey 		remove_ncu_from_ncp(ncph, name, NWAM_NCU_TYPE_INTERFACE);
1306*6ba597c5SAnurag S. Maskey 		remove_ncu_from_ncp(ncph, name, NWAM_NCU_TYPE_LINK);
1307*6ba597c5SAnurag S. Maskey 	}
1308*6ba597c5SAnurag S. Maskey 	nwam_ncp_free(ncph);
1309*6ba597c5SAnurag S. Maskey 
1310*6ba597c5SAnurag S. Maskey 	/*
1311*6ba597c5SAnurag S. Maskey 	 * If the Automatic NCP is not active, and the associated NCUs
1312*6ba597c5SAnurag S. Maskey 	 * exist, they must be moved into the appropriate states given the
1313*6ba597c5SAnurag S. Maskey 	 * action that has occurred.
1314*6ba597c5SAnurag S. Maskey 	 */
1315*6ba597c5SAnurag S. Maskey 	if (!automatic_ncp_active) {
1316*6ba597c5SAnurag S. Maskey 		ncu_action_change_state(action, NWAM_NCU_TYPE_INTERFACE, name);
1317*6ba597c5SAnurag S. Maskey 		ncu_action_change_state(action, NWAM_NCU_TYPE_LINK, name);
1318*6ba597c5SAnurag S. Maskey 	}
1319*6ba597c5SAnurag S. Maskey 
1320*6ba597c5SAnurag S. Maskey 	/* Need NCU check to evaluate state in light of added/removed NCUs */
1321*6ba597c5SAnurag S. Maskey 	if (!nwamd_event_enqueued(NWAM_EVENT_TYPE_NCU_CHECK,
1322*6ba597c5SAnurag S. Maskey 	    NWAM_OBJECT_TYPE_NCP, NULL)) {
1323*6ba597c5SAnurag S. Maskey 		nwamd_create_ncu_check_event(NEXT_FEW_SECONDS);
1324*6ba597c5SAnurag S. Maskey 	}
1325*6ba597c5SAnurag S. Maskey 
1326*6ba597c5SAnurag S. Maskey cleanup_exit:
1327*6ba597c5SAnurag S. Maskey 	free(name);
1328*6ba597c5SAnurag S. Maskey }
1329*6ba597c5SAnurag S. Maskey 
1330*6ba597c5SAnurag S. Maskey /*
1331*6ba597c5SAnurag S. Maskey  * Figure out if this link is part of an aggregation.  This is fairly
1332*6ba597c5SAnurag S. Maskey  * inefficient since we generate this list for every query and search
1333*6ba597c5SAnurag S. Maskey  * linearly.  A better way would be to generate the list of links in an
1334*6ba597c5SAnurag S. Maskey  * aggregation once and then check each link against it.
1335*6ba597c5SAnurag S. Maskey  */
1336*6ba597c5SAnurag S. Maskey struct link_aggr_search_data {
1337*6ba597c5SAnurag S. Maskey 	datalink_id_t linkid;
1338*6ba597c5SAnurag S. Maskey 	boolean_t under;
1339*6ba597c5SAnurag S. Maskey };
1340*6ba597c5SAnurag S. Maskey 
1341*6ba597c5SAnurag S. Maskey static int
1342*6ba597c5SAnurag S. Maskey ncu_aggr_search(const char *name, void *data)
1343*6ba597c5SAnurag S. Maskey {
1344*6ba597c5SAnurag S. Maskey 	struct link_aggr_search_data *lasd = data;
1345*6ba597c5SAnurag S. Maskey 	dladm_aggr_grp_attr_t ginfo;
1346*6ba597c5SAnurag S. Maskey 	datalink_id_t linkid;
1347*6ba597c5SAnurag S. Maskey 	int i;
1348*6ba597c5SAnurag S. Maskey 
1349*6ba597c5SAnurag S. Maskey 	if (dladm_name2info(dld_handle, name, &linkid, NULL, NULL, NULL) !=
1350*6ba597c5SAnurag S. Maskey 	    DLADM_STATUS_OK)
1351*6ba597c5SAnurag S. Maskey 		return (DLADM_WALK_CONTINUE);
1352*6ba597c5SAnurag S. Maskey 	if (dladm_aggr_info(dld_handle, linkid, &ginfo, DLADM_OPT_ACTIVE)
1353*6ba597c5SAnurag S. Maskey 	    != DLADM_STATUS_OK || ginfo.lg_nports == 0)
1354*6ba597c5SAnurag S. Maskey 		return (DLADM_WALK_CONTINUE);
1355*6ba597c5SAnurag S. Maskey 
1356*6ba597c5SAnurag S. Maskey 	for (i = 0; i < ginfo.lg_nports; i++) {
1357*6ba597c5SAnurag S. Maskey 		if (lasd->linkid == ginfo.lg_ports[i].lp_linkid) {
1358*6ba597c5SAnurag S. Maskey 			lasd->under = B_TRUE;
1359*6ba597c5SAnurag S. Maskey 			return (DLADM_WALK_TERMINATE);
1360*6ba597c5SAnurag S. Maskey 		}
1361*6ba597c5SAnurag S. Maskey 	}
1362*6ba597c5SAnurag S. Maskey 	free(ginfo.lg_ports);
1363*6ba597c5SAnurag S. Maskey 	return (DLADM_WALK_CONTINUE);
1364*6ba597c5SAnurag S. Maskey }
1365*6ba597c5SAnurag S. Maskey 
1366*6ba597c5SAnurag S. Maskey static boolean_t
1367*6ba597c5SAnurag S. Maskey nwamd_link_belongs_to_an_aggr(const char *name)
1368*6ba597c5SAnurag S. Maskey {
1369*6ba597c5SAnurag S. Maskey 	struct link_aggr_search_data lasd;
1370*6ba597c5SAnurag S. Maskey 
1371*6ba597c5SAnurag S. Maskey 	if (dladm_name2info(dld_handle, name, &lasd.linkid, NULL, NULL, NULL)
1372*6ba597c5SAnurag S. Maskey 	    != DLADM_STATUS_OK)
1373*6ba597c5SAnurag S. Maskey 		return (B_FALSE);
1374*6ba597c5SAnurag S. Maskey 	lasd.under = B_FALSE;
1375*6ba597c5SAnurag S. Maskey 	(void) dladm_walk(ncu_aggr_search, dld_handle, &lasd,
1376*6ba597c5SAnurag S. Maskey 	    DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
1377*6ba597c5SAnurag S. Maskey 	return (lasd.under);
1378*6ba597c5SAnurag S. Maskey }
1379*6ba597c5SAnurag S. Maskey 
1380*6ba597c5SAnurag S. Maskey /*
1381*6ba597c5SAnurag S. Maskey  * If NCU doesn't exist for interface with given name, enqueue a ADD
1382*6ba597c5SAnurag S. Maskey  * LINK_ACTION event.
1383*6ba597c5SAnurag S. Maskey  */
1384*6ba597c5SAnurag S. Maskey static int
1385*6ba597c5SAnurag S. Maskey ncu_create_link_action_event(const char *name, void *data)
1386*6ba597c5SAnurag S. Maskey {
1387*6ba597c5SAnurag S. Maskey 	nwam_ncp_handle_t ncph = data;
1388*6ba597c5SAnurag S. Maskey 	nwam_ncu_handle_t ncuh;
1389*6ba597c5SAnurag S. Maskey 	nwamd_event_t link_event;
1390*6ba597c5SAnurag S. Maskey 
1391*6ba597c5SAnurag S. Maskey 	/* Do not generate an event if this is a VirtualBox interface. */
1392*6ba597c5SAnurag S. Maskey 	if (strncmp(name, VBOX_IFACE_PREFIX, strlen(VBOX_IFACE_PREFIX)) == 0)
1393*6ba597c5SAnurag S. Maskey 		return (DLADM_WALK_CONTINUE);
1394*6ba597c5SAnurag S. Maskey 
1395*6ba597c5SAnurag S. Maskey 	/* Do not generate an event if this link belongs to another zone. */
1396*6ba597c5SAnurag S. Maskey 	if (!nwamd_link_belongs_to_this_zone(name))
1397*6ba597c5SAnurag S. Maskey 		return (DLADM_WALK_CONTINUE);
1398*6ba597c5SAnurag S. Maskey 
1399*6ba597c5SAnurag S. Maskey 	/* Do not generate an event if this link belongs to an aggregation. */
1400*6ba597c5SAnurag S. Maskey 	if (nwamd_link_belongs_to_an_aggr(name)) {
1401*6ba597c5SAnurag S. Maskey 		return (DLADM_WALK_CONTINUE);
1402*6ba597c5SAnurag S. Maskey 	}
1403*6ba597c5SAnurag S. Maskey 
1404*6ba597c5SAnurag S. Maskey 	/* Don't create an event if the NCU already exists. */
1405*6ba597c5SAnurag S. Maskey 	if (ncph != NULL && nwam_ncu_read(ncph, name, NWAM_NCU_TYPE_LINK, 0,
1406*6ba597c5SAnurag S. Maskey 	    &ncuh) == NWAM_SUCCESS) {
1407*6ba597c5SAnurag S. Maskey 		nwam_ncu_free(ncuh);
1408*6ba597c5SAnurag S. Maskey 		return (DLADM_WALK_CONTINUE);
1409*6ba597c5SAnurag S. Maskey 	}
1410*6ba597c5SAnurag S. Maskey 
1411*6ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "ncu_create_link_action_event: adding ncus for %s",
1412*6ba597c5SAnurag S. Maskey 	    name);
1413*6ba597c5SAnurag S. Maskey 
1414*6ba597c5SAnurag S. Maskey 	link_event = nwamd_event_init_link_action(name, NWAM_ACTION_ADD);
1415*6ba597c5SAnurag S. Maskey 	if (link_event != NULL)
1416*6ba597c5SAnurag S. Maskey 		nwamd_event_enqueue(link_event);
1417*6ba597c5SAnurag S. Maskey 
1418*6ba597c5SAnurag S. Maskey 	return (DLADM_WALK_CONTINUE);
1419*6ba597c5SAnurag S. Maskey }
1420*6ba597c5SAnurag S. Maskey 
1421*6ba597c5SAnurag S. Maskey /*
1422*6ba597c5SAnurag S. Maskey  * Check if interface exists for this NCU. If not, enqueue a REMOVE
1423*6ba597c5SAnurag S. Maskey  * LINK_ACTION event.
1424*6ba597c5SAnurag S. Maskey  */
1425*6ba597c5SAnurag S. Maskey /* ARGSUSED */
1426*6ba597c5SAnurag S. Maskey static int
1427*6ba597c5SAnurag S. Maskey nwamd_destroy_ncu(nwam_ncu_handle_t ncuh, void *data)
1428*6ba597c5SAnurag S. Maskey {
1429*6ba597c5SAnurag S. Maskey 	char *name;
1430*6ba597c5SAnurag S. Maskey 	uint32_t flags;
1431*6ba597c5SAnurag S. Maskey 	nwamd_event_t link_event;
1432*6ba597c5SAnurag S. Maskey 
1433*6ba597c5SAnurag S. Maskey 	if (nwam_ncu_get_name(ncuh, &name) != NWAM_SUCCESS) {
1434*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_destroy_ncu: could not get NCU name");
1435*6ba597c5SAnurag S. Maskey 		return (0);
1436*6ba597c5SAnurag S. Maskey 	}
1437*6ba597c5SAnurag S. Maskey 
1438*6ba597c5SAnurag S. Maskey 	/* Interfaces that exist return DLADM_OPT_ACTIVE flag */
1439*6ba597c5SAnurag S. Maskey 	if ((dladm_name2info(dld_handle, name, NULL, &flags, NULL, NULL)
1440*6ba597c5SAnurag S. Maskey 	    == DLADM_STATUS_OK && (flags & DLADM_OPT_ACTIVE)) &&
1441*6ba597c5SAnurag S. Maskey 	    !nwamd_link_belongs_to_an_aggr(name)) {
1442*6ba597c5SAnurag S. Maskey 		free(name);
1443*6ba597c5SAnurag S. Maskey 		return (0);
1444*6ba597c5SAnurag S. Maskey 	}
1445*6ba597c5SAnurag S. Maskey 
1446*6ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "nwamd_destroy_ncu: destroying ncus for %s", name);
1447*6ba597c5SAnurag S. Maskey 
1448*6ba597c5SAnurag S. Maskey 	link_event = nwamd_event_init_link_action(name, NWAM_ACTION_REMOVE);
1449*6ba597c5SAnurag S. Maskey 	if (link_event != NULL)
1450*6ba597c5SAnurag S. Maskey 		nwamd_event_enqueue(link_event);
1451*6ba597c5SAnurag S. Maskey 	free(name);
1452*6ba597c5SAnurag S. Maskey 	return (0);
1453*6ba597c5SAnurag S. Maskey }
1454*6ba597c5SAnurag S. Maskey 
1455*6ba597c5SAnurag S. Maskey /*
1456*6ba597c5SAnurag S. Maskey  * Called when nwamd is starting up.
1457*6ba597c5SAnurag S. Maskey  *
1458*6ba597c5SAnurag S. Maskey  * Walk all NCUs and destroy any NCU from the Automatic NCP without an
1459*6ba597c5SAnurag S. Maskey  * underlying interface (assumption here is that the interface was removed
1460*6ba597c5SAnurag S. Maskey  * when nwam was disabled).
1461*6ba597c5SAnurag S. Maskey  *
1462*6ba597c5SAnurag S. Maskey  * Walk the physical interfaces and create ADD LINK_ACTION event, which
1463*6ba597c5SAnurag S. Maskey  * will create appropriate interface and link NCUs in the Automatic NCP.
1464*6ba597c5SAnurag S. Maskey  */
1465*6ba597c5SAnurag S. Maskey void
1466*6ba597c5SAnurag S. Maskey nwamd_walk_physical_configuration(void)
1467*6ba597c5SAnurag S. Maskey {
1468*6ba597c5SAnurag S. Maskey 	nwam_ncp_handle_t ncph;
1469*6ba597c5SAnurag S. Maskey 
1470*6ba597c5SAnurag S. Maskey 	(void) pthread_mutex_lock(&active_ncp_mutex);
1471*6ba597c5SAnurag S. Maskey 	if (strcmp(active_ncp, NWAM_NCP_NAME_AUTOMATIC) == 0 &&
1472*6ba597c5SAnurag S. Maskey 	    active_ncph != NULL) {
1473*6ba597c5SAnurag S. Maskey 		ncph = active_ncph;
1474*6ba597c5SAnurag S. Maskey 	} else {
1475*6ba597c5SAnurag S. Maskey 		if (nwam_ncp_read(NWAM_NCP_NAME_AUTOMATIC, 0, &ncph)
1476*6ba597c5SAnurag S. Maskey 		    != NWAM_SUCCESS) {
1477*6ba597c5SAnurag S. Maskey 			ncph = NULL;
1478*6ba597c5SAnurag S. Maskey 		}
1479*6ba597c5SAnurag S. Maskey 	}
1480*6ba597c5SAnurag S. Maskey 
1481*6ba597c5SAnurag S. Maskey 	/* destroy NCUs for interfaces that don't exist */
1482*6ba597c5SAnurag S. Maskey 	if (ncph != NULL) {
1483*6ba597c5SAnurag S. Maskey 		(void) nwam_ncp_walk_ncus(ncph, nwamd_destroy_ncu, NULL,
1484*6ba597c5SAnurag S. Maskey 		    NWAM_FLAG_NCU_TYPE_LINK, NULL);
1485*6ba597c5SAnurag S. Maskey 	}
1486*6ba597c5SAnurag S. Maskey 
1487*6ba597c5SAnurag S. Maskey 	/* create NCUs for interfaces without NCUs */
1488*6ba597c5SAnurag S. Maskey 	(void) dladm_walk(ncu_create_link_action_event, dld_handle, ncph,
1489*6ba597c5SAnurag S. Maskey 	    DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
1490*6ba597c5SAnurag S. Maskey 
1491*6ba597c5SAnurag S. Maskey 	if (strcmp(active_ncp, NWAM_NCP_NAME_AUTOMATIC) != 0 ||
1492*6ba597c5SAnurag S. Maskey 	    active_ncph == NULL) {
1493*6ba597c5SAnurag S. Maskey 		nwam_ncp_free(ncph);
1494*6ba597c5SAnurag S. Maskey 	}
1495*6ba597c5SAnurag S. Maskey 	(void) pthread_mutex_unlock(&active_ncp_mutex);
1496*6ba597c5SAnurag S. Maskey }
1497*6ba597c5SAnurag S. Maskey 
1498*6ba597c5SAnurag S. Maskey /*
1499*6ba597c5SAnurag S. Maskey  * Handle NCU initialization/refresh event.
1500*6ba597c5SAnurag S. Maskey  */
1501*6ba597c5SAnurag S. Maskey void
1502*6ba597c5SAnurag S. Maskey nwamd_ncu_handle_init_event(nwamd_event_t event)
1503*6ba597c5SAnurag S. Maskey {
1504*6ba597c5SAnurag S. Maskey 	nwamd_object_t object = NULL;
1505*6ba597c5SAnurag S. Maskey 	nwam_ncu_handle_t ncuh;
1506*6ba597c5SAnurag S. Maskey 	nwamd_ncu_t *ncu = NULL;
1507*6ba597c5SAnurag S. Maskey 	nwam_error_t err;
1508*6ba597c5SAnurag S. Maskey 	nwam_ncu_type_t type;
1509*6ba597c5SAnurag S. Maskey 	char *name;
1510*6ba597c5SAnurag S. Maskey 	uint32_t flags;
1511*6ba597c5SAnurag S. Maskey 	boolean_t new = B_TRUE;
1512*6ba597c5SAnurag S. Maskey 
1513*6ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "nwamd_ncu_handle_init_event(%s)",
1514*6ba597c5SAnurag S. Maskey 	    event->event_object);
1515*6ba597c5SAnurag S. Maskey 
1516*6ba597c5SAnurag S. Maskey 	/* Get base linkname rather than interface:linkname or link:linkname */
1517*6ba597c5SAnurag S. Maskey 	err = nwam_ncu_typed_name_to_name(event->event_object,
1518*6ba597c5SAnurag S. Maskey 	    &type, &name);
1519*6ba597c5SAnurag S. Maskey 	if (err != NWAM_SUCCESS) {
1520*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_ncu_handle_init_event: "
1521*6ba597c5SAnurag S. Maskey 		    "nwam_ncu_typed_name_to_name returned %s",
1522*6ba597c5SAnurag S. Maskey 		    nwam_strerror(err));
1523*6ba597c5SAnurag S. Maskey 		nwamd_event_do_not_send(event);
1524*6ba597c5SAnurag S. Maskey 		return;
1525*6ba597c5SAnurag S. Maskey 	}
1526*6ba597c5SAnurag S. Maskey 
1527*6ba597c5SAnurag S. Maskey 	(void) pthread_mutex_lock(&active_ncp_mutex);
1528*6ba597c5SAnurag S. Maskey 	if (active_ncph == NULL) {
1529*6ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG,
1530*6ba597c5SAnurag S. Maskey 		    "nwamd_ncu_handle_init_event: active NCP handle NULL");
1531*6ba597c5SAnurag S. Maskey 		nwamd_event_do_not_send(event);
1532*6ba597c5SAnurag S. Maskey 		(void) pthread_mutex_unlock(&active_ncp_mutex);
1533*6ba597c5SAnurag S. Maskey 		return;
1534*6ba597c5SAnurag S. Maskey 	}
1535*6ba597c5SAnurag S. Maskey 	err = nwam_ncu_read(active_ncph, event->event_object,
1536*6ba597c5SAnurag S. Maskey 	    type, 0, &ncuh);
1537*6ba597c5SAnurag S. Maskey 	(void) pthread_mutex_unlock(&active_ncp_mutex);
1538*6ba597c5SAnurag S. Maskey 	if (err != NWAM_SUCCESS) {
1539*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_ncu_handle_init_event: "
1540*6ba597c5SAnurag S. Maskey 		    "could not read object '%s': %s",
1541*6ba597c5SAnurag S. Maskey 		    event->event_object, nwam_strerror(err));
1542*6ba597c5SAnurag S. Maskey 		free(name);
1543*6ba597c5SAnurag S. Maskey 		nwamd_event_do_not_send(event);
1544*6ba597c5SAnurag S. Maskey 		return;
1545*6ba597c5SAnurag S. Maskey 	}
1546*6ba597c5SAnurag S. Maskey 
1547*6ba597c5SAnurag S. Maskey 	if ((object = nwamd_object_find(NWAM_OBJECT_TYPE_NCU,
1548*6ba597c5SAnurag S. Maskey 	    event->event_object)) != NULL)
1549*6ba597c5SAnurag S. Maskey 		new = B_FALSE;
1550*6ba597c5SAnurag S. Maskey 
1551*6ba597c5SAnurag S. Maskey 	/*
1552*6ba597c5SAnurag S. Maskey 	 * For new NCUs, or interface NCUs, we (re)initialize data from scratch.
1553*6ba597c5SAnurag S. Maskey 	 * For link NCUs, we want to retain object data.
1554*6ba597c5SAnurag S. Maskey 	 */
1555*6ba597c5SAnurag S. Maskey 	switch (type) {
1556*6ba597c5SAnurag S. Maskey 	case NWAM_NCU_TYPE_LINK:
1557*6ba597c5SAnurag S. Maskey 		if (new) {
1558*6ba597c5SAnurag S. Maskey 			ncu = nwamd_ncu_init(type, name);
1559*6ba597c5SAnurag S. Maskey 		} else {
1560*6ba597c5SAnurag S. Maskey 			ncu = object->nwamd_object_data;
1561*6ba597c5SAnurag S. Maskey 			nwam_ncu_free(object->nwamd_object_handle);
1562*6ba597c5SAnurag S. Maskey 		}
1563*6ba597c5SAnurag S. Maskey 		populate_common_ncu_properties(ncuh, ncu);
1564*6ba597c5SAnurag S. Maskey 		populate_link_ncu_properties(ncuh, ncu);
1565*6ba597c5SAnurag S. Maskey 		break;
1566*6ba597c5SAnurag S. Maskey 	case NWAM_NCU_TYPE_INTERFACE:
1567*6ba597c5SAnurag S. Maskey 		if (!new) {
1568*6ba597c5SAnurag S. Maskey 			nwam_ncu_free(object->nwamd_object_handle);
1569*6ba597c5SAnurag S. Maskey 			nwamd_ncu_free(object->nwamd_object_data);
1570*6ba597c5SAnurag S. Maskey 		}
1571*6ba597c5SAnurag S. Maskey 		ncu = nwamd_ncu_init(type, name);
1572*6ba597c5SAnurag S. Maskey 		populate_common_ncu_properties(ncuh, ncu);
1573*6ba597c5SAnurag S. Maskey 		populate_ip_ncu_properties(ncuh, ncu);
1574*6ba597c5SAnurag S. Maskey 		break;
1575*6ba597c5SAnurag S. Maskey 	default:
1576*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "unknown ncu type %d", type);
1577*6ba597c5SAnurag S. Maskey 		free(name);
1578*6ba597c5SAnurag S. Maskey 		nwam_ncu_free(ncuh);
1579*6ba597c5SAnurag S. Maskey 		nwamd_event_do_not_send(event);
1580*6ba597c5SAnurag S. Maskey 		nwamd_object_release(object);
1581*6ba597c5SAnurag S. Maskey 		return;
1582*6ba597c5SAnurag S. Maskey 	}
1583*6ba597c5SAnurag S. Maskey 
1584*6ba597c5SAnurag S. Maskey 	if (new) {
1585*6ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "nwamd_ncu_handle_init_event: didn't find "
1586*6ba597c5SAnurag S. Maskey 		    "ncu so create it %s", name);
1587*6ba597c5SAnurag S. Maskey 		object = nwamd_object_init(NWAM_OBJECT_TYPE_NCU,
1588*6ba597c5SAnurag S. Maskey 		    event->event_object, ncuh, ncu);
1589*6ba597c5SAnurag S. Maskey 	} else {
1590*6ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "nwamd_ncu_handle_init_event: refreshing "
1591*6ba597c5SAnurag S. Maskey 		    "ncu %s", name);
1592*6ba597c5SAnurag S. Maskey 		object->nwamd_object_data = ncu;
1593*6ba597c5SAnurag S. Maskey 		object->nwamd_object_handle = ncuh;
1594*6ba597c5SAnurag S. Maskey 	}
1595*6ba597c5SAnurag S. Maskey 
1596*6ba597c5SAnurag S. Maskey 	/*
1597*6ba597c5SAnurag S. Maskey 	 * If the physical link for this NCU doesn't exist in the system,
1598*6ba597c5SAnurag S. Maskey 	 * the state should be UNINITIALIZED/NOT_FOUND.  Interfaces that
1599*6ba597c5SAnurag S. Maskey 	 * exist return DLADM_OPT_ACTIVE flag.
1600*6ba597c5SAnurag S. Maskey 	 */
1601*6ba597c5SAnurag S. Maskey 	if (dladm_name2info(dld_handle, name, NULL, &flags, NULL, NULL)
1602*6ba597c5SAnurag S. Maskey 	    != DLADM_STATUS_OK || !(flags & DLADM_OPT_ACTIVE)) {
1603*6ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "nwam_ncu_handle_init_event: "
1604*6ba597c5SAnurag S. Maskey 		    "interface for NCU %s doesn't exist",
1605*6ba597c5SAnurag S. Maskey 		    event->event_object);
1606*6ba597c5SAnurag S. Maskey 		nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
1607*6ba597c5SAnurag S. Maskey 		    object->nwamd_object_name, NWAM_STATE_UNINITIALIZED,
1608*6ba597c5SAnurag S. Maskey 		    NWAM_AUX_STATE_NOT_FOUND);
1609*6ba597c5SAnurag S. Maskey 		free(name);
1610*6ba597c5SAnurag S. Maskey 		nwamd_object_release(object);
1611*6ba597c5SAnurag S. Maskey 		return;
1612*6ba597c5SAnurag S. Maskey 	}
1613*6ba597c5SAnurag S. Maskey 
1614*6ba597c5SAnurag S. Maskey 	/*
1615*6ba597c5SAnurag S. Maskey 	 * If NCU is being initialized (rather than refreshed), the
1616*6ba597c5SAnurag S. Maskey 	 * object_state is INITIALIZED (from nwamd_object_init()).
1617*6ba597c5SAnurag S. Maskey 	 */
1618*6ba597c5SAnurag S. Maskey 	if (object->nwamd_object_state == NWAM_STATE_INITIALIZED) {
1619*6ba597c5SAnurag S. Maskey 		/*
1620*6ba597c5SAnurag S. Maskey 		 * If the NCU is disabled, initial state should be DISABLED.
1621*6ba597c5SAnurag S. Maskey 		 *
1622*6ba597c5SAnurag S. Maskey 		 * Otherwise, the initial state will be
1623*6ba597c5SAnurag S. Maskey 		 * OFFLINE/CONDITIONS_NOT_MET, and the link selection
1624*6ba597c5SAnurag S. Maskey 		 * algorithm will do the rest.
1625*6ba597c5SAnurag S. Maskey 		 */
1626*6ba597c5SAnurag S. Maskey 		if (!ncu->ncu_enabled) {
1627*6ba597c5SAnurag S. Maskey 			object->nwamd_object_state = NWAM_STATE_DISABLED;
1628*6ba597c5SAnurag S. Maskey 			object->nwamd_object_aux_state =
1629*6ba597c5SAnurag S. Maskey 			    NWAM_AUX_STATE_MANUAL_DISABLE;
1630*6ba597c5SAnurag S. Maskey 		} else {
1631*6ba597c5SAnurag S. Maskey 			object->nwamd_object_state = NWAM_STATE_OFFLINE;
1632*6ba597c5SAnurag S. Maskey 			object->nwamd_object_aux_state =
1633*6ba597c5SAnurag S. Maskey 			    NWAM_AUX_STATE_CONDITIONS_NOT_MET;
1634*6ba597c5SAnurag S. Maskey 		}
1635*6ba597c5SAnurag S. Maskey 	} else {
1636*6ba597c5SAnurag S. Maskey 		nwamd_link_t *link = &ncu->ncu_node.u_link;
1637*6ba597c5SAnurag S. Maskey 
1638*6ba597c5SAnurag S. Maskey 		/*
1639*6ba597c5SAnurag S. Maskey 		 * Refresh NCU.  Deal with disabled cases first, moving NCUs
1640*6ba597c5SAnurag S. Maskey 		 * that are not disabled - but have the enabled value set - to
1641*6ba597c5SAnurag S. Maskey 		 * the disabled state.  Then handle cases where the NCU was
1642*6ba597c5SAnurag S. Maskey 		 * disabled but is no longer.  Finally,  deal with refresh of
1643*6ba597c5SAnurag S. Maskey 		 * link and interface NCUs, as these are handled differently.
1644*6ba597c5SAnurag S. Maskey 		 */
1645*6ba597c5SAnurag S. Maskey 		if (!ncu->ncu_enabled) {
1646*6ba597c5SAnurag S. Maskey 			if (object->nwamd_object_state != NWAM_STATE_DISABLED) {
1647*6ba597c5SAnurag S. Maskey 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
1648*6ba597c5SAnurag S. Maskey 				    object->nwamd_object_name,
1649*6ba597c5SAnurag S. Maskey 				    NWAM_STATE_ONLINE_TO_OFFLINE,
1650*6ba597c5SAnurag S. Maskey 				    NWAM_AUX_STATE_MANUAL_DISABLE);
1651*6ba597c5SAnurag S. Maskey 			}
1652*6ba597c5SAnurag S. Maskey 			goto done;
1653*6ba597c5SAnurag S. Maskey 		} else {
1654*6ba597c5SAnurag S. Maskey 			if (object->nwamd_object_state == NWAM_STATE_DISABLED) {
1655*6ba597c5SAnurag S. Maskey 				int64_t c;
1656*6ba597c5SAnurag S. Maskey 
1657*6ba597c5SAnurag S. Maskey 				/*
1658*6ba597c5SAnurag S. Maskey 				 * Try to activate the NCU if manual or
1659*6ba597c5SAnurag S. Maskey 				 * prioritized (when priority <= current).
1660*6ba597c5SAnurag S. Maskey 				 */
1661*6ba597c5SAnurag S. Maskey 				(void) pthread_mutex_lock(&active_ncp_mutex);
1662*6ba597c5SAnurag S. Maskey 				c = current_ncu_priority_group;
1663*6ba597c5SAnurag S. Maskey 				(void) pthread_mutex_unlock(&active_ncp_mutex);
1664*6ba597c5SAnurag S. Maskey 				if (link->nwamd_link_activation_mode ==
1665*6ba597c5SAnurag S. Maskey 				    NWAM_ACTIVATION_MODE_MANUAL ||
1666*6ba597c5SAnurag S. Maskey 				    (link->nwamd_link_activation_mode ==
1667*6ba597c5SAnurag S. Maskey 				    NWAM_ACTIVATION_MODE_PRIORITIZED &&
1668*6ba597c5SAnurag S. Maskey 				    link->nwamd_link_priority_mode <= c)) {
1669*6ba597c5SAnurag S. Maskey 					nwamd_object_set_state
1670*6ba597c5SAnurag S. Maskey 					    (NWAM_OBJECT_TYPE_NCU,
1671*6ba597c5SAnurag S. Maskey 					    object->nwamd_object_name,
1672*6ba597c5SAnurag S. Maskey 					    NWAM_STATE_OFFLINE_TO_ONLINE,
1673*6ba597c5SAnurag S. Maskey 					    NWAM_AUX_STATE_INITIALIZED);
1674*6ba597c5SAnurag S. Maskey 				} else {
1675*6ba597c5SAnurag S. Maskey 					nwamd_object_set_state
1676*6ba597c5SAnurag S. Maskey 					    (NWAM_OBJECT_TYPE_NCU,
1677*6ba597c5SAnurag S. Maskey 					    object->nwamd_object_name,
1678*6ba597c5SAnurag S. Maskey 					    NWAM_STATE_OFFLINE_TO_ONLINE,
1679*6ba597c5SAnurag S. Maskey 					    NWAM_AUX_STATE_INITIALIZED);
1680*6ba597c5SAnurag S. Maskey 				}
1681*6ba597c5SAnurag S. Maskey 				goto done;
1682*6ba597c5SAnurag S. Maskey 			}
1683*6ba597c5SAnurag S. Maskey 		}
1684*6ba597c5SAnurag S. Maskey 
1685*6ba597c5SAnurag S. Maskey 		switch (type) {
1686*6ba597c5SAnurag S. Maskey 		case NWAM_NCU_TYPE_LINK:
1687*6ba597c5SAnurag S. Maskey 			if (ncu->ncu_node.u_link.nwamd_link_media == DL_WIFI) {
1688*6ba597c5SAnurag S. Maskey 				/*
1689*6ba597c5SAnurag S. Maskey 				 * Do rescan.  If the current state and the
1690*6ba597c5SAnurag S. Maskey 				 * active priority-group do not allow wireless
1691*6ba597c5SAnurag S. Maskey 				 * network selection, then it won't happen.
1692*6ba597c5SAnurag S. Maskey 				 */
1693*6ba597c5SAnurag S. Maskey 				(void) nwamd_wlan_scan(ncu->ncu_name);
1694*6ba597c5SAnurag S. Maskey 			}
1695*6ba597c5SAnurag S. Maskey 			break;
1696*6ba597c5SAnurag S. Maskey 		case NWAM_NCU_TYPE_INTERFACE:
1697*6ba597c5SAnurag S. Maskey 			/*
1698*6ba597c5SAnurag S. Maskey 			 * If interface NCU is offline*, online or in
1699*6ba597c5SAnurag S. Maskey 			 * maintenance, mark it down (from there, it will be
1700*6ba597c5SAnurag S. Maskey 			 * reinitialized to reapply addresses).
1701*6ba597c5SAnurag S. Maskey 			 */
1702*6ba597c5SAnurag S. Maskey 			if (object->nwamd_object_state != NWAM_STATE_OFFLINE) {
1703*6ba597c5SAnurag S. Maskey 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
1704*6ba597c5SAnurag S. Maskey 				    object->nwamd_object_name,
1705*6ba597c5SAnurag S. Maskey 				    NWAM_STATE_ONLINE_TO_OFFLINE,
1706*6ba597c5SAnurag S. Maskey 				    NWAM_AUX_STATE_DOWN);
1707*6ba597c5SAnurag S. Maskey 			} else {
1708*6ba597c5SAnurag S. Maskey 				object->nwamd_object_state = NWAM_STATE_OFFLINE;
1709*6ba597c5SAnurag S. Maskey 				object->nwamd_object_aux_state =
1710*6ba597c5SAnurag S. Maskey 				    NWAM_AUX_STATE_CONDITIONS_NOT_MET;
1711*6ba597c5SAnurag S. Maskey 			}
1712*6ba597c5SAnurag S. Maskey 			break;
1713*6ba597c5SAnurag S. Maskey 		}
1714*6ba597c5SAnurag S. Maskey 	}
1715*6ba597c5SAnurag S. Maskey 
1716*6ba597c5SAnurag S. Maskey done:
1717*6ba597c5SAnurag S. Maskey 	if (type == NWAM_NCU_TYPE_LINK &&
1718*6ba597c5SAnurag S. Maskey 	    !nwamd_event_enqueued(NWAM_EVENT_TYPE_NCU_CHECK,
1719*6ba597c5SAnurag S. Maskey 	    NWAM_OBJECT_TYPE_NCP, NULL)) {
1720*6ba597c5SAnurag S. Maskey 		nwamd_create_ncu_check_event(NEXT_FEW_SECONDS);
1721*6ba597c5SAnurag S. Maskey 	}
1722*6ba597c5SAnurag S. Maskey 	free(name);
1723*6ba597c5SAnurag S. Maskey 	nwamd_object_release(object);
1724*6ba597c5SAnurag S. Maskey }
1725*6ba597c5SAnurag S. Maskey 
1726*6ba597c5SAnurag S. Maskey void
1727*6ba597c5SAnurag S. Maskey nwamd_ncu_handle_fini_event(nwamd_event_t event)
1728*6ba597c5SAnurag S. Maskey {
1729*6ba597c5SAnurag S. Maskey 	nwamd_object_t object;
1730*6ba597c5SAnurag S. Maskey 	nwamd_event_t state_event;
1731*6ba597c5SAnurag S. Maskey 
1732*6ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "nwamd_ncu_handle_fini_event(%s)",
1733*6ba597c5SAnurag S. Maskey 	    event->event_object);
1734*6ba597c5SAnurag S. Maskey 
1735*6ba597c5SAnurag S. Maskey 	/*
1736*6ba597c5SAnurag S. Maskey 	 * Simulate a state event so that the state machine can correctly
1737*6ba597c5SAnurag S. Maskey 	 * disable the NCU.  Then free up allocated objects.
1738*6ba597c5SAnurag S. Maskey 	 */
1739*6ba597c5SAnurag S. Maskey 	state_event = nwamd_event_init_object_state(NWAM_OBJECT_TYPE_NCU,
1740*6ba597c5SAnurag S. Maskey 	    event->event_object, NWAM_STATE_ONLINE_TO_OFFLINE,
1741*6ba597c5SAnurag S. Maskey 	    NWAM_AUX_STATE_UNINITIALIZED);
1742*6ba597c5SAnurag S. Maskey 	if (state_event == NULL) {
1743*6ba597c5SAnurag S. Maskey 		nwamd_event_do_not_send(event);
1744*6ba597c5SAnurag S. Maskey 		return;
1745*6ba597c5SAnurag S. Maskey 	}
1746*6ba597c5SAnurag S. Maskey 	nwamd_ncu_handle_state_event(state_event);
1747*6ba597c5SAnurag S. Maskey 	nwamd_event_fini(state_event);
1748*6ba597c5SAnurag S. Maskey 
1749*6ba597c5SAnurag S. Maskey 	if ((object = nwamd_object_find(NWAM_OBJECT_TYPE_NCU,
1750*6ba597c5SAnurag S. Maskey 	    event->event_object)) == NULL) {
1751*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_ncu_handle_fini_event: "
1752*6ba597c5SAnurag S. Maskey 		    "ncu %s not found", event->event_object);
1753*6ba597c5SAnurag S. Maskey 		nwamd_event_do_not_send(event);
1754*6ba597c5SAnurag S. Maskey 		return;
1755*6ba597c5SAnurag S. Maskey 	}
1756*6ba597c5SAnurag S. Maskey 	nwamd_object_release_and_destroy(object);
1757*6ba597c5SAnurag S. Maskey }
1758*6ba597c5SAnurag S. Maskey 
1759*6ba597c5SAnurag S. Maskey void
1760*6ba597c5SAnurag S. Maskey nwamd_ncu_handle_action_event(nwamd_event_t event)
1761*6ba597c5SAnurag S. Maskey {
1762*6ba597c5SAnurag S. Maskey 	nwamd_object_t object;
1763*6ba597c5SAnurag S. Maskey 
1764*6ba597c5SAnurag S. Maskey 	(void) pthread_mutex_lock(&active_ncp_mutex);
1765*6ba597c5SAnurag S. Maskey 	if (strcmp(event->event_msg->nwe_data.nwe_object_action.nwe_parent,
1766*6ba597c5SAnurag S. Maskey 	    active_ncp) != 0) {
1767*6ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "nwamd_ncu_handle_action_event: action for "
1768*6ba597c5SAnurag S. Maskey 		    "inactive NCP %s, nothing to do",
1769*6ba597c5SAnurag S. Maskey 		    event->event_msg->nwe_data.nwe_object_action.nwe_parent);
1770*6ba597c5SAnurag S. Maskey 		(void) pthread_mutex_unlock(&active_ncp_mutex);
1771*6ba597c5SAnurag S. Maskey 		return;
1772*6ba597c5SAnurag S. Maskey 	}
1773*6ba597c5SAnurag S. Maskey 	(void) pthread_mutex_unlock(&active_ncp_mutex);
1774*6ba597c5SAnurag S. Maskey 
1775*6ba597c5SAnurag S. Maskey 	switch (event->event_msg->nwe_data.nwe_object_action.nwe_action) {
1776*6ba597c5SAnurag S. Maskey 	case NWAM_ACTION_ENABLE:
1777*6ba597c5SAnurag S. Maskey 		object = nwamd_object_find(NWAM_OBJECT_TYPE_NCU,
1778*6ba597c5SAnurag S. Maskey 		    event->event_object);
1779*6ba597c5SAnurag S. Maskey 		if (object == NULL) {
1780*6ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "nwamd_ncu_handle_action_event: "
1781*6ba597c5SAnurag S. Maskey 			    "could not find ncu %s", event->event_object);
1782*6ba597c5SAnurag S. Maskey 			nwamd_event_do_not_send(event);
1783*6ba597c5SAnurag S. Maskey 			return;
1784*6ba597c5SAnurag S. Maskey 		}
1785*6ba597c5SAnurag S. Maskey 		if (object->nwamd_object_state == NWAM_STATE_ONLINE) {
1786*6ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG, "nwamd_ncu_handle_action_event: "
1787*6ba597c5SAnurag S. Maskey 			    "ncu %s already online, nothing to do",
1788*6ba597c5SAnurag S. Maskey 			    event->event_object);
1789*6ba597c5SAnurag S. Maskey 			nwamd_object_release(object);
1790*6ba597c5SAnurag S. Maskey 			return;
1791*6ba597c5SAnurag S. Maskey 		}
1792*6ba597c5SAnurag S. Maskey 		nwamd_object_release(object);
1793*6ba597c5SAnurag S. Maskey 
1794*6ba597c5SAnurag S. Maskey 		nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
1795*6ba597c5SAnurag S. Maskey 		    event->event_object, NWAM_STATE_OFFLINE_TO_ONLINE,
1796*6ba597c5SAnurag S. Maskey 		    NWAM_AUX_STATE_INITIALIZED);
1797*6ba597c5SAnurag S. Maskey 		break;
1798*6ba597c5SAnurag S. Maskey 	case NWAM_ACTION_DISABLE:
1799*6ba597c5SAnurag S. Maskey 		object = nwamd_object_find(NWAM_OBJECT_TYPE_NCU,
1800*6ba597c5SAnurag S. Maskey 		    event->event_object);
1801*6ba597c5SAnurag S. Maskey 		if (object == NULL) {
1802*6ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "nwamd_ncu_handle_action_event: "
1803*6ba597c5SAnurag S. Maskey 			    "could not find ncu %s", event->event_object);
1804*6ba597c5SAnurag S. Maskey 			nwamd_event_do_not_send(event);
1805*6ba597c5SAnurag S. Maskey 			return;
1806*6ba597c5SAnurag S. Maskey 		}
1807*6ba597c5SAnurag S. Maskey 		if (object->nwamd_object_state == NWAM_STATE_DISABLED) {
1808*6ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG, "nwamd_ncu_handle_action_event: "
1809*6ba597c5SAnurag S. Maskey 			    "ncu %s already disabled, nothing to do",
1810*6ba597c5SAnurag S. Maskey 			    event->event_object);
1811*6ba597c5SAnurag S. Maskey 			nwamd_object_release(object);
1812*6ba597c5SAnurag S. Maskey 			return;
1813*6ba597c5SAnurag S. Maskey 		}
1814*6ba597c5SAnurag S. Maskey 		nwamd_object_release(object);
1815*6ba597c5SAnurag S. Maskey 
1816*6ba597c5SAnurag S. Maskey 		nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
1817*6ba597c5SAnurag S. Maskey 		    event->event_object, NWAM_STATE_ONLINE_TO_OFFLINE,
1818*6ba597c5SAnurag S. Maskey 		    NWAM_AUX_STATE_MANUAL_DISABLE);
1819*6ba597c5SAnurag S. Maskey 		break;
1820*6ba597c5SAnurag S. Maskey 	case NWAM_ACTION_ADD:
1821*6ba597c5SAnurag S. Maskey 	case NWAM_ACTION_REFRESH:
1822*6ba597c5SAnurag S. Maskey 		nwamd_ncu_handle_init_event(event);
1823*6ba597c5SAnurag S. Maskey 		break;
1824*6ba597c5SAnurag S. Maskey 	case NWAM_ACTION_DESTROY:
1825*6ba597c5SAnurag S. Maskey 		nwamd_ncu_handle_fini_event(event);
1826*6ba597c5SAnurag S. Maskey 		break;
1827*6ba597c5SAnurag S. Maskey 	default:
1828*6ba597c5SAnurag S. Maskey 		nlog(LOG_INFO, "nwam_ncu_handle_action_event: "
1829*6ba597c5SAnurag S. Maskey 		    "unexpected action");
1830*6ba597c5SAnurag S. Maskey 		nwamd_event_do_not_send(event);
1831*6ba597c5SAnurag S. Maskey 		break;
1832*6ba597c5SAnurag S. Maskey 	}
1833*6ba597c5SAnurag S. Maskey }
1834*6ba597c5SAnurag S. Maskey 
1835*6ba597c5SAnurag S. Maskey void
1836*6ba597c5SAnurag S. Maskey nwamd_ncu_handle_state_event(nwamd_event_t event)
1837*6ba597c5SAnurag S. Maskey {
1838*6ba597c5SAnurag S. Maskey 	nwamd_object_t object;
1839*6ba597c5SAnurag S. Maskey 	nwam_state_t old_state, new_state;
1840*6ba597c5SAnurag S. Maskey 	nwam_aux_state_t new_aux_state;
1841*6ba597c5SAnurag S. Maskey 	nwamd_ncu_t *ncu;
1842*6ba597c5SAnurag S. Maskey 	boolean_t is_link, enabled, prioritized = B_FALSE;
1843*6ba597c5SAnurag S. Maskey 	char linkname[NWAM_MAX_NAME_LEN];
1844*6ba597c5SAnurag S. Maskey 	nwam_event_t m = event->event_msg;
1845*6ba597c5SAnurag S. Maskey 
1846*6ba597c5SAnurag S. Maskey 	if ((object = nwamd_object_find(NWAM_OBJECT_TYPE_NCU,
1847*6ba597c5SAnurag S. Maskey 	    event->event_object)) == NULL) {
1848*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_ncu_handle_state_event %lld: "
1849*6ba597c5SAnurag S. Maskey 		    "state event for nonexistent NCU %s", event->event_id,
1850*6ba597c5SAnurag S. Maskey 		    event->event_object);
1851*6ba597c5SAnurag S. Maskey 		nwamd_event_do_not_send(event);
1852*6ba597c5SAnurag S. Maskey 		return;
1853*6ba597c5SAnurag S. Maskey 	}
1854*6ba597c5SAnurag S. Maskey 	ncu = object->nwamd_object_data;
1855*6ba597c5SAnurag S. Maskey 	old_state = object->nwamd_object_state;
1856*6ba597c5SAnurag S. Maskey 	new_state = event->event_msg->nwe_data.nwe_object_state.nwe_state;
1857*6ba597c5SAnurag S. Maskey 	new_aux_state =
1858*6ba597c5SAnurag S. Maskey 	    event->event_msg->nwe_data.nwe_object_state.nwe_aux_state;
1859*6ba597c5SAnurag S. Maskey 
1860*6ba597c5SAnurag S. Maskey 	/*
1861*6ba597c5SAnurag S. Maskey 	 * For NCU state changes, we need to supply the parent NCP name also,
1862*6ba597c5SAnurag S. Maskey 	 * regardless of whether the event is handled or not.  It is best to
1863*6ba597c5SAnurag S. Maskey 	 * fill this in here as we have the object lock - when we create
1864*6ba597c5SAnurag S. Maskey 	 * object state events we sometimes do not have the object lock, but
1865*6ba597c5SAnurag S. Maskey 	 * at this point in consuming the events (and prior to the associated
1866*6ba597c5SAnurag S. Maskey 	 * event message being sent out) we do.
1867*6ba597c5SAnurag S. Maskey 	 */
1868*6ba597c5SAnurag S. Maskey 	(void) strlcpy(m->nwe_data.nwe_object_state.nwe_parent, ncu->ncu_parent,
1869*6ba597c5SAnurag S. Maskey 	    sizeof (m->nwe_data.nwe_object_state.nwe_parent));
1870*6ba597c5SAnurag S. Maskey 
1871*6ba597c5SAnurag S. Maskey 	/*
1872*6ba597c5SAnurag S. Maskey 	 * If we receive a state change event moving this NCU to
1873*6ba597c5SAnurag S. Maskey 	 * DHCP_TIMED_OUT or UP state but this NCU is already ONLINE, then
1874*6ba597c5SAnurag S. Maskey 	 * ignore this state change event.
1875*6ba597c5SAnurag S. Maskey 	 */
1876*6ba597c5SAnurag S. Maskey 	if ((new_aux_state == NWAM_AUX_STATE_IF_DHCP_TIMED_OUT ||
1877*6ba597c5SAnurag S. Maskey 	    new_aux_state == NWAM_AUX_STATE_UP) &&
1878*6ba597c5SAnurag S. Maskey 	    object->nwamd_object_state == NWAM_STATE_ONLINE) {
1879*6ba597c5SAnurag S. Maskey 		nlog(LOG_INFO, "nwamd_ncu_handle_state_event: "
1880*6ba597c5SAnurag S. Maskey 		    "NCU %s already online, not going to '%s' state",
1881*6ba597c5SAnurag S. Maskey 		    object->nwamd_object_name,
1882*6ba597c5SAnurag S. Maskey 		    nwam_aux_state_to_string(new_aux_state));
1883*6ba597c5SAnurag S. Maskey 		nwamd_event_do_not_send(event);
1884*6ba597c5SAnurag S. Maskey 		nwamd_object_release(object);
1885*6ba597c5SAnurag S. Maskey 		return;
1886*6ba597c5SAnurag S. Maskey 	}
1887*6ba597c5SAnurag S. Maskey 
1888*6ba597c5SAnurag S. Maskey 	if (new_state == object->nwamd_object_state &&
1889*6ba597c5SAnurag S. Maskey 	    new_aux_state == object->nwamd_object_aux_state) {
1890*6ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "nwamd_ncu_handle_state_event: "
1891*6ba597c5SAnurag S. Maskey 		    "NCU %s already in state (%s, %s)",
1892*6ba597c5SAnurag S. Maskey 		    object->nwamd_object_name, nwam_state_to_string(new_state),
1893*6ba597c5SAnurag S. Maskey 		    nwam_aux_state_to_string(new_aux_state));
1894*6ba597c5SAnurag S. Maskey 		nwamd_object_release(object);
1895*6ba597c5SAnurag S. Maskey 		return;
1896*6ba597c5SAnurag S. Maskey 	}
1897*6ba597c5SAnurag S. Maskey 
1898*6ba597c5SAnurag S. Maskey 	if (old_state == NWAM_STATE_MAINTENANCE &&
1899*6ba597c5SAnurag S. Maskey 	    (new_state == NWAM_STATE_ONLINE ||
1900*6ba597c5SAnurag S. Maskey 	    (new_state == NWAM_STATE_OFFLINE_TO_ONLINE &&
1901*6ba597c5SAnurag S. Maskey 	    new_aux_state != NWAM_AUX_STATE_INITIALIZED))) {
1902*6ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "nwamd_ncu_handle_state_event: "
1903*6ba597c5SAnurag S. Maskey 		    "NCU %s cannot transition from state %s to state (%s, %s)",
1904*6ba597c5SAnurag S. Maskey 		    object->nwamd_object_name, nwam_state_to_string(old_state),
1905*6ba597c5SAnurag S. Maskey 		    nwam_state_to_string(new_state),
1906*6ba597c5SAnurag S. Maskey 		    nwam_aux_state_to_string(new_aux_state));
1907*6ba597c5SAnurag S. Maskey 		nwamd_event_do_not_send(event);
1908*6ba597c5SAnurag S. Maskey 		nwamd_object_release(object);
1909*6ba597c5SAnurag S. Maskey 		return;
1910*6ba597c5SAnurag S. Maskey 	}
1911*6ba597c5SAnurag S. Maskey 
1912*6ba597c5SAnurag S. Maskey 	object->nwamd_object_state = new_state;
1913*6ba597c5SAnurag S. Maskey 	object->nwamd_object_aux_state = new_aux_state;
1914*6ba597c5SAnurag S. Maskey 
1915*6ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "nwamd_ncu_handle_state_event: changing state for NCU "
1916*6ba597c5SAnurag S. Maskey 	    "%s to (%s, %s)", object->nwamd_object_name,
1917*6ba597c5SAnurag S. Maskey 	    nwam_state_to_string(object->nwamd_object_state),
1918*6ba597c5SAnurag S. Maskey 	    nwam_aux_state_to_string(object->nwamd_object_aux_state));
1919*6ba597c5SAnurag S. Maskey 
1920*6ba597c5SAnurag S. Maskey 	is_link = (ncu->ncu_type == NWAM_NCU_TYPE_LINK);
1921*6ba597c5SAnurag S. Maskey 	if (is_link)
1922*6ba597c5SAnurag S. Maskey 		(void) strlcpy(linkname, ncu->ncu_name, sizeof (linkname));
1923*6ba597c5SAnurag S. Maskey 	prioritized = (ncu->ncu_type == NWAM_NCU_TYPE_LINK &&
1924*6ba597c5SAnurag S. Maskey 	    ncu->ncu_node.u_link.nwamd_link_activation_mode ==
1925*6ba597c5SAnurag S. Maskey 	    NWAM_ACTIVATION_MODE_PRIORITIZED);
1926*6ba597c5SAnurag S. Maskey 	enabled = ncu->ncu_enabled;
1927*6ba597c5SAnurag S. Maskey 
1928*6ba597c5SAnurag S. Maskey 	nwamd_object_release(object);
1929*6ba597c5SAnurag S. Maskey 
1930*6ba597c5SAnurag S. Maskey 	/*
1931*6ba597c5SAnurag S. Maskey 	 * State machine for NCUs
1932*6ba597c5SAnurag S. Maskey 	 */
1933*6ba597c5SAnurag S. Maskey 	switch (new_state) {
1934*6ba597c5SAnurag S. Maskey 	case NWAM_STATE_OFFLINE_TO_ONLINE:
1935*6ba597c5SAnurag S. Maskey 		if (enabled) {
1936*6ba597c5SAnurag S. Maskey 			nwamd_ncu_state_machine(event->event_object);
1937*6ba597c5SAnurag S. Maskey 		} else {
1938*6ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG, "nwamd_ncu_handle_state_event: "
1939*6ba597c5SAnurag S. Maskey 			    "cannot move disabled NCU %s online",
1940*6ba597c5SAnurag S. Maskey 			    event->event_object);
1941*6ba597c5SAnurag S. Maskey 			nwamd_event_do_not_send(event);
1942*6ba597c5SAnurag S. Maskey 		}
1943*6ba597c5SAnurag S. Maskey 		break;
1944*6ba597c5SAnurag S. Maskey 
1945*6ba597c5SAnurag S. Maskey 	case NWAM_STATE_ONLINE_TO_OFFLINE:
1946*6ba597c5SAnurag S. Maskey 		nwamd_ncu_state_machine(event->event_object);
1947*6ba597c5SAnurag S. Maskey 		break;
1948*6ba597c5SAnurag S. Maskey 
1949*6ba597c5SAnurag S. Maskey 	case NWAM_STATE_ONLINE:
1950*6ba597c5SAnurag S. Maskey 		/*
1951*6ba597c5SAnurag S. Maskey 		 * We usually don't need to do anything when we're in the
1952*6ba597c5SAnurag S. Maskey 		 * ONLINE state.  However, for  WiFi we can be in INIT or
1953*6ba597c5SAnurag S. Maskey 		 * SCAN aux states while being ONLINE.
1954*6ba597c5SAnurag S. Maskey 		 */
1955*6ba597c5SAnurag S. Maskey 		nwamd_ncu_state_machine(event->event_object);
1956*6ba597c5SAnurag S. Maskey 		break;
1957*6ba597c5SAnurag S. Maskey 
1958*6ba597c5SAnurag S. Maskey 	case NWAM_STATE_OFFLINE:
1959*6ba597c5SAnurag S. Maskey 		/* Reassess priority group now member is offline */
1960*6ba597c5SAnurag S. Maskey 		if (prioritized) {
1961*6ba597c5SAnurag S. Maskey 			nwamd_create_ncu_check_event(0);
1962*6ba597c5SAnurag S. Maskey 		}
1963*6ba597c5SAnurag S. Maskey 		break;
1964*6ba597c5SAnurag S. Maskey 
1965*6ba597c5SAnurag S. Maskey 	case NWAM_STATE_DISABLED:
1966*6ba597c5SAnurag S. Maskey 	case NWAM_STATE_UNINITIALIZED:
1967*6ba597c5SAnurag S. Maskey 	case NWAM_STATE_MAINTENANCE:
1968*6ba597c5SAnurag S. Maskey 	case NWAM_STATE_DEGRADED:
1969*6ba597c5SAnurag S. Maskey 	default:
1970*6ba597c5SAnurag S. Maskey 		/* do nothing */
1971*6ba597c5SAnurag S. Maskey 		break;
1972*6ba597c5SAnurag S. Maskey 	}
1973*6ba597c5SAnurag S. Maskey 
1974*6ba597c5SAnurag S. Maskey 	if (is_link) {
1975*6ba597c5SAnurag S. Maskey 		if ((new_state == NWAM_STATE_ONLINE_TO_OFFLINE &&
1976*6ba597c5SAnurag S. Maskey 		    new_aux_state != NWAM_AUX_STATE_UNINITIALIZED &&
1977*6ba597c5SAnurag S. Maskey 		    new_aux_state != NWAM_AUX_STATE_NOT_FOUND) ||
1978*6ba597c5SAnurag S. Maskey 		    new_state == NWAM_STATE_DISABLED) {
1979*6ba597c5SAnurag S. Maskey 			/*
1980*6ba597c5SAnurag S. Maskey 			 * Going offline, propogate down event to IP NCU.  Do
1981*6ba597c5SAnurag S. Maskey 			 * not propogate event if new aux state is uninitialized
1982*6ba597c5SAnurag S. Maskey 			 * or not found as these auxiliary states signify
1983*6ba597c5SAnurag S. Maskey 			 * that an NCP switch/device removal is in progress.
1984*6ba597c5SAnurag S. Maskey 			 */
1985*6ba597c5SAnurag S. Maskey 			nwamd_propogate_link_up_down_to_ip(linkname, B_FALSE);
1986*6ba597c5SAnurag S. Maskey 		}
1987*6ba597c5SAnurag S. Maskey 		if (new_state == NWAM_STATE_ONLINE) {
1988*6ba597c5SAnurag S. Maskey 			/* gone online, propogate up event to IP NCU */
1989*6ba597c5SAnurag S. Maskey 			nwamd_propogate_link_up_down_to_ip(linkname, B_TRUE);
1990*6ba597c5SAnurag S. Maskey 		}
1991*6ba597c5SAnurag S. Maskey 	} else {
1992*6ba597c5SAnurag S. Maskey 		/* If IP NCU is online, reasses priority group */
1993*6ba597c5SAnurag S. Maskey 		if (new_state == NWAM_STATE_ONLINE)
1994*6ba597c5SAnurag S. Maskey 			nwamd_create_ncu_check_event(0);
1995*6ba597c5SAnurag S. Maskey 	}
1996*6ba597c5SAnurag S. Maskey }
1997