xref: /illumos-gate/usr/src/cmd/cmd-inet/lib/nwamd/ncp.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 <libdllink.h>
30*6ba597c5SAnurag S. Maskey #include <libdlstat.h>
31*6ba597c5SAnurag S. Maskey #include <libnwam.h>
32*6ba597c5SAnurag S. Maskey #include <libscf.h>
33*6ba597c5SAnurag S. Maskey #include <netinet/in.h>
34*6ba597c5SAnurag S. Maskey #include <stdlib.h>
35*6ba597c5SAnurag S. Maskey #include <sys/socket.h>
36*6ba597c5SAnurag S. Maskey #include <sys/time.h>
37*6ba597c5SAnurag S. Maskey #include <sys/types.h>
38*6ba597c5SAnurag S. Maskey #include <values.h>
39*6ba597c5SAnurag S. Maskey 
40*6ba597c5SAnurag S. Maskey #include "conditions.h"
41*6ba597c5SAnurag S. Maskey #include "events.h"
42*6ba597c5SAnurag S. Maskey #include "objects.h"
43*6ba597c5SAnurag S. Maskey #include "ncp.h"
44*6ba597c5SAnurag S. Maskey #include "ncu.h"
45*6ba597c5SAnurag S. Maskey #include "util.h"
46*6ba597c5SAnurag S. Maskey 
47*6ba597c5SAnurag S. Maskey /*
48*6ba597c5SAnurag S. Maskey  * ncp.c - handles NCP actions.
49*6ba597c5SAnurag S. Maskey  */
50*6ba597c5SAnurag S. Maskey 
51*6ba597c5SAnurag S. Maskey char active_ncp[NWAM_MAX_NAME_LEN];
52*6ba597c5SAnurag S. Maskey nwam_ncp_handle_t active_ncph = NULL;
53*6ba597c5SAnurag S. Maskey int64_t current_ncu_priority_group = INVALID_PRIORITY_GROUP;
54*6ba597c5SAnurag S. Maskey /*
55*6ba597c5SAnurag S. Maskey  * active_ncp_mutex protects active_ncp, active_ncph and
56*6ba597c5SAnurag S. Maskey  * current_ncu_priority_group.
57*6ba597c5SAnurag S. Maskey  */
58*6ba597c5SAnurag S. Maskey pthread_mutex_t active_ncp_mutex = PTHREAD_MUTEX_INITIALIZER;
59*6ba597c5SAnurag S. Maskey 
60*6ba597c5SAnurag S. Maskey /*
61*6ba597c5SAnurag S. Maskey  * The variable ncu_wait_time specifies how long to wait to obtain a
62*6ba597c5SAnurag S. Maskey  * DHCP lease before giving up on that NCU and moving on to the next/lower
63*6ba597c5SAnurag S. Maskey  * priority-group.
64*6ba597c5SAnurag S. Maskey  */
65*6ba597c5SAnurag S. Maskey uint64_t ncu_wait_time = NCU_WAIT_TIME_DEFAULT;
66*6ba597c5SAnurag S. Maskey 
67*6ba597c5SAnurag S. Maskey /*
68*6ba597c5SAnurag S. Maskey  * Specifies if this is the first time the NCP has been enabled. True
69*6ba597c5SAnurag S. Maskey  * on startup so that we can differentiate between when we start up
70*6ba597c5SAnurag S. Maskey  * with a given NCP versus when we are asked to reenable it.
71*6ba597c5SAnurag S. Maskey  */
72*6ba597c5SAnurag S. Maskey boolean_t initial_ncp_enable = B_TRUE;
73*6ba597c5SAnurag S. Maskey 
74*6ba597c5SAnurag S. Maskey /*
75*6ba597c5SAnurag S. Maskey  * nwamd_ncp_handle_enable_event() should be called in the event handling
76*6ba597c5SAnurag S. Maskey  * loop in response to an _ENABLE event, triggered as a result of an
77*6ba597c5SAnurag S. Maskey  * nwam_ncp_enable() call from a libnwam consumer.  To enable the new NCP,
78*6ba597c5SAnurag S. Maskey  * we first call nwamd_fini_ncus() on the old NCP.  This results in enqueueing
79*6ba597c5SAnurag S. Maskey  * of a set of _FINI events for each NCU.  These events are handled and in
80*6ba597c5SAnurag S. Maskey  * order to tear down config, (online*, uninitialized) state change events
81*6ba597c5SAnurag S. Maskey  * are created and consumed directly by the fini event handler (these events
82*6ba597c5SAnurag S. Maskey  * are not enqueued as this would result in state events for the old NCP
83*6ba597c5SAnurag S. Maskey  * appearing after the new NCP has been enabled.  After the _FINI events are
84*6ba597c5SAnurag S. Maskey  * enqueued, we enqueue an NCP _OBJECT_STATE event for the new NCP.  Since
85*6ba597c5SAnurag S. Maskey  * it is enqueued after the _FINI events, we are guaranteed no events for the
86*6ba597c5SAnurag S. Maskey  * old NCP will appear after the new NCP is activated.
87*6ba597c5SAnurag S. Maskey  */
88*6ba597c5SAnurag S. Maskey void
89*6ba597c5SAnurag S. Maskey nwamd_ncp_handle_enable_event(nwamd_event_t event)
90*6ba597c5SAnurag S. Maskey {
91*6ba597c5SAnurag S. Maskey 	char *new_ncp = event->event_object;
92*6ba597c5SAnurag S. Maskey 	nwam_ncp_handle_t new_ncph;
93*6ba597c5SAnurag S. Maskey 	nwam_error_t err;
94*6ba597c5SAnurag S. Maskey 
95*6ba597c5SAnurag S. Maskey 	if (new_ncp[0] == '\0')
96*6ba597c5SAnurag S. Maskey 		return;
97*6ba597c5SAnurag S. Maskey 
98*6ba597c5SAnurag S. Maskey 	(void) pthread_mutex_lock(&active_ncp_mutex);
99*6ba597c5SAnurag S. Maskey 	if (strcmp(active_ncp, new_ncp) == 0 && !initial_ncp_enable) {
100*6ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "nwamd_ncp_handle_enable_event: "
101*6ba597c5SAnurag S. Maskey 		    "%s is already active", new_ncp);
102*6ba597c5SAnurag S. Maskey 		(void) pthread_mutex_unlock(&active_ncp_mutex);
103*6ba597c5SAnurag S. Maskey 		return;
104*6ba597c5SAnurag S. Maskey 	}
105*6ba597c5SAnurag S. Maskey 	(void) pthread_mutex_unlock(&active_ncp_mutex);
106*6ba597c5SAnurag S. Maskey 
107*6ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "nwamd_ncp_handle_enable_event: activating NCP %s",
108*6ba597c5SAnurag S. Maskey 	    new_ncp);
109*6ba597c5SAnurag S. Maskey 
110*6ba597c5SAnurag S. Maskey 	/*
111*6ba597c5SAnurag S. Maskey 	 * To activate new NCP, run nwamd_fini_ncus(), reset the active
112*6ba597c5SAnurag S. Maskey 	 * priority-group, set the active_ncp property and refresh the
113*6ba597c5SAnurag S. Maskey 	 * daemon.  The refresh action will trigger a re-read of the NCUs
114*6ba597c5SAnurag S. Maskey 	 * for the activated NCP.
115*6ba597c5SAnurag S. Maskey 	 */
116*6ba597c5SAnurag S. Maskey 
117*6ba597c5SAnurag S. Maskey 	nwamd_fini_ncus();
118*6ba597c5SAnurag S. Maskey 
119*6ba597c5SAnurag S. Maskey 	err = nwam_ncp_read(new_ncp, 0, &new_ncph);
120*6ba597c5SAnurag S. Maskey 	switch (err) {
121*6ba597c5SAnurag S. Maskey 	case NWAM_ENTITY_NOT_FOUND:
122*6ba597c5SAnurag S. Maskey 		err = nwam_ncp_create(new_ncp, 0, &new_ncph);
123*6ba597c5SAnurag S. Maskey 		break;
124*6ba597c5SAnurag S. Maskey 	case NWAM_SUCCESS:
125*6ba597c5SAnurag S. Maskey 		break;
126*6ba597c5SAnurag S. Maskey 	default:
127*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_ncp_handle_enable_event: error %s",
128*6ba597c5SAnurag S. Maskey 		    nwam_strerror(err));
129*6ba597c5SAnurag S. Maskey 		return;
130*6ba597c5SAnurag S. Maskey 	}
131*6ba597c5SAnurag S. Maskey 	nwam_ncp_free(new_ncph);
132*6ba597c5SAnurag S. Maskey 
133*6ba597c5SAnurag S. Maskey 	if (err == NWAM_SUCCESS) {
134*6ba597c5SAnurag S. Maskey 		nwamd_object_set_state(NWAM_OBJECT_TYPE_NCP, new_ncp,
135*6ba597c5SAnurag S. Maskey 		    NWAM_STATE_ONLINE, NWAM_AUX_STATE_ACTIVE);
136*6ba597c5SAnurag S. Maskey 	} else {
137*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_ncp_handle_enable_event: error %s",
138*6ba597c5SAnurag S. Maskey 		    nwam_strerror(err));
139*6ba597c5SAnurag S. Maskey 		return;
140*6ba597c5SAnurag S. Maskey 	}
141*6ba597c5SAnurag S. Maskey }
142*6ba597c5SAnurag S. Maskey 
143*6ba597c5SAnurag S. Maskey void
144*6ba597c5SAnurag S. Maskey nwamd_ncp_handle_action_event(nwamd_event_t event)
145*6ba597c5SAnurag S. Maskey {
146*6ba597c5SAnurag S. Maskey 	switch (event->event_msg->nwe_data.nwe_object_action.nwe_action) {
147*6ba597c5SAnurag S. Maskey 	case NWAM_ACTION_ENABLE:
148*6ba597c5SAnurag S. Maskey 		nwamd_ncp_handle_enable_event(event);
149*6ba597c5SAnurag S. Maskey 		break;
150*6ba597c5SAnurag S. Maskey 	case NWAM_ACTION_ADD:
151*6ba597c5SAnurag S. Maskey 	case NWAM_ACTION_DESTROY:
152*6ba597c5SAnurag S. Maskey 		/* nothing to do */
153*6ba597c5SAnurag S. Maskey 		break;
154*6ba597c5SAnurag S. Maskey 	default:
155*6ba597c5SAnurag S. Maskey 		nlog(LOG_INFO, "nwam_ncp_handle_action_event: "
156*6ba597c5SAnurag S. Maskey 		    "unexpected action");
157*6ba597c5SAnurag S. Maskey 		nwamd_event_do_not_send(event);
158*6ba597c5SAnurag S. Maskey 		break;
159*6ba597c5SAnurag S. Maskey 	}
160*6ba597c5SAnurag S. Maskey }
161*6ba597c5SAnurag S. Maskey 
162*6ba597c5SAnurag S. Maskey /*
163*6ba597c5SAnurag S. Maskey  * The only state events we create are (online, active) events which are
164*6ba597c5SAnurag S. Maskey  * generated as part of an NCP enable action (see above).
165*6ba597c5SAnurag S. Maskey  */
166*6ba597c5SAnurag S. Maskey void
167*6ba597c5SAnurag S. Maskey nwamd_ncp_handle_state_event(nwamd_event_t event)
168*6ba597c5SAnurag S. Maskey {
169*6ba597c5SAnurag S. Maskey 	char *new_ncp = event->event_object;
170*6ba597c5SAnurag S. Maskey 	nwam_ncp_handle_t new_ncph, old_ncph;
171*6ba597c5SAnurag S. Maskey 	nwam_error_t err;
172*6ba597c5SAnurag S. Maskey 
173*6ba597c5SAnurag S. Maskey 	/* The NCP to be activated should always exist. */
174*6ba597c5SAnurag S. Maskey 	if ((err = nwam_ncp_read(new_ncp, 0, &new_ncph)) != NWAM_SUCCESS) {
175*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_ncp_handle_state_event: "
176*6ba597c5SAnurag S. Maskey 		    "cannot read NCP %s: : %s", new_ncp, nwam_strerror(err));
177*6ba597c5SAnurag S. Maskey 		nwamd_event_do_not_send(event);
178*6ba597c5SAnurag S. Maskey 		return;
179*6ba597c5SAnurag S. Maskey 	}
180*6ba597c5SAnurag S. Maskey 
181*6ba597c5SAnurag S. Maskey 	/*
182*6ba597c5SAnurag S. Maskey 	 * To activate new NCP, reset the active priority-group, set the
183*6ba597c5SAnurag S. Maskey 	 * active_ncp property and refresh the daemon.  The refresh action will
184*6ba597c5SAnurag S. Maskey 	 * trigger a re-read of the NCUs for the activated NCP.
185*6ba597c5SAnurag S. Maskey 	 */
186*6ba597c5SAnurag S. Maskey 	(void) pthread_mutex_lock(&active_ncp_mutex);
187*6ba597c5SAnurag S. Maskey 	old_ncph = active_ncph;
188*6ba597c5SAnurag S. Maskey 	active_ncph = new_ncph;
189*6ba597c5SAnurag S. Maskey 	nwam_ncp_free(old_ncph);
190*6ba597c5SAnurag S. Maskey 	current_ncu_priority_group = INVALID_PRIORITY_GROUP;
191*6ba597c5SAnurag S. Maskey 	(void) strlcpy(active_ncp, event->event_object,
192*6ba597c5SAnurag S. Maskey 	    sizeof (active_ncp));
193*6ba597c5SAnurag S. Maskey 	(void) pthread_mutex_unlock(&active_ncp_mutex);
194*6ba597c5SAnurag S. Maskey 	(void) nwamd_set_string_property(OUR_FMRI, OUR_PG,
195*6ba597c5SAnurag S. Maskey 	    OUR_ACTIVE_NCP_PROP_NAME, new_ncp);
196*6ba597c5SAnurag S. Maskey 	(void) smf_refresh_instance(OUR_FMRI);
197*6ba597c5SAnurag S. Maskey 	initial_ncp_enable = B_FALSE;
198*6ba597c5SAnurag S. Maskey }
199*6ba597c5SAnurag S. Maskey 
200*6ba597c5SAnurag S. Maskey int
201*6ba597c5SAnurag S. Maskey nwamd_ncp_action(const char *ncp, nwam_action_t action)
202*6ba597c5SAnurag S. Maskey {
203*6ba597c5SAnurag S. Maskey 	nwamd_event_t event = nwamd_event_init_object_action
204*6ba597c5SAnurag S. Maskey 	    (NWAM_OBJECT_TYPE_NCP, ncp, NULL, action);
205*6ba597c5SAnurag S. Maskey 	if (event == NULL)
206*6ba597c5SAnurag S. Maskey 		return (1);
207*6ba597c5SAnurag S. Maskey 	nwamd_event_enqueue(event);
208*6ba597c5SAnurag S. Maskey 	return (0);
209*6ba597c5SAnurag S. Maskey }
210*6ba597c5SAnurag S. Maskey 
211*6ba597c5SAnurag S. Maskey /*
212*6ba597c5SAnurag S. Maskey  * Below this point are routines handling NCU prioritization
213*6ba597c5SAnurag S. Maskey  * policy for the active NCP.
214*6ba597c5SAnurag S. Maskey  */
215*6ba597c5SAnurag S. Maskey 
216*6ba597c5SAnurag S. Maskey struct priority_group_cbarg {
217*6ba597c5SAnurag S. Maskey 	uint64_t minpriority;
218*6ba597c5SAnurag S. Maskey 	uint64_t currpriority;
219*6ba597c5SAnurag S. Maskey 	boolean_t found;
220*6ba597c5SAnurag S. Maskey };
221*6ba597c5SAnurag S. Maskey 
222*6ba597c5SAnurag S. Maskey /* Callback used to find next pg in NCP that is >= start_pg */
223*6ba597c5SAnurag S. Maskey static int
224*6ba597c5SAnurag S. Maskey find_next_priority_group_cb(nwamd_object_t object, void *data)
225*6ba597c5SAnurag S. Maskey {
226*6ba597c5SAnurag S. Maskey 	struct priority_group_cbarg *cbarg = data;
227*6ba597c5SAnurag S. Maskey 	uint64_t priority;
228*6ba597c5SAnurag S. Maskey 	nwamd_ncu_t *ncu = object->nwamd_object_data;
229*6ba597c5SAnurag S. Maskey 
230*6ba597c5SAnurag S. Maskey 	if (ncu->ncu_node.u_link.nwamd_link_activation_mode !=
231*6ba597c5SAnurag S. Maskey 	    NWAM_ACTIVATION_MODE_PRIORITIZED)
232*6ba597c5SAnurag S. Maskey 		return (0);
233*6ba597c5SAnurag S. Maskey 
234*6ba597c5SAnurag S. Maskey 	priority = ncu->ncu_node.u_link.nwamd_link_priority_group;
235*6ba597c5SAnurag S. Maskey 
236*6ba597c5SAnurag S. Maskey 	if (priority >= cbarg->minpriority && priority < cbarg->currpriority) {
237*6ba597c5SAnurag S. Maskey 		cbarg->found = B_TRUE;
238*6ba597c5SAnurag S. Maskey 		cbarg->currpriority = priority;
239*6ba597c5SAnurag S. Maskey 	}
240*6ba597c5SAnurag S. Maskey 	return (0);
241*6ba597c5SAnurag S. Maskey }
242*6ba597c5SAnurag S. Maskey 
243*6ba597c5SAnurag S. Maskey 
244*6ba597c5SAnurag S. Maskey /* Set current_pg to next pg in NCP that is >= start_pg */
245*6ba597c5SAnurag S. Maskey boolean_t
246*6ba597c5SAnurag S. Maskey nwamd_ncp_find_next_priority_group(int64_t minpriority,
247*6ba597c5SAnurag S. Maskey     int64_t *nextpriorityp)
248*6ba597c5SAnurag S. Maskey {
249*6ba597c5SAnurag S. Maskey 	struct priority_group_cbarg cbarg;
250*6ba597c5SAnurag S. Maskey 
251*6ba597c5SAnurag S. Maskey 	cbarg.minpriority = minpriority;
252*6ba597c5SAnurag S. Maskey 	cbarg.currpriority = MAXINT;
253*6ba597c5SAnurag S. Maskey 	cbarg.found = B_FALSE;
254*6ba597c5SAnurag S. Maskey 
255*6ba597c5SAnurag S. Maskey 	(void) nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU,
256*6ba597c5SAnurag S. Maskey 	    find_next_priority_group_cb, &cbarg);
257*6ba597c5SAnurag S. Maskey 
258*6ba597c5SAnurag S. Maskey 	if (cbarg.found) {
259*6ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "nwamd_ncp_find_next_priority_group: "
260*6ba597c5SAnurag S. Maskey 		    "next priority group >= %lld is %lld",
261*6ba597c5SAnurag S. Maskey 		    minpriority, cbarg.currpriority);
262*6ba597c5SAnurag S. Maskey 		*nextpriorityp = cbarg.currpriority;
263*6ba597c5SAnurag S. Maskey 		return (B_TRUE);
264*6ba597c5SAnurag S. Maskey 	} else {
265*6ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "nwamd_ncp_find_next_priority_group: "
266*6ba597c5SAnurag S. Maskey 		    "no priority groups >= %lld exist", minpriority);
267*6ba597c5SAnurag S. Maskey 		return (B_FALSE);
268*6ba597c5SAnurag S. Maskey 	}
269*6ba597c5SAnurag S. Maskey }
270*6ba597c5SAnurag S. Maskey 
271*6ba597c5SAnurag S. Maskey /*
272*6ba597c5SAnurag S. Maskey  * Struct for walking NCUs in the selected priority group.  We count
273*6ba597c5SAnurag S. Maskey  * how many of the exclusive, all and shared NCUs are online, and
274*6ba597c5SAnurag S. Maskey  * if activate_or_deactivate is true, we either activate or deactivate
275*6ba597c5SAnurag S. Maskey  * (depending on the value of activate) offline/online NCUs.
276*6ba597c5SAnurag S. Maskey  */
277*6ba597c5SAnurag S. Maskey struct nwamd_ncu_check_walk_arg {
278*6ba597c5SAnurag S. Maskey 	boolean_t manual;	/* enable manual NCUs only */
279*6ba597c5SAnurag S. Maskey 	int64_t priority_group; /* interested priority-group for this walk */
280*6ba597c5SAnurag S. Maskey 	uint64_t exclusive_ncus;
281*6ba597c5SAnurag S. Maskey 	uint64_t exclusive_online_ncus;
282*6ba597c5SAnurag S. Maskey 	uint64_t shared_ncus;
283*6ba597c5SAnurag S. Maskey 	uint64_t shared_online_ncus;
284*6ba597c5SAnurag S. Maskey 	uint64_t all_ncus;
285*6ba597c5SAnurag S. Maskey 	uint64_t all_online_ncus;
286*6ba597c5SAnurag S. Maskey 	boolean_t activate_or_deactivate;
287*6ba597c5SAnurag S. Maskey 	boolean_t activate;
288*6ba597c5SAnurag S. Maskey };
289*6ba597c5SAnurag S. Maskey 
290*6ba597c5SAnurag S. Maskey /*
291*6ba597c5SAnurag S. Maskey  * This function serves a number of purposes:
292*6ba597c5SAnurag S. Maskey  * - it supports activation/deactivation of manual NCUs in the current NCP
293*6ba597c5SAnurag S. Maskey  * (when wa->manual is true, wa->activate determines if we activate or
294*6ba597c5SAnurag S. Maskey  * deactivate the current NCU)
295*6ba597c5SAnurag S. Maskey  * - it supports checking/activation of a particular priority group in
296*6ba597c5SAnurag S. Maskey  * the active NCP. This works as follows:
297*6ba597c5SAnurag S. Maskey  *
298*6ba597c5SAnurag S. Maskey  * Count up numbers of exclusive, shared and all NCUs, and how many of each
299*6ba597c5SAnurag S. Maskey  * are online.  If an NCU is waiting for IP address to be assigned, it is
300*6ba597c5SAnurag S. Maskey  * also considered online.  If activate_or_deactivate is true, we also
301*6ba597c5SAnurag S. Maskey  * either activate (if activate is true) or deactivate prioritized NCUs
302*6ba597c5SAnurag S. Maskey  * that are offline or online.
303*6ba597c5SAnurag S. Maskey  */
304*6ba597c5SAnurag S. Maskey static int
305*6ba597c5SAnurag S. Maskey nwamd_ncu_check_or_activate(nwamd_object_t object, void *data)
306*6ba597c5SAnurag S. Maskey {
307*6ba597c5SAnurag S. Maskey 	struct nwamd_ncu_check_walk_arg *wa = data;
308*6ba597c5SAnurag S. Maskey 	nwamd_ncu_t *ncu;
309*6ba597c5SAnurag S. Maskey 	uint64_t priority_group, priority_mode;
310*6ba597c5SAnurag S. Maskey 	nwamd_object_t if_obj;
311*6ba597c5SAnurag S. Maskey 	nwam_state_t state, if_state;
312*6ba597c5SAnurag S. Maskey 	nwam_aux_state_t aux_state, if_aux_state;
313*6ba597c5SAnurag S. Maskey 	char *name;
314*6ba597c5SAnurag S. Maskey 
315*6ba597c5SAnurag S. Maskey 	state = object->nwamd_object_state;
316*6ba597c5SAnurag S. Maskey 	aux_state = object->nwamd_object_aux_state;
317*6ba597c5SAnurag S. Maskey 	name = object->nwamd_object_name;
318*6ba597c5SAnurag S. Maskey 	ncu = object->nwamd_object_data;
319*6ba597c5SAnurag S. Maskey 
320*6ba597c5SAnurag S. Maskey 	/* skip NCUs in UNINITIALIZED state */
321*6ba597c5SAnurag S. Maskey 	if (state == NWAM_STATE_UNINITIALIZED) {
322*6ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
323*6ba597c5SAnurag S. Maskey 		    "skipping uninitialized ncu %s", name);
324*6ba597c5SAnurag S. Maskey 		return (0);
325*6ba597c5SAnurag S. Maskey 	}
326*6ba597c5SAnurag S. Maskey 	if (!wa->manual && wa->priority_group == INVALID_PRIORITY_GROUP)
327*6ba597c5SAnurag S. Maskey 		return (0);
328*6ba597c5SAnurag S. Maskey 
329*6ba597c5SAnurag S. Maskey 	if (ncu->ncu_type != NWAM_NCU_TYPE_LINK) {
330*6ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
331*6ba597c5SAnurag S. Maskey 		    "skipping interface NCU %s", name);
332*6ba597c5SAnurag S. Maskey 		return (0);
333*6ba597c5SAnurag S. Maskey 	}
334*6ba597c5SAnurag S. Maskey 	if (!wa->manual && ncu->ncu_node.u_link.nwamd_link_activation_mode !=
335*6ba597c5SAnurag S. Maskey 	    NWAM_ACTIVATION_MODE_PRIORITIZED) {
336*6ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
337*6ba597c5SAnurag S. Maskey 		    "skipping non-prioritized NCU %s", name);
338*6ba597c5SAnurag S. Maskey 		return (0);
339*6ba597c5SAnurag S. Maskey 	}
340*6ba597c5SAnurag S. Maskey 	if (wa->manual && ncu->ncu_node.u_link.nwamd_link_activation_mode !=
341*6ba597c5SAnurag S. Maskey 	    NWAM_ACTIVATION_MODE_MANUAL) {
342*6ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
343*6ba597c5SAnurag S. Maskey 		    "skipping non-manual NCU %s", name);
344*6ba597c5SAnurag S. Maskey 		return (0);
345*6ba597c5SAnurag S. Maskey 	}
346*6ba597c5SAnurag S. Maskey 
347*6ba597c5SAnurag S. Maskey 	priority_group = ncu->ncu_node.u_link.nwamd_link_priority_group;
348*6ba597c5SAnurag S. Maskey 	priority_mode = ncu->ncu_node.u_link.nwamd_link_priority_mode;
349*6ba597c5SAnurag S. Maskey 	/* Only work with NCUs in the requested priority-group */
350*6ba597c5SAnurag S. Maskey 	if (!wa->manual && priority_group != wa->priority_group) {
351*6ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
352*6ba597c5SAnurag S. Maskey 		    "skipping NCU %s in different priority-group", name);
353*6ba597c5SAnurag S. Maskey 		return (0);
354*6ba597c5SAnurag S. Maskey 	}
355*6ba597c5SAnurag S. Maskey 	/* Get the state of the corresponding interface NCU */
356*6ba597c5SAnurag S. Maskey 	if ((if_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_INTERFACE,
357*6ba597c5SAnurag S. Maskey 	    ncu->ncu_name)) == NULL) {
358*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_ncu_check_or_activate: "
359*6ba597c5SAnurag S. Maskey 		    "interface NCU of %s not found, skipping", name);
360*6ba597c5SAnurag S. Maskey 		return (0);
361*6ba597c5SAnurag S. Maskey 	}
362*6ba597c5SAnurag S. Maskey 	if_state = if_obj->nwamd_object_state;
363*6ba597c5SAnurag S. Maskey 	if_aux_state = if_obj->nwamd_object_aux_state;
364*6ba597c5SAnurag S. Maskey 	nwamd_object_release(if_obj);
365*6ba597c5SAnurag S. Maskey 
366*6ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: %s ncu %s",
367*6ba597c5SAnurag S. Maskey 	    wa->activate_or_deactivate ?
368*6ba597c5SAnurag S. Maskey 	    (wa->activate ? "activating" : "deactivating") :
369*6ba597c5SAnurag S. Maskey 	    "checking", name);
370*6ba597c5SAnurag S. Maskey 
371*6ba597c5SAnurag S. Maskey 	if (wa->manual) {
372*6ba597c5SAnurag S. Maskey 		if (wa->activate_or_deactivate && wa->activate) {
373*6ba597c5SAnurag S. Maskey 			if (state == NWAM_STATE_OFFLINE && ncu->ncu_enabled) {
374*6ba597c5SAnurag S. Maskey 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
375*6ba597c5SAnurag S. Maskey 				    "moving NCU %s to offline* from offline",
376*6ba597c5SAnurag S. Maskey 				    name);
377*6ba597c5SAnurag S. Maskey 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
378*6ba597c5SAnurag S. Maskey 				    name, NWAM_STATE_OFFLINE_TO_ONLINE,
379*6ba597c5SAnurag S. Maskey 				    NWAM_AUX_STATE_INITIALIZED);
380*6ba597c5SAnurag S. Maskey 			}
381*6ba597c5SAnurag S. Maskey 			if (state != NWAM_STATE_DISABLED &&
382*6ba597c5SAnurag S. Maskey 			    !ncu->ncu_enabled) {
383*6ba597c5SAnurag S. Maskey 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
384*6ba597c5SAnurag S. Maskey 				    "moving NCU %s to online* (disabling)",
385*6ba597c5SAnurag S. Maskey 				    name);
386*6ba597c5SAnurag S. Maskey 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
387*6ba597c5SAnurag S. Maskey 				    name, NWAM_STATE_ONLINE_TO_OFFLINE,
388*6ba597c5SAnurag S. Maskey 				    NWAM_AUX_STATE_MANUAL_DISABLE);
389*6ba597c5SAnurag S. Maskey 			}
390*6ba597c5SAnurag S. Maskey 		}
391*6ba597c5SAnurag S. Maskey 		return (0);
392*6ba597c5SAnurag S. Maskey 	}
393*6ba597c5SAnurag S. Maskey 	switch (priority_mode) {
394*6ba597c5SAnurag S. Maskey 	case NWAM_PRIORITY_MODE_EXCLUSIVE:
395*6ba597c5SAnurag S. Maskey 		wa->exclusive_ncus++;
396*6ba597c5SAnurag S. Maskey 		if (state == NWAM_STATE_ONLINE &&
397*6ba597c5SAnurag S. Maskey 		    (if_state == NWAM_STATE_ONLINE ||
398*6ba597c5SAnurag S. Maskey 		    if_aux_state == NWAM_AUX_STATE_IF_WAITING_FOR_ADDR))
399*6ba597c5SAnurag S. Maskey 			wa->exclusive_online_ncus++;
400*6ba597c5SAnurag S. Maskey 
401*6ba597c5SAnurag S. Maskey 		/*
402*6ba597c5SAnurag S. Maskey 		 * For exclusive NCUs, we activate offline NCUs as long
403*6ba597c5SAnurag S. Maskey 		 * as no other exclusive NCUs are active.
404*6ba597c5SAnurag S. Maskey 		 */
405*6ba597c5SAnurag S. Maskey 		if (wa->activate_or_deactivate && wa->activate) {
406*6ba597c5SAnurag S. Maskey 			if (state == NWAM_STATE_OFFLINE &&
407*6ba597c5SAnurag S. Maskey 			    wa->exclusive_online_ncus == 0) {
408*6ba597c5SAnurag S. Maskey 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
409*6ba597c5SAnurag S. Maskey 				    "moving NCU %s to offline* from offline",
410*6ba597c5SAnurag S. Maskey 				    name);
411*6ba597c5SAnurag S. Maskey 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
412*6ba597c5SAnurag S. Maskey 				    name, NWAM_STATE_OFFLINE_TO_ONLINE,
413*6ba597c5SAnurag S. Maskey 				    NWAM_AUX_STATE_INITIALIZED);
414*6ba597c5SAnurag S. Maskey 			}
415*6ba597c5SAnurag S. Maskey 		}
416*6ba597c5SAnurag S. Maskey 		if (wa->activate_or_deactivate && !wa->activate) {
417*6ba597c5SAnurag S. Maskey 			if (aux_state != NWAM_AUX_STATE_CONDITIONS_NOT_MET) {
418*6ba597c5SAnurag S. Maskey 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
419*6ba597c5SAnurag S. Maskey 				    "deactivating NCU %s", name);
420*6ba597c5SAnurag S. Maskey 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
421*6ba597c5SAnurag S. Maskey 				    name, NWAM_STATE_ONLINE_TO_OFFLINE,
422*6ba597c5SAnurag S. Maskey 				    NWAM_AUX_STATE_CONDITIONS_NOT_MET);
423*6ba597c5SAnurag S. Maskey 			}
424*6ba597c5SAnurag S. Maskey 		}
425*6ba597c5SAnurag S. Maskey 		/*
426*6ba597c5SAnurag S. Maskey 		 * If we are activating or checking the priority group and
427*6ba597c5SAnurag S. Maskey 		 * too many exclusive NCUs are online, take this NCU down.
428*6ba597c5SAnurag S. Maskey 		 */
429*6ba597c5SAnurag S. Maskey 		if ((wa->activate_or_deactivate && wa->activate) ||
430*6ba597c5SAnurag S. Maskey 		    !wa->activate_or_deactivate) {
431*6ba597c5SAnurag S. Maskey 			if (state == NWAM_STATE_ONLINE &&
432*6ba597c5SAnurag S. Maskey 			    if_state == NWAM_STATE_ONLINE &&
433*6ba597c5SAnurag S. Maskey 			    wa->exclusive_online_ncus > 1) {
434*6ba597c5SAnurag S. Maskey 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
435*6ba597c5SAnurag S. Maskey 				    "moving NCU %s to online* since another "
436*6ba597c5SAnurag S. Maskey 				    "NCU is already active",
437*6ba597c5SAnurag S. Maskey 				    name);
438*6ba597c5SAnurag S. Maskey 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
439*6ba597c5SAnurag S. Maskey 				    name, NWAM_STATE_ONLINE_TO_OFFLINE,
440*6ba597c5SAnurag S. Maskey 				    NWAM_AUX_STATE_CONDITIONS_NOT_MET);
441*6ba597c5SAnurag S. Maskey 			}
442*6ba597c5SAnurag S. Maskey 		}
443*6ba597c5SAnurag S. Maskey 		break;
444*6ba597c5SAnurag S. Maskey 	case NWAM_PRIORITY_MODE_SHARED:
445*6ba597c5SAnurag S. Maskey 		wa->shared_ncus++;
446*6ba597c5SAnurag S. Maskey 		if (state == NWAM_STATE_ONLINE &&
447*6ba597c5SAnurag S. Maskey 		    (if_state == NWAM_STATE_ONLINE ||
448*6ba597c5SAnurag S. Maskey 		    if_aux_state == NWAM_AUX_STATE_IF_WAITING_FOR_ADDR))
449*6ba597c5SAnurag S. Maskey 			wa->shared_online_ncus++;
450*6ba597c5SAnurag S. Maskey 
451*6ba597c5SAnurag S. Maskey 		if (wa->activate_or_deactivate && wa->activate) {
452*6ba597c5SAnurag S. Maskey 			if (state == NWAM_STATE_OFFLINE) {
453*6ba597c5SAnurag S. Maskey 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
454*6ba597c5SAnurag S. Maskey 				    "activating NCU %s", name);
455*6ba597c5SAnurag S. Maskey 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
456*6ba597c5SAnurag S. Maskey 				    name, NWAM_STATE_OFFLINE_TO_ONLINE,
457*6ba597c5SAnurag S. Maskey 				    NWAM_AUX_STATE_INITIALIZED);
458*6ba597c5SAnurag S. Maskey 			}
459*6ba597c5SAnurag S. Maskey 		}
460*6ba597c5SAnurag S. Maskey 		if (wa->activate_or_deactivate && !wa->activate) {
461*6ba597c5SAnurag S. Maskey 			if (aux_state != NWAM_AUX_STATE_CONDITIONS_NOT_MET) {
462*6ba597c5SAnurag S. Maskey 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
463*6ba597c5SAnurag S. Maskey 				    "deactivating NCU %s", name);
464*6ba597c5SAnurag S. Maskey 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
465*6ba597c5SAnurag S. Maskey 				    name, NWAM_STATE_ONLINE_TO_OFFLINE,
466*6ba597c5SAnurag S. Maskey 				    NWAM_AUX_STATE_CONDITIONS_NOT_MET);
467*6ba597c5SAnurag S. Maskey 			}
468*6ba597c5SAnurag S. Maskey 		}
469*6ba597c5SAnurag S. Maskey 		break;
470*6ba597c5SAnurag S. Maskey 	case NWAM_PRIORITY_MODE_ALL:
471*6ba597c5SAnurag S. Maskey 		wa->all_ncus++;
472*6ba597c5SAnurag S. Maskey 		if (state == NWAM_STATE_ONLINE &&
473*6ba597c5SAnurag S. Maskey 		    (if_state == NWAM_STATE_ONLINE ||
474*6ba597c5SAnurag S. Maskey 		    if_aux_state == NWAM_AUX_STATE_IF_WAITING_FOR_ADDR))
475*6ba597c5SAnurag S. Maskey 			wa->all_online_ncus++;
476*6ba597c5SAnurag S. Maskey 
477*6ba597c5SAnurag S. Maskey 		/*
478*6ba597c5SAnurag S. Maskey 		 * For "all" NCUs, activate/deactivate all offline/online
479*6ba597c5SAnurag S. Maskey 		 * NCUs.
480*6ba597c5SAnurag S. Maskey 		 */
481*6ba597c5SAnurag S. Maskey 		if (wa->activate_or_deactivate && wa->activate) {
482*6ba597c5SAnurag S. Maskey 			if (state == NWAM_STATE_OFFLINE) {
483*6ba597c5SAnurag S. Maskey 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
484*6ba597c5SAnurag S. Maskey 				    "activating NCU %s", name);
485*6ba597c5SAnurag S. Maskey 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
486*6ba597c5SAnurag S. Maskey 				    name, NWAM_STATE_OFFLINE_TO_ONLINE,
487*6ba597c5SAnurag S. Maskey 				    NWAM_AUX_STATE_INITIALIZED);
488*6ba597c5SAnurag S. Maskey 			}
489*6ba597c5SAnurag S. Maskey 		}
490*6ba597c5SAnurag S. Maskey 		if (wa->activate_or_deactivate && !wa->activate) {
491*6ba597c5SAnurag S. Maskey 			if (aux_state != NWAM_AUX_STATE_CONDITIONS_NOT_MET) {
492*6ba597c5SAnurag S. Maskey 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
493*6ba597c5SAnurag S. Maskey 				    "deactivating NCU %s", name);
494*6ba597c5SAnurag S. Maskey 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
495*6ba597c5SAnurag S. Maskey 				    name, NWAM_STATE_ONLINE_TO_OFFLINE,
496*6ba597c5SAnurag S. Maskey 				    NWAM_AUX_STATE_CONDITIONS_NOT_MET);
497*6ba597c5SAnurag S. Maskey 			}
498*6ba597c5SAnurag S. Maskey 		}
499*6ba597c5SAnurag S. Maskey 
500*6ba597c5SAnurag S. Maskey 		break;
501*6ba597c5SAnurag S. Maskey 	default:
502*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_ncu_check_or_activate: "
503*6ba597c5SAnurag S. Maskey 		    "invalid priority-mode");
504*6ba597c5SAnurag S. Maskey 		break;
505*6ba597c5SAnurag S. Maskey 	}
506*6ba597c5SAnurag S. Maskey 
507*6ba597c5SAnurag S. Maskey 	return (0);
508*6ba597c5SAnurag S. Maskey }
509*6ba597c5SAnurag S. Maskey 
510*6ba597c5SAnurag S. Maskey void
511*6ba597c5SAnurag S. Maskey nwamd_ncp_activate_priority_group(int64_t priority)
512*6ba597c5SAnurag S. Maskey {
513*6ba597c5SAnurag S. Maskey 	struct nwamd_ncu_check_walk_arg wa;
514*6ba597c5SAnurag S. Maskey 	nwamd_event_t check_event, priority_event;
515*6ba597c5SAnurag S. Maskey 
516*6ba597c5SAnurag S. Maskey 	if (priority == INVALID_PRIORITY_GROUP)
517*6ba597c5SAnurag S. Maskey 		return;
518*6ba597c5SAnurag S. Maskey 
519*6ba597c5SAnurag S. Maskey 	(void) pthread_mutex_lock(&active_ncp_mutex);
520*6ba597c5SAnurag S. Maskey 	if (priority == current_ncu_priority_group) {
521*6ba597c5SAnurag S. Maskey 		(void) pthread_mutex_unlock(&active_ncp_mutex);
522*6ba597c5SAnurag S. Maskey 		return;
523*6ba597c5SAnurag S. Maskey 	}
524*6ba597c5SAnurag S. Maskey 	(void) pthread_mutex_unlock(&active_ncp_mutex);
525*6ba597c5SAnurag S. Maskey 
526*6ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "nwamd_ncp_activate_priority_group: "
527*6ba597c5SAnurag S. Maskey 	    "activating priority group %lld", priority);
528*6ba597c5SAnurag S. Maskey 
529*6ba597c5SAnurag S. Maskey 	wa.manual = B_FALSE;
530*6ba597c5SAnurag S. Maskey 	wa.priority_group = priority;
531*6ba597c5SAnurag S. Maskey 	wa.exclusive_ncus = 0;
532*6ba597c5SAnurag S. Maskey 	wa.exclusive_online_ncus = 0;
533*6ba597c5SAnurag S. Maskey 	wa.shared_ncus = 0;
534*6ba597c5SAnurag S. Maskey 	wa.shared_online_ncus = 0;
535*6ba597c5SAnurag S. Maskey 	wa.all_ncus = 0;
536*6ba597c5SAnurag S. Maskey 	wa.all_online_ncus = 0;
537*6ba597c5SAnurag S. Maskey 	wa.activate_or_deactivate = B_TRUE;
538*6ba597c5SAnurag S. Maskey 	wa.activate = B_TRUE;
539*6ba597c5SAnurag S. Maskey 
540*6ba597c5SAnurag S. Maskey 	if (nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU,
541*6ba597c5SAnurag S. Maskey 	    nwamd_ncu_check_or_activate, &wa) != 0) {
542*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_ncp_activate_priority_group: "
543*6ba597c5SAnurag S. Maskey 		    "nwamd_walk_objects() failed");
544*6ba597c5SAnurag S. Maskey 		return;
545*6ba597c5SAnurag S. Maskey 	}
546*6ba597c5SAnurag S. Maskey 
547*6ba597c5SAnurag S. Maskey 	/*
548*6ba597c5SAnurag S. Maskey 	 * Enqueue event to update current_ncu_priority_group and send to
549*6ba597c5SAnurag S. Maskey 	 * any event listeners.
550*6ba597c5SAnurag S. Maskey 	 */
551*6ba597c5SAnurag S. Maskey 	priority_event = nwamd_event_init_priority_group_change(priority);
552*6ba597c5SAnurag S. Maskey 	if (priority_event == NULL)
553*6ba597c5SAnurag S. Maskey 		return;
554*6ba597c5SAnurag S. Maskey 	nwamd_event_enqueue(priority_event);
555*6ba597c5SAnurag S. Maskey 
556*6ba597c5SAnurag S. Maskey 	/*
557*6ba597c5SAnurag S. Maskey 	 * Now we've activated a new priority group, enqueue an event
558*6ba597c5SAnurag S. Maskey 	 * to check up on the state of this priority group.
559*6ba597c5SAnurag S. Maskey 	 */
560*6ba597c5SAnurag S. Maskey 	check_event = nwamd_event_init_ncu_check();
561*6ba597c5SAnurag S. Maskey 	if (check_event == NULL)
562*6ba597c5SAnurag S. Maskey 		return;
563*6ba597c5SAnurag S. Maskey 	nwamd_event_enqueue_timed(check_event, ncu_wait_time);
564*6ba597c5SAnurag S. Maskey }
565*6ba597c5SAnurag S. Maskey 
566*6ba597c5SAnurag S. Maskey void
567*6ba597c5SAnurag S. Maskey nwamd_ncp_deactivate_priority_group(int64_t priority)
568*6ba597c5SAnurag S. Maskey {
569*6ba597c5SAnurag S. Maskey 	struct nwamd_ncu_check_walk_arg wa;
570*6ba597c5SAnurag S. Maskey 
571*6ba597c5SAnurag S. Maskey 	if (priority == INVALID_PRIORITY_GROUP)
572*6ba597c5SAnurag S. Maskey 		return;
573*6ba597c5SAnurag S. Maskey 
574*6ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "nwamd_ncp_deactivate_priority_group: "
575*6ba597c5SAnurag S. Maskey 	    "deactivating priority group %lld", priority);
576*6ba597c5SAnurag S. Maskey 
577*6ba597c5SAnurag S. Maskey 	wa.manual = B_FALSE;
578*6ba597c5SAnurag S. Maskey 	wa.priority_group = priority;
579*6ba597c5SAnurag S. Maskey 	wa.exclusive_ncus = 0;
580*6ba597c5SAnurag S. Maskey 	wa.exclusive_online_ncus = 0;
581*6ba597c5SAnurag S. Maskey 	wa.shared_ncus = 0;
582*6ba597c5SAnurag S. Maskey 	wa.shared_online_ncus = 0;
583*6ba597c5SAnurag S. Maskey 	wa.all_ncus = 0;
584*6ba597c5SAnurag S. Maskey 	wa.all_online_ncus = 0;
585*6ba597c5SAnurag S. Maskey 	wa.activate_or_deactivate = B_TRUE;
586*6ba597c5SAnurag S. Maskey 	wa.activate = B_FALSE;
587*6ba597c5SAnurag S. Maskey 
588*6ba597c5SAnurag S. Maskey 	if (nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU,
589*6ba597c5SAnurag S. Maskey 	    nwamd_ncu_check_or_activate, &wa) != 0) {
590*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_ncp_deactivate_priority_group: "
591*6ba597c5SAnurag S. Maskey 		    "nwamd_walk_objects() failed");
592*6ba597c5SAnurag S. Maskey 		return;
593*6ba597c5SAnurag S. Maskey 	}
594*6ba597c5SAnurag S. Maskey }
595*6ba597c5SAnurag S. Maskey 
596*6ba597c5SAnurag S. Maskey /*
597*6ba597c5SAnurag S. Maskey  * This function deactivates all priority groups at level 'priority' and lower
598*6ba597c5SAnurag S. Maskey  * (which is, numerically, all priorities >= priority).
599*6ba597c5SAnurag S. Maskey  */
600*6ba597c5SAnurag S. Maskey void
601*6ba597c5SAnurag S. Maskey nwamd_ncp_deactivate_priority_group_all(int64_t priority)
602*6ba597c5SAnurag S. Maskey {
603*6ba597c5SAnurag S. Maskey 	if (priority == INVALID_PRIORITY_GROUP)
604*6ba597c5SAnurag S. Maskey 		return;
605*6ba597c5SAnurag S. Maskey 
606*6ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "nwamd_ncp_deactivate_priority_group_all: "
607*6ba597c5SAnurag S. Maskey 	    "deactivating priority group less than or equal to %lld", priority);
608*6ba597c5SAnurag S. Maskey 
609*6ba597c5SAnurag S. Maskey 	do {
610*6ba597c5SAnurag S. Maskey 		nwamd_ncp_deactivate_priority_group(priority);
611*6ba597c5SAnurag S. Maskey 	} while (nwamd_ncp_find_next_priority_group(priority + 1, &priority));
612*6ba597c5SAnurag S. Maskey }
613*6ba597c5SAnurag S. Maskey 
614*6ba597c5SAnurag S. Maskey /*
615*6ba597c5SAnurag S. Maskey  * Returns 'true' if it found the highest priority group no higher then what
616*6ba597c5SAnurag S. Maskey  * is passed that should be activated and sets *priority to that.
617*6ba597c5SAnurag S. Maskey  */
618*6ba597c5SAnurag S. Maskey boolean_t
619*6ba597c5SAnurag S. Maskey nwamd_ncp_check_priority_group(int64_t *priority)
620*6ba597c5SAnurag S. Maskey {
621*6ba597c5SAnurag S. Maskey 	struct nwamd_ncu_check_walk_arg wa;
622*6ba597c5SAnurag S. Maskey 	boolean_t conditions_met = B_FALSE;
623*6ba597c5SAnurag S. Maskey 
624*6ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "nwamd_ncp_check_priority_group: "
625*6ba597c5SAnurag S. Maskey 	    "checking priority group %lld", *priority);
626*6ba597c5SAnurag S. Maskey 
627*6ba597c5SAnurag S. Maskey 	if (*priority == INVALID_PRIORITY_GROUP) {
628*6ba597c5SAnurag S. Maskey 		if (!nwamd_ncp_find_next_priority_group(0, priority))
629*6ba597c5SAnurag S. Maskey 			return (B_FALSE);
630*6ba597c5SAnurag S. Maskey 	}
631*6ba597c5SAnurag S. Maskey 
632*6ba597c5SAnurag S. Maskey 	while (!conditions_met) {
633*6ba597c5SAnurag S. Maskey 		(void) memset(&wa, 0, sizeof (wa));
634*6ba597c5SAnurag S. Maskey 		wa.manual = B_FALSE;
635*6ba597c5SAnurag S. Maskey 		wa.priority_group = *priority;
636*6ba597c5SAnurag S. Maskey 		wa.activate_or_deactivate = B_FALSE;
637*6ba597c5SAnurag S. Maskey 
638*6ba597c5SAnurag S. Maskey 		if (nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU,
639*6ba597c5SAnurag S. Maskey 		    nwamd_ncu_check_or_activate, &wa) != 0) {
640*6ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "nwamd_ncp_check_priority_group: "
641*6ba597c5SAnurag S. Maskey 			    "nwamd_walk_objects() failed");
642*6ba597c5SAnurag S. Maskey 			return (B_FALSE);
643*6ba597c5SAnurag S. Maskey 		}
644*6ba597c5SAnurag S. Maskey 
645*6ba597c5SAnurag S. Maskey 		/*
646*6ba597c5SAnurag S. Maskey 		 * Are activation conditons satisifed? In other words:
647*6ba597c5SAnurag S. Maskey 		 * - exactly one of the exclusive NCUs is online
648*6ba597c5SAnurag S. Maskey 		 * - 1 or more shared NCUs are online
649*6ba597c5SAnurag S. Maskey 		 * - all of the all NCUs are online.
650*6ba597c5SAnurag S. Maskey 		 * If any of these is untrue, conditions are not satisfied.
651*6ba597c5SAnurag S. Maskey 		 */
652*6ba597c5SAnurag S. Maskey 		conditions_met = B_TRUE;
653*6ba597c5SAnurag S. Maskey 		if (wa.exclusive_ncus > 0 && wa.exclusive_online_ncus != 1)
654*6ba597c5SAnurag S. Maskey 			conditions_met = B_FALSE;
655*6ba597c5SAnurag S. Maskey 		if (wa.shared_ncus > 0 && wa.shared_online_ncus == 0)
656*6ba597c5SAnurag S. Maskey 			conditions_met = B_FALSE;
657*6ba597c5SAnurag S. Maskey 		if (wa.all_ncus > 0 && wa.all_ncus != wa.all_online_ncus)
658*6ba597c5SAnurag S. Maskey 			conditions_met = B_FALSE;
659*6ba597c5SAnurag S. Maskey 		if (wa.exclusive_online_ncus == 0 &&
660*6ba597c5SAnurag S. Maskey 		    wa.shared_online_ncus == 0 && wa.all_online_ncus == 0)
661*6ba597c5SAnurag S. Maskey 			conditions_met = B_FALSE;
662*6ba597c5SAnurag S. Maskey 
663*6ba597c5SAnurag S. Maskey 		if (conditions_met) {
664*6ba597c5SAnurag S. Maskey 			return (B_TRUE);
665*6ba597c5SAnurag S. Maskey 		} else {
666*6ba597c5SAnurag S. Maskey 			/*
667*6ba597c5SAnurag S. Maskey 			 * If there is a next pg, activate it. If not, do
668*6ba597c5SAnurag S. Maskey 			 * nothing - we're stuck here unless an event occurs
669*6ba597c5SAnurag S. Maskey 			 * for our or a higher pg.
670*6ba597c5SAnurag S. Maskey 			 */
671*6ba597c5SAnurag S. Maskey 			if (!nwamd_ncp_find_next_priority_group
672*6ba597c5SAnurag S. Maskey 			    (wa.priority_group + 1, priority)) {
673*6ba597c5SAnurag S. Maskey 				nlog(LOG_DEBUG, "ran out of prio groups");
674*6ba597c5SAnurag S. Maskey 				return (B_FALSE);
675*6ba597c5SAnurag S. Maskey 			}
676*6ba597c5SAnurag S. Maskey 		}
677*6ba597c5SAnurag S. Maskey 	}
678*6ba597c5SAnurag S. Maskey 	return (B_FALSE);
679*6ba597c5SAnurag S. Maskey }
680*6ba597c5SAnurag S. Maskey 
681*6ba597c5SAnurag S. Maskey void
682*6ba597c5SAnurag S. Maskey nwamd_ncp_activate_manual_ncus(void)
683*6ba597c5SAnurag S. Maskey {
684*6ba597c5SAnurag S. Maskey 	struct nwamd_ncu_check_walk_arg wa;
685*6ba597c5SAnurag S. Maskey 
686*6ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "nwamd_ncp_activate_manual_ncus: activating NCUs");
687*6ba597c5SAnurag S. Maskey 
688*6ba597c5SAnurag S. Maskey 	wa.manual = B_TRUE;
689*6ba597c5SAnurag S. Maskey 	wa.activate_or_deactivate = B_TRUE;
690*6ba597c5SAnurag S. Maskey 	wa.activate = B_TRUE;
691*6ba597c5SAnurag S. Maskey 
692*6ba597c5SAnurag S. Maskey 	if (nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU,
693*6ba597c5SAnurag S. Maskey 	    nwamd_ncu_check_or_activate, &wa) != 0) {
694*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_ncp_activate_manual_ncus: "
695*6ba597c5SAnurag S. Maskey 		    "nwamd_walk_objects() failed");
696*6ba597c5SAnurag S. Maskey 		return;
697*6ba597c5SAnurag S. Maskey 	}
698*6ba597c5SAnurag S. Maskey }
699*6ba597c5SAnurag S. Maskey 
700*6ba597c5SAnurag S. Maskey void
701*6ba597c5SAnurag S. Maskey nwamd_create_ncu_check_event(uint64_t when)
702*6ba597c5SAnurag S. Maskey {
703*6ba597c5SAnurag S. Maskey 	nwamd_event_t check_event = nwamd_event_init_ncu_check();
704*6ba597c5SAnurag S. Maskey 	if (check_event != NULL)
705*6ba597c5SAnurag S. Maskey 		nwamd_event_enqueue_timed(check_event, when);
706*6ba597c5SAnurag S. Maskey }
707