dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / lib / nwamd / loc.c
blob4376eb00fe7514cb400dda68ab68db022f85f9ee
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <arpa/inet.h>
27 #include <errno.h>
28 #include <inet/ip.h>
29 #include <libdladm.h>
30 #include <libdllink.h>
31 #include <libdlwlan.h>
32 #include <libscf.h>
33 #include <limits.h>
34 #include <netdb.h>
35 #include <netinet/in.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/socket.h>
40 #include <sys/types.h>
42 #include <libnwam.h>
43 #include "conditions.h"
44 #include "events.h"
45 #include "objects.h"
46 #include "util.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];
55 static int
56 loc_create_init_fini_event(nwam_loc_handle_t loch, void *data)
58 boolean_t *init = data;
59 char *name;
60 nwamd_event_t event;
62 if (nwam_loc_get_name(loch, &name) != NWAM_SUCCESS) {
63 nlog(LOG_ERR, "loc_init_fini: could not get loc name");
64 return (0);
67 event = nwamd_event_init(*init ?
68 NWAM_EVENT_TYPE_OBJECT_INIT : NWAM_EVENT_TYPE_OBJECT_FINI,
69 NWAM_OBJECT_TYPE_LOC, 0, name);
70 if (event != NULL)
71 nwamd_event_enqueue(event);
72 free(name);
74 return (0);
78 * Walk all locs, creating init events for each.
80 void
81 nwamd_init_locs(void)
83 boolean_t init = B_TRUE;
85 /* Unset active location */
86 (void) pthread_mutex_lock(&active_loc_mutex);
87 active_loc[0] = '\0';
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.
95 void
96 nwamd_fini_locs(void)
98 boolean_t init = B_FALSE;
100 (void) nwam_walk_locs(loc_create_init_fini_event, &init, 0, NULL);
103 static boolean_t
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 "
112 "enabled value");
113 return (B_FALSE);
115 if (nwam_value_get_boolean(enabledval, &enabled)
116 != NWAM_SUCCESS) {
117 nlog(LOG_ERR, "loc_is_enabled: could not retrieve "
118 "enabled value");
119 nwam_value_free(enabledval);
120 return (B_FALSE);
122 nwam_value_free(enabledval);
123 return (enabled);
126 static int64_t
127 loc_get_activation_mode(nwam_loc_handle_t loch)
129 nwam_error_t err;
130 uint64_t activation;
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");
137 return (-1);
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");
144 return (-1);
147 return ((int64_t)activation);
150 /* Enables the location. */
151 static void
152 nwamd_loc_activate(const char *object_name)
154 char *enabled;
156 nlog(LOG_DEBUG, "nwamd_loc_activate: activating loc %s",
157 object_name);
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);
174 if (eobj == NULL) {
175 nlog(LOG_INFO, "nwamd_loc_activate: could not "
176 "find old location %s", enabled);
177 goto skip_disable;
180 * Disable if the old location was manual, since the
181 * only way a manual location can deactivate is if
182 * it is disabled.
184 do_disable =
185 (loc_get_activation_mode(eobj->nwamd_object_handle)
186 == (int64_t)NWAM_ACTIVATION_MODE_MANUAL);
187 nwamd_object_release(eobj);
189 if (do_disable) {
190 nlog(LOG_DEBUG, "nwamd_loc_activate: "
191 "disable needed for old location %s",
192 enabled);
193 nwamd_object_set_state
194 (NWAM_OBJECT_TYPE_LOC, enabled,
195 NWAM_STATE_DISABLED,
196 NWAM_AUX_STATE_MANUAL_DISABLE);
197 } else {
198 nlog(LOG_DEBUG, "nwamd_loc_activate: "
199 "offline needed for old location %s",
200 enabled);
201 nwamd_object_set_state
202 (NWAM_OBJECT_TYPE_LOC, enabled,
203 NWAM_STATE_OFFLINE,
204 NWAM_AUX_STATE_CONDITIONS_NOT_MET);
208 skip_disable:
209 free(enabled);
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);
217 free(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,
225 object_name,
226 NWAM_STATE_ONLINE, NWAM_AUX_STATE_ACTIVE);
227 } else {
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,
231 object_name,
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.
246 static int
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;
252 int64_t lactivation;
253 uint64_t rating, activation;
254 boolean_t satisfied;
255 char **conditions;
256 uint_t nelem;
258 lactivation = loc_get_activation_mode(object->nwamd_object_handle);
260 if (lactivation == -1)
261 return (0);
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;
272 } else {
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,
278 NWAM_STATE_DISABLED,
279 NWAM_AUX_STATE_MANUAL_DISABLE);
283 return (0);
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 "
298 "condition value");
299 return (0);
301 if (nwam_value_get_string_array(conditionval,
302 &conditions, &nelem) != NWAM_SUCCESS) {
303 nlog(LOG_ERR, "nwamd_loc_check: could not retrieve "
304 "condition value");
305 nwam_value_free(conditionval);
306 return (0);
308 satisfied = nwamd_check_conditions(activation, conditions,
309 nelem);
311 if (satisfied) {
312 rating = nwamd_rate_conditions(activation,
313 conditions, nelem);
314 if (rating > wa->winning_rating) {
315 wa->winning_object = object;
316 wa->winning_rating = rating;
319 nwam_value_free(conditionval);
320 return (0);
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. */
333 return (0);
334 default:
335 return (0);
337 /*NOTREACHED*/
338 return (0);
341 static int
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)
348 return (0);
350 if (object->nwamd_object_state == NWAM_STATE_ONLINE) {
351 /* An online IP NCU found, stop walk */
352 *online = B_TRUE;
353 return (1);
355 return (0);
358 void
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;
364 boolean_t is_active;
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
369 * location.
371 (void) nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU, nwamd_ncu_online_check,
372 &ncu_online);
374 if (!ncu_online) {
375 winning_loc = NWAM_LOC_NAME_NO_NET;
376 } else {
377 (void) nwamd_walk_objects(NWAM_OBJECT_TYPE_LOC, nwamd_loc_check,
378 &wa);
379 if (wa.winning_object != NULL)
380 winning_loc = wa.winning_object->nwamd_object_name;
381 else
382 winning_loc = NWAM_LOC_NAME_AUTOMATIC;
384 nlog(LOG_DEBUG, "nwamd_loc_check_conditions: winning loc is %s",
385 winning_loc);
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);
391 if (is_active)
392 return;
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);
403 if (event == NULL)
404 return (1);
405 nwamd_event_enqueue(event);
406 return (0);
410 * Event handling functions.
413 /* Handle loc initialization/refresh event */
414 void
415 nwamd_loc_handle_init_event(nwamd_event_t event)
417 nwamd_object_t object;
418 nwam_loc_handle_t loch;
419 nwam_error_t err;
420 boolean_t new_enabled, old_enabled = B_FALSE;
421 nwam_state_t state;
423 if ((err = nwam_loc_read(event->event_object, 0, &loch))
424 != NWAM_SUCCESS) {
425 nlog(LOG_ERR, "nwamd_loc_handle_init_event: could not "
426 "read object '%s': %s", event->event_object,
427 nwam_strerror(err));
428 nwamd_event_do_not_send(event);
429 return;
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;
436 } else {
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 */
463 void
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);
477 return;
479 nwamd_object_release_and_destroy(object);
482 void
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);
495 return;
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);
502 return;
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);
509 break;
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);
517 return;
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);
524 return;
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);
531 break;
532 case NWAM_ACTION_ADD:
533 case NWAM_ACTION_REFRESH:
534 nwamd_loc_handle_init_event(event);
535 break;
536 case NWAM_ACTION_DESTROY:
537 nwamd_loc_handle_fini_event(event);
538 break;
539 default:
540 nlog(LOG_INFO, "nwam_loc_handle_action_event: "
541 "unexpected action");
542 break;
546 void
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);
558 return;
560 new_state = event->event_msg->nwe_data.nwe_object_state.nwe_state;
561 new_aux_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);
572 return;
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.
588 switch (new_state) {
589 case NWAM_STATE_OFFLINE_TO_ONLINE:
590 nwamd_loc_activate(event->event_object);
591 break;
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
598 * confused.
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();
605 break;
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:
611 default:
612 /* do nothing */
613 break;