/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "conditions.h" #include "events.h" #include "objects.h" #include "util.h" /* * enm.c - contains routines which handle ENM (external network modifier) * abstraction. ENMs represent scripts or services that can be activated either * manually or in response to network conditions. */ #define CTRUN "/usr/bin/ctrun" static int enm_create_init_fini_event(nwam_enm_handle_t enmh, void *data) { boolean_t *init = data; char *name; nwamd_event_t enm_event; if (nwam_enm_get_name(enmh, &name) != NWAM_SUCCESS) { nlog(LOG_ERR, "enm_init_fini: could not get enm name"); return (0); } enm_event = nwamd_event_init(*init ? NWAM_EVENT_TYPE_OBJECT_INIT : NWAM_EVENT_TYPE_OBJECT_FINI, NWAM_OBJECT_TYPE_ENM, 0, name); if (enm_event != NULL) nwamd_event_enqueue(enm_event); free(name); return (0); } /* * Walk all ENMs, creating init events for each. */ void nwamd_init_enms(void) { boolean_t init = B_TRUE; (void) nwam_walk_enms(enm_create_init_fini_event, &init, 0, NULL); } /* * Walk all ENMs, creating fini events for each. */ void nwamd_fini_enms(void) { boolean_t init = B_FALSE; (void) nwam_walk_enms(enm_create_init_fini_event, &init, 0, NULL); } static boolean_t enm_is_enabled(nwam_enm_handle_t enmh) { nwam_value_t enabledval; boolean_t enabled = B_FALSE; if (nwam_enm_get_prop_value(enmh, NWAM_ENM_PROP_ENABLED, &enabledval) != NWAM_SUCCESS) { /* It's legal for a conditional ENM to not specify "enabled" */ return (B_FALSE); } if (nwam_value_get_boolean(enabledval, &enabled) != NWAM_SUCCESS) { nlog(LOG_ERR, "enm_is_enabled: could not retrieve " "enabled value"); } nwam_value_free(enabledval); return (enabled); } static int64_t enm_get_activation_mode(nwam_enm_handle_t enmh) { uint64_t activation; int64_t ret; nwam_value_t activationval; if (nwam_enm_get_prop_value(enmh, NWAM_ENM_PROP_ACTIVATION_MODE, &activationval) != NWAM_SUCCESS) { nlog(LOG_ERR, "enm_get_activation_mode: could not retrieve " "activation mode value"); return (-1); } if (nwam_value_get_uint64(activationval, &activation) != NWAM_SUCCESS) { nlog(LOG_ERR, "enm_get_activation_mode: could not retrieve " "activation mode value"); ret = -1; } else { ret = activation; } nwam_value_free(activationval); return (ret); } static void * nwamd_enm_activate_deactivate_thread(void *arg) { char *object_name = arg; nwamd_object_t object; nwam_enm_handle_t enmh; nwam_value_t scriptval = NULL; nwam_state_t state; nwam_aux_state_t aux_state; char *script, *copy = NULL; const char **argv = NULL; boolean_t going_online, disable_succeeded = B_FALSE; int ret; object = nwamd_object_find(NWAM_OBJECT_TYPE_ENM, object_name); if (object == NULL) { nlog(LOG_ERR, "nwamd_enm_activate_deactivate_thread: " "could not find enm %s", object_name); goto done; } enmh = object->nwamd_object_handle; going_online = (object->nwamd_object_state == NWAM_STATE_OFFLINE_TO_ONLINE); /* * We're starting if current state is offline* and stopping otherwise. */ if (nwam_enm_get_prop_value(enmh, going_online ? NWAM_ENM_PROP_START : NWAM_ENM_PROP_STOP, &scriptval) != NWAM_SUCCESS || nwam_value_get_string(scriptval, &script) != NWAM_SUCCESS) { /* * If we're stopping, it's not an error for no script to * be specified. */ nlog(going_online ? LOG_ERR : LOG_DEBUG, "nwamd_enm_activate_deactivate_thread: " "no script specified for enm %s", object_name); if (going_online) { state = NWAM_STATE_MAINTENANCE; aux_state = NWAM_AUX_STATE_METHOD_MISSING; } else { disable_succeeded = B_TRUE; } } else { char *lasts; const char **newargv; int i = 0; struct timeval now; nlog(LOG_DEBUG, "nwamd_enm_activate_deactivate_thread: " "running script %s for enm %s", script, object_name); /* * The script may take a number of arguments. We need to * create a string array consisting of the wrapper command * (ctrun), ENM script name, arguments and NULL array * terminator. Start with an array of size equal to the * string length (since the number of arguments will always * be less than this) and shrink array to the actual number * of arguments when we have parsed the string. */ if ((copy = strdup(script)) == NULL || (argv = calloc(strlen(script), sizeof (char *))) == NULL) { ret = 1; goto err; } argv[i++] = CTRUN; argv[i++] = strtok_r(copy, " ", &lasts); if (argv[1] == NULL) { ret = 1; goto err; } for (; (argv[i] = strtok_r(NULL, " ", &lasts)) != NULL; i++) {} newargv = realloc(argv, (i + 1) * sizeof (char *)); argv = newargv; /* Store the current time as the time the script began */ (void) gettimeofday(&now, NULL); object->nwamd_script_time = now; /* * Release the object so that it is not blocked while the * script is running. */ nwamd_object_release(object); ret = nwamd_start_childv(CTRUN, argv); /* * Find the object again, now that the script has finished * running. Check if this ENM was re-read during that time by * comparing the object's script time with the one from above. */ object = nwamd_object_find(NWAM_OBJECT_TYPE_ENM, object_name); if (object == NULL) { nlog(LOG_ERR, "nwamd_enm_activate_deactivate_thread: " "could not find enm %s after running script", object_name); goto done; } if (object->nwamd_script_time.tv_sec != now.tv_sec || object->nwamd_script_time.tv_usec != now.tv_usec) { nlog(LOG_INFO, "nwamd_enm_activate_deactivate_thread: " "enm %s has been refreshed, nothing to do", object_name); nwamd_object_release(object); goto done; } (void) gettimeofday(&object->nwamd_script_time, NULL); err: /* * If script execution fails and we're not destroying the * object, go to maintenance. */ if (ret != 0) { nlog(LOG_ERR, "nwamd_enm_activate_deactivate_thread: " "execution of '%s' failed for enm %s", script, object_name); if (object->nwamd_object_aux_state != NWAM_AUX_STATE_UNINITIALIZED) { state = NWAM_STATE_MAINTENANCE; aux_state = NWAM_AUX_STATE_METHOD_FAILED; } else { state = NWAM_STATE_UNINITIALIZED; aux_state = NWAM_AUX_STATE_UNINITIALIZED; } } else { if (going_online) { state = NWAM_STATE_ONLINE; aux_state = NWAM_AUX_STATE_ACTIVE; } else { disable_succeeded = B_TRUE; } } } if (disable_succeeded) { /* * If aux state is "manual disable", we know * this was a disable request, otherwise it was * _fini request or a condition satisfaction * failure. */ switch (object->nwamd_object_aux_state) { case NWAM_AUX_STATE_MANUAL_DISABLE: state = NWAM_STATE_DISABLED; aux_state = NWAM_AUX_STATE_MANUAL_DISABLE; break; case NWAM_AUX_STATE_UNINITIALIZED: state = NWAM_STATE_UNINITIALIZED; aux_state = NWAM_AUX_STATE_UNINITIALIZED; break; default: state = NWAM_STATE_OFFLINE; aux_state = NWAM_AUX_STATE_CONDITIONS_NOT_MET; break; } } /* If state/aux state are uninitialized/unintialized, destroy the ENM */ if (state == NWAM_STATE_UNINITIALIZED && aux_state == NWAM_AUX_STATE_UNINITIALIZED) { object->nwamd_object_state = state; object->nwamd_object_aux_state = aux_state; (void) nwamd_object_release_and_destroy_after_preserve(object); } else { nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM, object->nwamd_object_name, state, aux_state); (void) nwamd_object_release_after_preserve(object); } done: /* object_name was malloc() before this thread was created, free() it */ free(object_name); free(argv); free(copy); nwam_value_free(scriptval); return (NULL); } /* * Run start/stop method for ENM in a separate thread. The object lock is not * held across threads, so we duplicate the object name for the method * execution thread. Returns true if thread is successfully launched. */ boolean_t nwamd_enm_run_method(nwamd_object_t object) { char *name; pthread_t script; /* * Launch separate thread to wait for execution of script * to complete. Do not hold object lock across threads. */ if ((name = strdup(object->nwamd_object_name)) == NULL) { nlog(LOG_ERR, "nwamd_enm_run_method: %s: out of memory", object->nwamd_object_name); return (B_FALSE); } if (pthread_create(&script, NULL, nwamd_enm_activate_deactivate_thread, name) != 0) { nlog(LOG_ERR, "nwamd_enm_run_method: could not create " "enm script thread for %s", name); free(name); return (B_FALSE); } /* "name" will be freed by the newly-created thread. */ /* detach thread so that it doesn't become a zombie */ (void) pthread_detach(script); return (B_TRUE); } /* * Activate the ENM, either in response to an enable event or conditions * being satisfied. */ static void nwamd_enm_activate(const char *object_name) { nwamd_object_t object; nwam_value_t fmrival; char *fmri, *smf_state; int ret; nwam_enm_handle_t enmh; nwam_state_t state; nwam_aux_state_t aux_state; nwam_error_t err; boolean_t ran_method = B_FALSE; object = nwamd_object_find(NWAM_OBJECT_TYPE_ENM, object_name); if (object == NULL) { nlog(LOG_ERR, "nwamd_enm_activate: could not find enm %s", object_name); return; } state = object->nwamd_object_state; aux_state = object->nwamd_object_aux_state; enmh = object->nwamd_object_handle; nlog(LOG_DEBUG, "nwamd_enm_activate: activating enm %s", object->nwamd_object_name); err = nwam_enm_get_prop_value(enmh, NWAM_ENM_PROP_FMRI, &fmrival); switch (err) { case NWAM_SUCCESS: if (nwam_value_get_string(fmrival, &fmri) != NWAM_SUCCESS) { nlog(LOG_ERR, "nwamd_enm_activate: could not retrieve " "fmri string for enm %s", object->nwamd_object_name); nwam_value_free(fmrival); state = NWAM_STATE_MAINTENANCE; aux_state = NWAM_AUX_STATE_INVALID_CONFIG; break; } if ((smf_state = smf_get_state(fmri)) == NULL) { nlog(LOG_ERR, "nwamd_enm_activate: invalid fmri %s " "for enm %s", fmri, object->nwamd_object_name); nwam_value_free(fmrival); state = NWAM_STATE_MAINTENANCE; aux_state = NWAM_AUX_STATE_INVALID_CONFIG; break; } nlog(LOG_DEBUG, "nwamd_enm_activate: activating %s for enm %s", fmri, object->nwamd_object_name); if (strcmp(smf_state, SCF_STATE_STRING_ONLINE) == 0) ret = smf_restart_instance(fmri); else if (strcmp(smf_state, SCF_STATE_STRING_OFFLINE) == 0) ret = smf_restart_instance(fmri); else if (strcmp(smf_state, SCF_STATE_STRING_DISABLED) == 0) ret = smf_enable_instance(fmri, SMF_TEMPORARY); else ret = smf_restore_instance(fmri); if (ret == 0) { state = NWAM_STATE_ONLINE; aux_state = NWAM_AUX_STATE_ACTIVE; } else { nlog(LOG_ERR, "nwamd_enm_activate: failed to enable " "fmri %s for enm %s", fmri, object->nwamd_object_name); state = NWAM_STATE_MAINTENANCE; aux_state = NWAM_AUX_STATE_METHOD_FAILED; } free(smf_state); nwam_value_free(fmrival); break; default: /* * Must be a method-based ENM with start (and stop) script(s). */ if (!nwamd_enm_run_method(object)) { /* Could not launch method execution thread */ state = NWAM_STATE_MAINTENANCE; aux_state = NWAM_AUX_STATE_METHOD_FAILED; } else { ran_method = B_TRUE; } break; } if (state != object->nwamd_object_state || aux_state != object->nwamd_object_aux_state) { nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM, object->nwamd_object_name, state, aux_state); } /* * If the method thread was created, we drop the lock to the ENM * object without decreasing the reference count, ensuring it will not * be destroyed until method execution has completed. */ if (ran_method) { nwamd_object_release_and_preserve(object); } else { nwamd_object_release(object); } } /* Deactivates the ENM. */ static void nwamd_enm_deactivate(const char *object_name) { nwamd_object_t object; nwam_enm_handle_t enmh; nwam_value_t fmrival; char *fmri, *smf_state; int ret; nwam_state_t state; nwam_aux_state_t aux_state; boolean_t destroying = B_FALSE; object = nwamd_object_find(NWAM_OBJECT_TYPE_ENM, object_name); if (object == NULL) { nlog(LOG_ERR, "nwamd_enm_deactivate: could not find enm %s", object_name); return; } state = object->nwamd_object_state; aux_state = object->nwamd_object_aux_state; enmh = object->nwamd_object_handle; state = object->nwamd_object_state; /* If destroying, we don't care about method failure/config err */ destroying = (aux_state == NWAM_AUX_STATE_UNINITIALIZED); nlog(LOG_DEBUG, "nwamd_enm_deactivate: deactivating enm %s", object->nwamd_object_name); if (nwam_enm_get_prop_value(enmh, NWAM_ENM_PROP_FMRI, &fmrival) != NWAM_SUCCESS) { /* * Must be a method-based ENM with start (and stop) script(s). * Script execution thread will take care of the rest. * If the method thread was created, we drop the lock to the ENM * object without decreasing the reference count, ensuring it * will not be destroyed until method execution has completed. */ if (nwamd_enm_run_method(object)) { nwamd_object_release_and_preserve(object); return; } /* Could not launch method execution thread */ if (!destroying) { state = NWAM_STATE_MAINTENANCE; aux_state = NWAM_AUX_STATE_METHOD_FAILED; } } else { if (nwam_value_get_string(fmrival, &fmri) != NWAM_SUCCESS) { nlog(LOG_ERR, "nwamd_enm_deactivate: could not " "retrieve fmri string for enm %s", object->nwamd_object_name); if (!destroying) { state = NWAM_STATE_MAINTENANCE; aux_state = NWAM_AUX_STATE_INVALID_CONFIG; } } else { if ((smf_state = smf_get_state(fmri)) == NULL) { nlog(LOG_ERR, "nwamd_enm_deactivate: invalid " "fmri %s for enm %s", fmri, object->nwamd_object_name); nwam_value_free(fmrival); if (!destroying) { state = NWAM_STATE_MAINTENANCE; aux_state = NWAM_AUX_STATE_INVALID_CONFIG; } goto done; } free(smf_state); nlog(LOG_DEBUG, "nwamd_enm_deactivate: deactivating %s " "for enm %s", fmri, object->nwamd_object_name); ret = smf_disable_instance(fmri, SMF_TEMPORARY); if (ret != 0) { nlog(LOG_ERR, "nwamd_enm_deactivate: " "smf_disable_instance(%s) failed for " "enm %s: %s", fmri, object->nwamd_object_name, scf_strerror(scf_error())); if (!destroying) { state = NWAM_STATE_MAINTENANCE; aux_state = NWAM_AUX_STATE_METHOD_FAILED; } } } nwam_value_free(fmrival); } done: if (state == object->nwamd_object_state && aux_state == object->nwamd_object_aux_state) { /* * If aux state is "manual disable", we know * this was a disable request, otherwise it was * a _fini request or a condition satisfaction * failure. */ switch (object->nwamd_object_aux_state) { case NWAM_AUX_STATE_MANUAL_DISABLE: state = NWAM_STATE_DISABLED; aux_state = NWAM_AUX_STATE_MANUAL_DISABLE; break; case NWAM_AUX_STATE_UNINITIALIZED: state = NWAM_STATE_UNINITIALIZED; aux_state = NWAM_AUX_STATE_UNINITIALIZED; break; default: state = NWAM_STATE_OFFLINE; aux_state = NWAM_AUX_STATE_CONDITIONS_NOT_MET; break; } } /* Only change state if we aren't destroying the ENM */ if (!destroying && (state != object->nwamd_object_state || aux_state != object->nwamd_object_aux_state)) { nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM, object->nwamd_object_name, state, aux_state); } /* If state/aux state are uninitialized/unintialized, destroy the ENM */ if (state == NWAM_STATE_UNINITIALIZED && aux_state == NWAM_AUX_STATE_UNINITIALIZED) { (void) nwamd_object_release_and_destroy(object); } else { (void) nwamd_object_release(object); } } /* * Determine whether an ENM should be (de)activated. */ /* ARGSUSED1 */ static int nwamd_enm_check(nwamd_object_t object, void *data) { nwam_enm_handle_t enmh; nwam_value_t conditionval; int64_t eactivation; boolean_t enabled, satisfied; char **conditions; nwam_state_t state; uint_t nelem; state = object->nwamd_object_state; enmh = object->nwamd_object_handle; eactivation = enm_get_activation_mode(enmh); if (eactivation == -1) return (0); switch (eactivation) { case NWAM_ACTIVATION_MODE_MANUAL: enabled = enm_is_enabled(enmh); if (enabled) { nlog(LOG_DEBUG, "nwamd_enm_check: %s is enabled", object->nwamd_object_name); switch (state) { case NWAM_STATE_ONLINE: case NWAM_STATE_MAINTENANCE: /* Do nothing */ break; default: if (nwamd_enm_action(object->nwamd_object_name, NWAM_ACTION_ENABLE) != 0) { nlog(LOG_ERR, "nwamd_enm_check: " "enable failed for enm %s", object->nwamd_object_name); } break; } } else { nlog(LOG_DEBUG, "nwamd_enm_check: %s is disabled", object->nwamd_object_name); switch (state) { case NWAM_STATE_ONLINE: if (nwamd_enm_action(object->nwamd_object_name, NWAM_ACTION_DISABLE) != 0) { nlog(LOG_ERR, "nwamd_enm_check: " "disable failed for enm %s", object->nwamd_object_name); } break; case NWAM_STATE_MAINTENANCE: /* Do nothing */ break; case NWAM_STATE_DISABLED: /* Do nothing */ break; default: nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM, object->nwamd_object_name, NWAM_STATE_DISABLED, NWAM_AUX_STATE_MANUAL_DISABLE); break; } } break; case NWAM_ACTIVATION_MODE_CONDITIONAL_ANY: case NWAM_ACTIVATION_MODE_CONDITIONAL_ALL: if (nwam_enm_get_prop_value(enmh, NWAM_ENM_PROP_CONDITIONS, &conditionval) != NWAM_SUCCESS) { nlog(LOG_ERR, "nwamd_enm_check: could not retrieve " "condition value"); break; } if (nwam_value_get_string_array(conditionval, &conditions, &nelem) != NWAM_SUCCESS) { nlog(LOG_ERR, "nwamd_enm_check: could not retrieve " "condition value"); nwam_value_free(conditionval); break; } satisfied = nwamd_check_conditions((uint64_t)eactivation, conditions, nelem); nlog(LOG_DEBUG, "nwamd_enm_check: conditions for enm %s " "%s satisfied", object->nwamd_object_name, satisfied ? "is" : "is not"); if (state != NWAM_STATE_ONLINE && satisfied) { nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM, object->nwamd_object_name, NWAM_STATE_OFFLINE_TO_ONLINE, NWAM_AUX_STATE_METHOD_RUNNING); } if (state == NWAM_STATE_ONLINE && !satisfied) { nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM, object->nwamd_object_name, NWAM_STATE_ONLINE_TO_OFFLINE, NWAM_AUX_STATE_CONDITIONS_NOT_MET); } nwam_value_free(conditionval); break; } return (0); } void nwamd_enm_check_conditions(void) { (void) nwamd_walk_objects(NWAM_OBJECT_TYPE_ENM, nwamd_enm_check, NULL); } int nwamd_enm_action(const char *enm, nwam_action_t action) { nwamd_event_t event = nwamd_event_init_object_action (NWAM_OBJECT_TYPE_ENM, enm, NULL, action); if (event == NULL) return (1); nwamd_event_enqueue(event); return (0); } /* * Event handling functions. */ /* Handle ENM initialization/refresh event */ void nwamd_enm_handle_init_event(nwamd_event_t event) { nwamd_object_t object; nwam_enm_handle_t enmh; nwam_error_t err; boolean_t manual_disabled = B_FALSE; if ((err = nwam_enm_read(event->event_object, 0, &enmh)) != NWAM_SUCCESS) { nlog(LOG_ERR, "nwamd_enm_handle_init_event: could not " "read object '%s': %s", event->event_object, nwam_strerror(err)); nwamd_event_do_not_send(event); return; } if ((object = nwamd_object_find(NWAM_OBJECT_TYPE_ENM, event->event_object)) != NULL) { nwam_enm_free(object->nwamd_object_handle); object->nwamd_object_handle = enmh; } else { object = nwamd_object_init(NWAM_OBJECT_TYPE_ENM, event->event_object, enmh, NULL); object->nwamd_object_state = NWAM_STATE_OFFLINE; object->nwamd_object_aux_state = NWAM_AUX_STATE_CONDITIONS_NOT_MET; } /* (Re)set script time to now as the object has just been (re)read */ (void) gettimeofday(&object->nwamd_script_time, NULL); manual_disabled = (enm_get_activation_mode(enmh) == NWAM_ACTIVATION_MODE_MANUAL && !enm_is_enabled(enmh)); /* * If this ENM is ONLINE, and not manual and disabled (since in * that case it was online but we've just set enabled = false as part * of a disable action), then it is still active but refreshing. * Change states to re-activate itself. */ if (!manual_disabled && object->nwamd_object_state == NWAM_STATE_ONLINE) { nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM, event->event_object, NWAM_STATE_OFFLINE_TO_ONLINE, NWAM_AUX_STATE_METHOD_RUNNING); } nwamd_object_release(object); } /* Handle ENM finish event */ void nwamd_enm_handle_fini_event(nwamd_event_t event) { nwamd_event_t state_event; nlog(LOG_DEBUG, "nwamd_enm_handle_fini_event(%s)", event->event_object); /* * Simulate a state event so that the state machine can correctly * deactivate the ENM and free up the handle. */ state_event = nwamd_event_init_object_state(NWAM_OBJECT_TYPE_ENM, event->event_object, NWAM_STATE_ONLINE_TO_OFFLINE, NWAM_AUX_STATE_UNINITIALIZED); if (state_event == NULL) { nwamd_event_do_not_send(event); return; } nwamd_enm_handle_state_event(state_event); nwamd_event_fini(state_event); /* * Do not free the handle and object. * nwamd_enm_activate_deactivate_thread() and * nwamd_enm_deactivate() does this after running the stop script * and disabling the FMRI respectively. */ } void nwamd_enm_handle_action_event(nwamd_event_t event) { nwamd_object_t object; switch (event->event_msg->nwe_data.nwe_object_action.nwe_action) { case NWAM_ACTION_ENABLE: object = nwamd_object_find(NWAM_OBJECT_TYPE_ENM, event->event_object); if (object == NULL) { nlog(LOG_ERR, "nwamd_enm_handle_action_event: " "could not find enm %s", event->event_object); nwamd_event_do_not_send(event); return; } if (object->nwamd_object_state == NWAM_STATE_ONLINE) { nlog(LOG_DEBUG, "nwamd_enm_handle_action_event: " "enm %s already online, nothing to do", event->event_object); nwamd_object_release(object); return; } nwamd_object_release(object); nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM, event->event_object, NWAM_STATE_OFFLINE_TO_ONLINE, NWAM_AUX_STATE_METHOD_RUNNING); break; case NWAM_ACTION_DISABLE: object = nwamd_object_find(NWAM_OBJECT_TYPE_ENM, event->event_object); if (object == NULL) { nlog(LOG_ERR, "nwamd_enm_handle_action_event: " "could not find enm %s", event->event_object); nwamd_event_do_not_send(event); return; } if (object->nwamd_object_state == NWAM_STATE_DISABLED) { nlog(LOG_DEBUG, "nwamd_enm_handle_action_event: " "enm %s already disabled, nothing to do", event->event_object); nwamd_object_release(object); return; } nwamd_object_release(object); nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM, event->event_object, NWAM_STATE_ONLINE_TO_OFFLINE, NWAM_AUX_STATE_MANUAL_DISABLE); break; case NWAM_ACTION_ADD: case NWAM_ACTION_REFRESH: nwamd_enm_handle_init_event(event); break; case NWAM_ACTION_DESTROY: nwamd_enm_handle_fini_event(event); break; default: nlog(LOG_INFO, "nwam_enm_handle_action_event: " "unexpected action"); nwamd_event_do_not_send(event); break; } } void nwamd_enm_handle_state_event(nwamd_event_t event) { nwamd_object_t object; nwam_state_t new_state; nwam_aux_state_t new_aux_state; if ((object = nwamd_object_find(NWAM_OBJECT_TYPE_ENM, event->event_object)) == NULL) { nlog(LOG_INFO, "nwamd_enm_handle_state_event: " "state event for nonexistent enm %s", event->event_object); nwamd_event_do_not_send(event); return; } new_state = event->event_msg->nwe_data.nwe_object_state.nwe_state; new_aux_state = event->event_msg->nwe_data.nwe_object_state.nwe_aux_state; if (new_state == object->nwamd_object_state && new_aux_state == object->nwamd_object_aux_state) { nlog(LOG_DEBUG, "nwamd_enm_handle_state_event: " "enm %s already in state (%s , %s)", object->nwamd_object_name, nwam_state_to_string(new_state), nwam_aux_state_to_string(new_aux_state)); nwamd_object_release(object); return; } object->nwamd_object_state = new_state; object->nwamd_object_aux_state = new_aux_state; nlog(LOG_DEBUG, "nwamd_enm_handle_state_event: changing state for enm " "%s to (%s , %s)", object->nwamd_object_name, nwam_state_to_string(object->nwamd_object_state), nwam_aux_state_to_string(object->nwamd_object_aux_state)); nwamd_object_release(object); /* * State machine for ENMs. */ switch (new_state) { case NWAM_STATE_OFFLINE_TO_ONLINE: nwamd_enm_activate(event->event_object); break; case NWAM_STATE_ONLINE_TO_OFFLINE: nwamd_enm_deactivate(event->event_object); break; case NWAM_STATE_DISABLED: case NWAM_STATE_OFFLINE: case NWAM_STATE_UNINITIALIZED: case NWAM_STATE_MAINTENANCE: case NWAM_STATE_DEGRADED: default: /* do nothing */ break; } }