4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <arpa/inet.h>
30 #include <libdllink.h>
31 #include <libdlwlan.h>
35 #include <netinet/in.h>
39 #include <sys/socket.h>
40 #include <sys/types.h>
43 #include "conditions.h"
49 * loc.c - contains routines which handle location abstraction.
52 pthread_mutex_t active_loc_mutex
= PTHREAD_MUTEX_INITIALIZER
;
53 char active_loc
[NWAM_MAX_NAME_LEN
];
56 loc_create_init_fini_event(nwam_loc_handle_t loch
, void *data
)
58 boolean_t
*init
= data
;
62 if (nwam_loc_get_name(loch
, &name
) != NWAM_SUCCESS
) {
63 nlog(LOG_ERR
, "loc_init_fini: could not get loc name");
67 event
= nwamd_event_init(*init
?
68 NWAM_EVENT_TYPE_OBJECT_INIT
: NWAM_EVENT_TYPE_OBJECT_FINI
,
69 NWAM_OBJECT_TYPE_LOC
, 0, name
);
71 nwamd_event_enqueue(event
);
78 * Walk all locs, creating init events for each.
83 boolean_t init
= B_TRUE
;
85 /* Unset active location */
86 (void) pthread_mutex_lock(&active_loc_mutex
);
88 (void) pthread_mutex_unlock(&active_loc_mutex
);
89 (void) nwam_walk_locs(loc_create_init_fini_event
, &init
, 0, NULL
);
93 * Walk all locs, creating fini events for each.
98 boolean_t init
= B_FALSE
;
100 (void) nwam_walk_locs(loc_create_init_fini_event
, &init
, 0, NULL
);
104 loc_is_enabled(nwam_loc_handle_t loch
)
106 nwam_value_t enabledval
;
107 boolean_t enabled
= B_FALSE
;
109 if (nwam_loc_get_prop_value(loch
, NWAM_LOC_PROP_ENABLED
,
110 &enabledval
) != NWAM_SUCCESS
) {
111 nlog(LOG_ERR
, "loc_is_enabled: could not retrieve "
115 if (nwam_value_get_boolean(enabledval
, &enabled
)
117 nlog(LOG_ERR
, "loc_is_enabled: could not retrieve "
119 nwam_value_free(enabledval
);
122 nwam_value_free(enabledval
);
127 loc_get_activation_mode(nwam_loc_handle_t loch
)
131 nwam_value_t activationval
;
133 if (nwam_loc_get_prop_value(loch
, NWAM_LOC_PROP_ACTIVATION_MODE
,
134 &activationval
) != NWAM_SUCCESS
) {
135 nlog(LOG_ERR
, "loc_get_activation_mode: could not retrieve "
136 "activation mode value");
139 err
= nwam_value_get_uint64(activationval
, &activation
);
140 nwam_value_free(activationval
);
141 if (err
!= NWAM_SUCCESS
) {
142 nlog(LOG_ERR
, "loc_get_activation_mode: could not retrieve "
143 "activation mode value");
147 return ((int64_t)activation
);
150 /* Enables the location. */
152 nwamd_loc_activate(const char *object_name
)
156 nlog(LOG_DEBUG
, "nwamd_loc_activate: activating loc %s",
160 * Find currently enabled location and change its state to disabled
161 * if it is a manual location, or offline (if it is not).
162 * Only manual locations reach disabled, since conditional and
163 * system locations which are manually disabled simply revert to
164 * their conditions for activation.
166 if ((enabled
= malloc(NWAM_MAX_NAME_LEN
)) != NULL
&&
167 nwamd_lookup_string_property(NET_LOC_FMRI
, NET_LOC_PG
,
168 NET_LOC_SELECTED_PROP
, enabled
, NWAM_MAX_NAME_LEN
) == 0) {
169 /* Only change state if current != new */
170 if (strcmp(enabled
, object_name
) != 0) {
171 boolean_t do_disable
= B_FALSE
;
172 nwamd_object_t eobj
= nwamd_object_find
173 (NWAM_OBJECT_TYPE_LOC
, enabled
);
175 nlog(LOG_INFO
, "nwamd_loc_activate: could not "
176 "find old location %s", enabled
);
180 * Disable if the old location was manual, since the
181 * only way a manual location can deactivate is if
185 (loc_get_activation_mode(eobj
->nwamd_object_handle
)
186 == (int64_t)NWAM_ACTIVATION_MODE_MANUAL
);
187 nwamd_object_release(eobj
);
190 nlog(LOG_DEBUG
, "nwamd_loc_activate: "
191 "disable needed for old location %s",
193 nwamd_object_set_state
194 (NWAM_OBJECT_TYPE_LOC
, enabled
,
196 NWAM_AUX_STATE_MANUAL_DISABLE
);
198 nlog(LOG_DEBUG
, "nwamd_loc_activate: "
199 "offline needed for old location %s",
201 nwamd_object_set_state
202 (NWAM_OBJECT_TYPE_LOC
, enabled
,
204 NWAM_AUX_STATE_CONDITIONS_NOT_MET
);
211 if (nwamd_set_string_property(NET_LOC_FMRI
, NET_LOC_PG
,
212 NET_LOC_SELECTED_PROP
, object_name
) == 0) {
213 char *state
= smf_get_state(NET_LOC_FMRI
);
214 nlog(LOG_INFO
, "nwamd_loc_activate: set %s/%s to %s; "
215 "service is in %s state", NET_LOC_PG
, NET_LOC_SELECTED_PROP
,
216 object_name
, state
== NULL
? "unknown" : state
);
218 (void) smf_restore_instance(NET_LOC_FMRI
);
219 if (smf_refresh_instance(NET_LOC_FMRI
) == 0) {
220 (void) pthread_mutex_lock(&active_loc_mutex
);
221 (void) strlcpy(active_loc
, object_name
,
222 sizeof (active_loc
));
223 (void) pthread_mutex_unlock(&active_loc_mutex
);
224 nwamd_object_set_state(NWAM_OBJECT_TYPE_LOC
,
226 NWAM_STATE_ONLINE
, NWAM_AUX_STATE_ACTIVE
);
228 nlog(LOG_ERR
, "nwamd_loc_activate: "
229 "%s could not be refreshed", NET_LOC_FMRI
);
230 nwamd_object_set_state(NWAM_OBJECT_TYPE_LOC
,
232 NWAM_STATE_MAINTENANCE
,
233 NWAM_AUX_STATE_METHOD_FAILED
);
238 struct nwamd_loc_check_walk_arg
{
239 nwamd_object_t winning_object
;
240 uint64_t winning_rating
;
244 * Determine which location should be activated.
247 nwamd_loc_check(nwamd_object_t object
, void *data
)
249 struct nwamd_loc_check_walk_arg
*wa
= data
;
250 nwam_loc_handle_t loch
= object
->nwamd_object_handle
;
251 nwam_value_t conditionval
;
253 uint64_t rating
, activation
;
258 lactivation
= loc_get_activation_mode(object
->nwamd_object_handle
);
260 if (lactivation
== -1)
263 activation
= (uint64_t)lactivation
;
264 switch (activation
) {
265 case NWAM_ACTIVATION_MODE_MANUAL
:
266 if (loc_is_enabled(loch
)) {
267 /* Manually enabled locations should always win out. */
268 nlog(LOG_DEBUG
, "nwamd_loc_check: %s is enabled",
269 object
->nwamd_object_name
);
270 wa
->winning_object
= object
;
271 wa
->winning_rating
= UINT64_MAX
;
273 nlog(LOG_DEBUG
, "nwamd_loc_check: %s is disabled",
274 object
->nwamd_object_name
);
275 if (object
->nwamd_object_state
!= NWAM_STATE_DISABLED
) {
276 nwamd_object_set_state(NWAM_OBJECT_TYPE_LOC
,
277 object
->nwamd_object_name
,
279 NWAM_AUX_STATE_MANUAL_DISABLE
);
285 case NWAM_ACTIVATION_MODE_CONDITIONAL_ANY
:
286 case NWAM_ACTIVATION_MODE_CONDITIONAL_ALL
:
287 if (loc_is_enabled(loch
)) {
288 /* Manually enabled locations should always win out. */
289 nlog(LOG_DEBUG
, "nwamd_loc_check: %s is enabled",
290 object
->nwamd_object_name
);
291 wa
->winning_object
= object
;
292 wa
->winning_rating
= UINT64_MAX
;
295 if (nwam_loc_get_prop_value(loch
,
296 NWAM_LOC_PROP_CONDITIONS
, &conditionval
) != NWAM_SUCCESS
) {
297 nlog(LOG_ERR
, "nwamd_loc_check: could not retrieve "
301 if (nwam_value_get_string_array(conditionval
,
302 &conditions
, &nelem
) != NWAM_SUCCESS
) {
303 nlog(LOG_ERR
, "nwamd_loc_check: could not retrieve "
305 nwam_value_free(conditionval
);
308 satisfied
= nwamd_check_conditions(activation
, conditions
,
312 rating
= nwamd_rate_conditions(activation
,
314 if (rating
> wa
->winning_rating
) {
315 wa
->winning_object
= object
;
316 wa
->winning_rating
= rating
;
319 nwam_value_free(conditionval
);
322 case NWAM_ACTIVATION_MODE_SYSTEM
:
323 if (loc_is_enabled(loch
)) {
324 /* Manually enabled locations should always win out. */
325 nlog(LOG_DEBUG
, "nwamd_loc_check: %s is enabled",
326 object
->nwamd_object_name
);
327 wa
->winning_object
= object
;
328 wa
->winning_rating
= UINT64_MAX
;
331 /* Either NoNet, Automatic or Legacy location, so skip. */
342 nwamd_ncu_online_check(nwamd_object_t object
, void *data
)
344 boolean_t
*online
= data
;
345 nwamd_ncu_t
*ncu_data
= object
->nwamd_object_data
;
347 if (ncu_data
->ncu_type
!= NWAM_NCU_TYPE_INTERFACE
)
350 if (object
->nwamd_object_state
== NWAM_STATE_ONLINE
) {
351 /* An online IP NCU found, stop walk */
359 nwamd_loc_check_conditions(void)
361 struct nwamd_loc_check_walk_arg wa
= { NULL
, 0 };
362 const char *winning_loc
;
363 boolean_t ncu_online
= B_FALSE
;
367 * Walk the NCUs to find out if at least one IP NCU is online. If so,
368 * check the activation-mode and conditions. If not, enable the NoNet
371 (void) nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU
, nwamd_ncu_online_check
,
375 winning_loc
= NWAM_LOC_NAME_NO_NET
;
377 (void) nwamd_walk_objects(NWAM_OBJECT_TYPE_LOC
, nwamd_loc_check
,
379 if (wa
.winning_object
!= NULL
)
380 winning_loc
= wa
.winning_object
->nwamd_object_name
;
382 winning_loc
= NWAM_LOC_NAME_AUTOMATIC
;
384 nlog(LOG_DEBUG
, "nwamd_loc_check_conditions: winning loc is %s",
387 /* If the winning location is already active, do nothing */
388 (void) pthread_mutex_lock(&active_loc_mutex
);
389 is_active
= (strcmp(active_loc
, winning_loc
) == 0);
390 (void) pthread_mutex_unlock(&active_loc_mutex
);
394 nwamd_object_set_state(NWAM_OBJECT_TYPE_LOC
, winning_loc
,
395 NWAM_STATE_OFFLINE_TO_ONLINE
, NWAM_AUX_STATE_METHOD_RUNNING
);
399 nwamd_loc_action(const char *loc
, nwam_action_t action
)
401 nwamd_event_t event
= nwamd_event_init_object_action
402 (NWAM_OBJECT_TYPE_LOC
, loc
, NULL
, action
);
405 nwamd_event_enqueue(event
);
410 * Event handling functions.
413 /* Handle loc initialization/refresh event */
415 nwamd_loc_handle_init_event(nwamd_event_t event
)
417 nwamd_object_t object
;
418 nwam_loc_handle_t loch
;
420 boolean_t new_enabled
, old_enabled
= B_FALSE
;
423 if ((err
= nwam_loc_read(event
->event_object
, 0, &loch
))
425 nlog(LOG_ERR
, "nwamd_loc_handle_init_event: could not "
426 "read object '%s': %s", event
->event_object
,
428 nwamd_event_do_not_send(event
);
431 if ((object
= nwamd_object_find(NWAM_OBJECT_TYPE_LOC
,
432 event
->event_object
)) != NULL
) {
433 old_enabled
= loc_is_enabled(object
->nwamd_object_handle
);
434 nwam_loc_free(object
->nwamd_object_handle
);
435 object
->nwamd_object_handle
= loch
;
437 object
= nwamd_object_init(NWAM_OBJECT_TYPE_LOC
,
438 event
->event_object
, loch
, NULL
);
439 object
->nwamd_object_state
= NWAM_STATE_OFFLINE
;
440 object
->nwamd_object_aux_state
=
441 NWAM_AUX_STATE_CONDITIONS_NOT_MET
;
443 new_enabled
= loc_is_enabled(loch
);
444 state
= object
->nwamd_object_state
;
445 nwamd_object_release(object
);
448 * If this location is ONLINE and the value of the "enabled" property
449 * has not changed, then this location is getting refreshed because it
450 * was committed with changes. Change states to re-activate itself.
451 * If the "enabled" property has changed, then this location is
452 * getting refreshed as part of a enable/disable action and there is
453 * no need to change states here.
455 if (state
== NWAM_STATE_ONLINE
&& old_enabled
== new_enabled
) {
456 nwamd_object_set_state(NWAM_OBJECT_TYPE_LOC
,
457 event
->event_object
, NWAM_STATE_OFFLINE_TO_ONLINE
,
458 NWAM_AUX_STATE_METHOD_RUNNING
);
462 /* Handle loc finish event */
464 nwamd_loc_handle_fini_event(nwamd_event_t event
)
466 nwamd_object_t object
;
468 nlog(LOG_DEBUG
, "nwamd_loc_handle_fini_event(%s)",
469 event
->event_object
);
471 /* Don't disable the location, as this can enable the Automatic loc */
472 if ((object
= nwamd_object_find(NWAM_OBJECT_TYPE_LOC
,
473 event
->event_object
)) == NULL
) {
474 nlog(LOG_INFO
, "nwamd_loc_handle_fini_event: "
475 "loc %s not found", event
->event_object
);
476 nwamd_event_do_not_send(event
);
479 nwamd_object_release_and_destroy(object
);
483 nwamd_loc_handle_action_event(nwamd_event_t event
)
485 nwamd_object_t object
;
487 switch (event
->event_msg
->nwe_data
.nwe_object_action
.nwe_action
) {
488 case NWAM_ACTION_ENABLE
:
489 object
= nwamd_object_find(NWAM_OBJECT_TYPE_LOC
,
490 event
->event_object
);
491 if (object
== NULL
) {
492 nlog(LOG_ERR
, "nwamd_loc_handle_action_event: "
493 "could not find location %s", event
->event_object
);
494 nwamd_event_do_not_send(event
);
497 if (object
->nwamd_object_state
== NWAM_STATE_ONLINE
) {
498 nlog(LOG_DEBUG
, "nwamd_loc_handle_action_event: "
499 "location %s already online, nothing to do",
500 event
->event_object
);
501 nwamd_object_release(object
);
504 nwamd_object_release(object
);
506 nwamd_object_set_state(NWAM_OBJECT_TYPE_LOC
,
507 event
->event_object
, NWAM_STATE_OFFLINE_TO_ONLINE
,
508 NWAM_AUX_STATE_METHOD_RUNNING
);
510 case NWAM_ACTION_DISABLE
:
511 object
= nwamd_object_find(NWAM_OBJECT_TYPE_LOC
,
512 event
->event_object
);
513 if (object
== NULL
) {
514 nlog(LOG_ERR
, "nwamd_loc_handle_action_event: "
515 "could not find location %s", event
->event_object
);
516 nwamd_event_do_not_send(event
);
519 if (object
->nwamd_object_state
== NWAM_STATE_DISABLED
) {
520 nlog(LOG_DEBUG
, "nwamd_loc_handle_action_event: "
521 "location %s already disabled, nothing to do",
522 event
->event_object
);
523 nwamd_object_release(object
);
526 nwamd_object_release(object
);
528 nwamd_object_set_state(NWAM_OBJECT_TYPE_LOC
,
529 event
->event_object
, NWAM_STATE_ONLINE_TO_OFFLINE
,
530 NWAM_AUX_STATE_MANUAL_DISABLE
);
532 case NWAM_ACTION_ADD
:
533 case NWAM_ACTION_REFRESH
:
534 nwamd_loc_handle_init_event(event
);
536 case NWAM_ACTION_DESTROY
:
537 nwamd_loc_handle_fini_event(event
);
540 nlog(LOG_INFO
, "nwam_loc_handle_action_event: "
541 "unexpected action");
547 nwamd_loc_handle_state_event(nwamd_event_t event
)
549 nwamd_object_t object
;
550 nwam_state_t new_state
;
551 nwam_aux_state_t new_aux_state
;
553 if ((object
= nwamd_object_find(NWAM_OBJECT_TYPE_LOC
,
554 event
->event_object
)) == NULL
) {
555 nlog(LOG_INFO
, "nwamd_loc_handle_state_event: "
556 "state event for nonexistent loc %s", event
->event_object
);
557 nwamd_event_do_not_send(event
);
560 new_state
= event
->event_msg
->nwe_data
.nwe_object_state
.nwe_state
;
562 event
->event_msg
->nwe_data
.nwe_object_state
.nwe_aux_state
;
564 if (new_state
== object
->nwamd_object_state
&&
565 new_aux_state
== object
->nwamd_object_aux_state
) {
566 nlog(LOG_DEBUG
, "nwamd_loc_handle_state_event: "
567 "loc %s already in state (%s , %s)",
568 object
->nwamd_object_name
,
569 nwam_state_to_string(new_state
),
570 nwam_aux_state_to_string(new_aux_state
));
571 nwamd_object_release(object
);
575 object
->nwamd_object_state
= new_state
;
576 object
->nwamd_object_aux_state
= new_aux_state
;
578 nlog(LOG_DEBUG
, "nwamd_loc_handle_state_event: changing state for loc "
579 "%s to (%s , %s)", object
->nwamd_object_name
,
580 nwam_state_to_string(object
->nwamd_object_state
),
581 nwam_aux_state_to_string(object
->nwamd_object_aux_state
));
583 nwamd_object_release(object
);
586 * State machine for location.
589 case NWAM_STATE_OFFLINE_TO_ONLINE
:
590 nwamd_loc_activate(event
->event_object
);
592 case NWAM_STATE_ONLINE_TO_OFFLINE
:
594 * Don't need to deactivate current location - condition check
595 * will activate another. If the currently active location is
596 * being deactivated, then it is being manually deactivated;
597 * so also clear active_loc so condition checking is not
600 (void) pthread_mutex_lock(&active_loc_mutex
);
601 if (strcmp(event
->event_object
, active_loc
) == 0)
602 active_loc
[0] = '\0';
603 (void) pthread_mutex_unlock(&active_loc_mutex
);
604 nwamd_loc_check_conditions();
606 case NWAM_STATE_DISABLED
:
607 case NWAM_STATE_OFFLINE
:
608 case NWAM_STATE_UNINITIALIZED
:
609 case NWAM_STATE_MAINTENANCE
:
610 case NWAM_STATE_DEGRADED
: