xref: /illumos-gate/usr/src/cmd/cmd-inet/lib/nwamd/enm.c (revision 6a634c9d)
16ba597c5SAnurag S. Maskey /*
26ba597c5SAnurag S. Maskey  * CDDL HEADER START
36ba597c5SAnurag S. Maskey  *
46ba597c5SAnurag S. Maskey  * The contents of this file are subject to the terms of the
56ba597c5SAnurag S. Maskey  * Common Development and Distribution License (the "License").
66ba597c5SAnurag S. Maskey  * You may not use this file except in compliance with the License.
76ba597c5SAnurag S. Maskey  *
86ba597c5SAnurag S. Maskey  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96ba597c5SAnurag S. Maskey  * or http://www.opensolaris.org/os/licensing.
106ba597c5SAnurag S. Maskey  * See the License for the specific language governing permissions
116ba597c5SAnurag S. Maskey  * and limitations under the License.
126ba597c5SAnurag S. Maskey  *
136ba597c5SAnurag S. Maskey  * When distributing Covered Code, include this CDDL HEADER in each
146ba597c5SAnurag S. Maskey  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156ba597c5SAnurag S. Maskey  * If applicable, add the following below this CDDL HEADER, with the
166ba597c5SAnurag S. Maskey  * fields enclosed by brackets "[]" replaced with your own identifying
176ba597c5SAnurag S. Maskey  * information: Portions Copyright [yyyy] [name of copyright owner]
186ba597c5SAnurag S. Maskey  *
196ba597c5SAnurag S. Maskey  * CDDL HEADER END
206ba597c5SAnurag S. Maskey  */
216ba597c5SAnurag S. Maskey 
226ba597c5SAnurag S. Maskey /*
23f6da83d4SAnurag S. Maskey  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
246ba597c5SAnurag S. Maskey  */
256ba597c5SAnurag S. Maskey 
266ba597c5SAnurag S. Maskey #include <arpa/inet.h>
276ba597c5SAnurag S. Maskey #include <errno.h>
286ba597c5SAnurag S. Maskey #include <inet/ip.h>
296ba597c5SAnurag S. Maskey #include <libdladm.h>
306ba597c5SAnurag S. Maskey #include <libdllink.h>
316ba597c5SAnurag S. Maskey #include <libdlwlan.h>
326ba597c5SAnurag S. Maskey #include <libscf.h>
336ba597c5SAnurag S. Maskey #include <netinet/in.h>
346ba597c5SAnurag S. Maskey #include <netdb.h>
356ba597c5SAnurag S. Maskey #include <stdio.h>
366ba597c5SAnurag S. Maskey #include <stdlib.h>
376ba597c5SAnurag S. Maskey #include <string.h>
386ba597c5SAnurag S. Maskey #include <sys/socket.h>
396ba597c5SAnurag S. Maskey #include <sys/types.h>
406ba597c5SAnurag S. Maskey 
416ba597c5SAnurag S. Maskey #include <libnwam.h>
426ba597c5SAnurag S. Maskey #include "conditions.h"
436ba597c5SAnurag S. Maskey #include "events.h"
446ba597c5SAnurag S. Maskey #include "objects.h"
456ba597c5SAnurag S. Maskey #include "util.h"
466ba597c5SAnurag S. Maskey 
476ba597c5SAnurag S. Maskey /*
486ba597c5SAnurag S. Maskey  * enm.c - contains routines which handle ENM (external network modifier)
496ba597c5SAnurag S. Maskey  * abstraction.  ENMs represent scripts or services that can be activated either
506ba597c5SAnurag S. Maskey  * manually or in response to network conditions.
516ba597c5SAnurag S. Maskey  */
526ba597c5SAnurag S. Maskey 
536ba597c5SAnurag S. Maskey #define	CTRUN	"/usr/bin/ctrun"
546ba597c5SAnurag S. Maskey 
556ba597c5SAnurag S. Maskey static int
enm_create_init_fini_event(nwam_enm_handle_t enmh,void * data)566ba597c5SAnurag S. Maskey enm_create_init_fini_event(nwam_enm_handle_t enmh, void *data)
576ba597c5SAnurag S. Maskey {
586ba597c5SAnurag S. Maskey 	boolean_t *init = data;
596ba597c5SAnurag S. Maskey 	char *name;
606ba597c5SAnurag S. Maskey 	nwamd_event_t enm_event;
616ba597c5SAnurag S. Maskey 
626ba597c5SAnurag S. Maskey 	if (nwam_enm_get_name(enmh, &name) != NWAM_SUCCESS) {
63*f6904bc3SRenee Danson Sommerfeld 		nlog(LOG_ERR, "enm_init_fini: could not get enm name");
646ba597c5SAnurag S. Maskey 		return (0);
656ba597c5SAnurag S. Maskey 	}
666ba597c5SAnurag S. Maskey 
676ba597c5SAnurag S. Maskey 	enm_event = nwamd_event_init(*init ?
686ba597c5SAnurag S. Maskey 	    NWAM_EVENT_TYPE_OBJECT_INIT : NWAM_EVENT_TYPE_OBJECT_FINI,
696ba597c5SAnurag S. Maskey 	    NWAM_OBJECT_TYPE_ENM, 0, name);
706ba597c5SAnurag S. Maskey 	if (enm_event != NULL)
716ba597c5SAnurag S. Maskey 		nwamd_event_enqueue(enm_event);
726ba597c5SAnurag S. Maskey 	free(name);
736ba597c5SAnurag S. Maskey 
746ba597c5SAnurag S. Maskey 	return (0);
756ba597c5SAnurag S. Maskey }
766ba597c5SAnurag S. Maskey 
776ba597c5SAnurag S. Maskey /*
786ba597c5SAnurag S. Maskey  * Walk all ENMs, creating init events for each.
796ba597c5SAnurag S. Maskey  */
806ba597c5SAnurag S. Maskey void
nwamd_init_enms(void)816ba597c5SAnurag S. Maskey nwamd_init_enms(void)
826ba597c5SAnurag S. Maskey {
836ba597c5SAnurag S. Maskey 	boolean_t init = B_TRUE;
846ba597c5SAnurag S. Maskey 
856ba597c5SAnurag S. Maskey 	(void) nwam_walk_enms(enm_create_init_fini_event, &init, 0, NULL);
866ba597c5SAnurag S. Maskey }
876ba597c5SAnurag S. Maskey 
886ba597c5SAnurag S. Maskey /*
896ba597c5SAnurag S. Maskey  * Walk all ENMs, creating fini events for each.
906ba597c5SAnurag S. Maskey  */
916ba597c5SAnurag S. Maskey void
nwamd_fini_enms(void)926ba597c5SAnurag S. Maskey nwamd_fini_enms(void)
936ba597c5SAnurag S. Maskey {
946ba597c5SAnurag S. Maskey 	boolean_t init = B_FALSE;
956ba597c5SAnurag S. Maskey 
966ba597c5SAnurag S. Maskey 	(void) nwam_walk_enms(enm_create_init_fini_event, &init, 0, NULL);
976ba597c5SAnurag S. Maskey }
986ba597c5SAnurag S. Maskey 
996ba597c5SAnurag S. Maskey static boolean_t
enm_is_enabled(nwam_enm_handle_t enmh)1006ba597c5SAnurag S. Maskey enm_is_enabled(nwam_enm_handle_t enmh)
1016ba597c5SAnurag S. Maskey {
1026ba597c5SAnurag S. Maskey 	nwam_value_t enabledval;
1036ba597c5SAnurag S. Maskey 	boolean_t enabled = B_FALSE;
1046ba597c5SAnurag S. Maskey 
1056ba597c5SAnurag S. Maskey 	if (nwam_enm_get_prop_value(enmh, NWAM_ENM_PROP_ENABLED,
1066ba597c5SAnurag S. Maskey 	    &enabledval) != NWAM_SUCCESS) {
1076ba597c5SAnurag S. Maskey 		/* It's legal for a conditional ENM to not specify "enabled" */
1086ba597c5SAnurag S. Maskey 		return (B_FALSE);
1096ba597c5SAnurag S. Maskey 	}
1106ba597c5SAnurag S. Maskey 	if (nwam_value_get_boolean(enabledval, &enabled) != NWAM_SUCCESS) {
1116ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "enm_is_enabled: could not retrieve "
1126ba597c5SAnurag S. Maskey 		    "enabled value");
1136ba597c5SAnurag S. Maskey 	}
1146ba597c5SAnurag S. Maskey 	nwam_value_free(enabledval);
1156ba597c5SAnurag S. Maskey 	return (enabled);
1166ba597c5SAnurag S. Maskey }
1176ba597c5SAnurag S. Maskey 
1186ba597c5SAnurag S. Maskey static int64_t
enm_get_activation_mode(nwam_enm_handle_t enmh)1196ba597c5SAnurag S. Maskey enm_get_activation_mode(nwam_enm_handle_t enmh)
1206ba597c5SAnurag S. Maskey {
1216ba597c5SAnurag S. Maskey 	uint64_t activation;
1226ba597c5SAnurag S. Maskey 	int64_t ret;
1236ba597c5SAnurag S. Maskey 	nwam_value_t activationval;
1246ba597c5SAnurag S. Maskey 
1256ba597c5SAnurag S. Maskey 	if (nwam_enm_get_prop_value(enmh, NWAM_ENM_PROP_ACTIVATION_MODE,
1266ba597c5SAnurag S. Maskey 	    &activationval)  != NWAM_SUCCESS) {
1276ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "enm_get_activation_mode: could not retrieve "
1286ba597c5SAnurag S. Maskey 		    "activation mode value");
1296ba597c5SAnurag S. Maskey 		return (-1);
1306ba597c5SAnurag S. Maskey 	}
1316ba597c5SAnurag S. Maskey 	if (nwam_value_get_uint64(activationval, &activation) != NWAM_SUCCESS) {
1326ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "enm_get_activation_mode: could not retrieve "
1336ba597c5SAnurag S. Maskey 		    "activation mode value");
1346ba597c5SAnurag S. Maskey 		ret = -1;
1356ba597c5SAnurag S. Maskey 	} else {
1366ba597c5SAnurag S. Maskey 		ret = activation;
1376ba597c5SAnurag S. Maskey 	}
1386ba597c5SAnurag S. Maskey 	nwam_value_free(activationval);
1396ba597c5SAnurag S. Maskey 
1406ba597c5SAnurag S. Maskey 	return (ret);
1416ba597c5SAnurag S. Maskey }
1426ba597c5SAnurag S. Maskey 
1436ba597c5SAnurag S. Maskey static void *
nwamd_enm_activate_deactivate_thread(void * arg)1446ba597c5SAnurag S. Maskey nwamd_enm_activate_deactivate_thread(void *arg)
1456ba597c5SAnurag S. Maskey {
1466ba597c5SAnurag S. Maskey 	char *object_name = arg;
1476ba597c5SAnurag S. Maskey 	nwamd_object_t object;
1486ba597c5SAnurag S. Maskey 	nwam_enm_handle_t enmh;
1496ba597c5SAnurag S. Maskey 	nwam_value_t scriptval = NULL;
1506ba597c5SAnurag S. Maskey 	nwam_state_t state;
1516ba597c5SAnurag S. Maskey 	nwam_aux_state_t aux_state;
152874067a0SAnurag S. Maskey 	char *script, *copy = NULL;
153874067a0SAnurag S. Maskey 	const char **argv = NULL;
1546ba597c5SAnurag S. Maskey 	boolean_t going_online, disable_succeeded = B_FALSE;
1556ba597c5SAnurag S. Maskey 	int ret;
1566ba597c5SAnurag S. Maskey 
1576ba597c5SAnurag S. Maskey 	object = nwamd_object_find(NWAM_OBJECT_TYPE_ENM, object_name);
1586ba597c5SAnurag S. Maskey 	if (object == NULL) {
1596ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_enm_activate_deactivate_thread: "
160*f6904bc3SRenee Danson Sommerfeld 		    "could not find enm %s", object_name);
161874067a0SAnurag S. Maskey 		goto done;
1626ba597c5SAnurag S. Maskey 	}
1636ba597c5SAnurag S. Maskey 	enmh = object->nwamd_object_handle;
1646ba597c5SAnurag S. Maskey 
1656ba597c5SAnurag S. Maskey 	going_online =
1666ba597c5SAnurag S. Maskey 	    (object->nwamd_object_state == NWAM_STATE_OFFLINE_TO_ONLINE);
1676ba597c5SAnurag S. Maskey 	/*
1686ba597c5SAnurag S. Maskey 	 * We're starting if current state is offline* and stopping otherwise.
1696ba597c5SAnurag S. Maskey 	 */
1706ba597c5SAnurag S. Maskey 	if (nwam_enm_get_prop_value(enmh,
1716ba597c5SAnurag S. Maskey 	    going_online ? NWAM_ENM_PROP_START : NWAM_ENM_PROP_STOP,
1726ba597c5SAnurag S. Maskey 	    &scriptval) != NWAM_SUCCESS ||
1736ba597c5SAnurag S. Maskey 	    nwam_value_get_string(scriptval, &script) != NWAM_SUCCESS) {
1746ba597c5SAnurag S. Maskey 		/*
1756ba597c5SAnurag S. Maskey 		 * If we're stopping, it's not an error for no script to
1766ba597c5SAnurag S. Maskey 		 * be specified.
1776ba597c5SAnurag S. Maskey 		 */
1786ba597c5SAnurag S. Maskey 		nlog(going_online ? LOG_ERR : LOG_DEBUG,
1796ba597c5SAnurag S. Maskey 		    "nwamd_enm_activate_deactivate_thread: "
180874067a0SAnurag S. Maskey 		    "no script specified for enm %s", object_name);
1816ba597c5SAnurag S. Maskey 		if (going_online) {
1826ba597c5SAnurag S. Maskey 			state = NWAM_STATE_MAINTENANCE;
1836ba597c5SAnurag S. Maskey 			aux_state = NWAM_AUX_STATE_METHOD_MISSING;
1846ba597c5SAnurag S. Maskey 		} else {
1856ba597c5SAnurag S. Maskey 			disable_succeeded = B_TRUE;
1866ba597c5SAnurag S. Maskey 		}
1876ba597c5SAnurag S. Maskey 	} else {
188874067a0SAnurag S. Maskey 		char *lasts;
189874067a0SAnurag S. Maskey 		const char **newargv;
1906ba597c5SAnurag S. Maskey 		int i = 0;
191874067a0SAnurag S. Maskey 		struct timeval now;
1926ba597c5SAnurag S. Maskey 
1936ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "nwamd_enm_activate_deactivate_thread: "
194*f6904bc3SRenee Danson Sommerfeld 		    "running script %s for enm %s", script, object_name);
1956ba597c5SAnurag S. Maskey 
1966ba597c5SAnurag S. Maskey 		/*
1976ba597c5SAnurag S. Maskey 		 * The script may take a number of arguments. We need to
1986ba597c5SAnurag S. Maskey 		 * create a string array consisting of the wrapper command
1996ba597c5SAnurag S. Maskey 		 * (ctrun), ENM script name, arguments and NULL array
2006ba597c5SAnurag S. Maskey 		 * terminator.  Start with an array of size equal to the
2016ba597c5SAnurag S. Maskey 		 * string length (since the number of arguments will always
2026ba597c5SAnurag S. Maskey 		 * be less than this) and shrink array to the actual number
2036ba597c5SAnurag S. Maskey 		 * of arguments when we have parsed the string.
2046ba597c5SAnurag S. Maskey 		 */
2056ba597c5SAnurag S. Maskey 		if ((copy = strdup(script)) == NULL ||
2066ba597c5SAnurag S. Maskey 		    (argv = calloc(strlen(script), sizeof (char *))) == NULL) {
2076ba597c5SAnurag S. Maskey 			ret = 1;
2086ba597c5SAnurag S. Maskey 			goto err;
2096ba597c5SAnurag S. Maskey 		}
2106ba597c5SAnurag S. Maskey 		argv[i++] = CTRUN;
2116ba597c5SAnurag S. Maskey 		argv[i++] = strtok_r(copy, " ", &lasts);
2126ba597c5SAnurag S. Maskey 		if (argv[1] == NULL) {
2136ba597c5SAnurag S. Maskey 			ret = 1;
2146ba597c5SAnurag S. Maskey 			goto err;
2156ba597c5SAnurag S. Maskey 		}
2166ba597c5SAnurag S. Maskey 
2176ba597c5SAnurag S. Maskey 		for (; (argv[i] = strtok_r(NULL, " ", &lasts)) != NULL; i++) {}
2186ba597c5SAnurag S. Maskey 
2196ba597c5SAnurag S. Maskey 		newargv = realloc(argv, (i + 1) * sizeof (char *));
2206ba597c5SAnurag S. Maskey 		argv = newargv;
2216ba597c5SAnurag S. Maskey 
222874067a0SAnurag S. Maskey 		/* Store the current time as the time the script began */
223874067a0SAnurag S. Maskey 		(void) gettimeofday(&now, NULL);
224874067a0SAnurag S. Maskey 		object->nwamd_script_time = now;
225874067a0SAnurag S. Maskey 
226874067a0SAnurag S. Maskey 		/*
227874067a0SAnurag S. Maskey 		 * Release the object so that it is not blocked while the
228874067a0SAnurag S. Maskey 		 * script is running.
229874067a0SAnurag S. Maskey 		 */
230874067a0SAnurag S. Maskey 		nwamd_object_release(object);
231874067a0SAnurag S. Maskey 
2326ba597c5SAnurag S. Maskey 		ret = nwamd_start_childv(CTRUN, argv);
2336ba597c5SAnurag S. Maskey 
234874067a0SAnurag S. Maskey 		/*
235874067a0SAnurag S. Maskey 		 * Find the object again, now that the script has finished
236874067a0SAnurag S. Maskey 		 * running.  Check if this ENM was re-read during that time by
237874067a0SAnurag S. Maskey 		 * comparing the object's script time with the one from above.
238874067a0SAnurag S. Maskey 		 */
239874067a0SAnurag S. Maskey 		object = nwamd_object_find(NWAM_OBJECT_TYPE_ENM, object_name);
240874067a0SAnurag S. Maskey 		if (object == NULL) {
241874067a0SAnurag S. Maskey 			nlog(LOG_ERR, "nwamd_enm_activate_deactivate_thread: "
242*f6904bc3SRenee Danson Sommerfeld 			    "could not find enm %s after running script",
243874067a0SAnurag S. Maskey 			    object_name);
244874067a0SAnurag S. Maskey 			goto done;
245874067a0SAnurag S. Maskey 		}
246874067a0SAnurag S. Maskey 
247874067a0SAnurag S. Maskey 		if (object->nwamd_script_time.tv_sec != now.tv_sec ||
248874067a0SAnurag S. Maskey 		    object->nwamd_script_time.tv_usec != now.tv_usec) {
249874067a0SAnurag S. Maskey 			nlog(LOG_INFO, "nwamd_enm_activate_deactivate_thread: "
250*f6904bc3SRenee Danson Sommerfeld 			    "enm %s has been refreshed, nothing to do",
251874067a0SAnurag S. Maskey 			    object_name);
252874067a0SAnurag S. Maskey 			nwamd_object_release(object);
253874067a0SAnurag S. Maskey 			goto done;
254874067a0SAnurag S. Maskey 		}
255874067a0SAnurag S. Maskey 		(void) gettimeofday(&object->nwamd_script_time, NULL);
256874067a0SAnurag S. Maskey 
2576ba597c5SAnurag S. Maskey err:
2586ba597c5SAnurag S. Maskey 		/*
2596ba597c5SAnurag S. Maskey 		 * If script execution fails and we're not destroying the
2606ba597c5SAnurag S. Maskey 		 * object, go to maintenance.
2616ba597c5SAnurag S. Maskey 		 */
2626ba597c5SAnurag S. Maskey 		if (ret != 0) {
2636ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "nwamd_enm_activate_deactivate_thread: "
264*f6904bc3SRenee Danson Sommerfeld 			    "execution of '%s' failed for enm %s",
265874067a0SAnurag S. Maskey 			    script, object_name);
2666ba597c5SAnurag S. Maskey 			if (object->nwamd_object_aux_state !=
2676ba597c5SAnurag S. Maskey 			    NWAM_AUX_STATE_UNINITIALIZED) {
2686ba597c5SAnurag S. Maskey 				state = NWAM_STATE_MAINTENANCE;
2696ba597c5SAnurag S. Maskey 				aux_state = NWAM_AUX_STATE_METHOD_FAILED;
2706ba597c5SAnurag S. Maskey 			} else {
2716ba597c5SAnurag S. Maskey 				state = NWAM_STATE_UNINITIALIZED;
2726ba597c5SAnurag S. Maskey 				aux_state = NWAM_AUX_STATE_UNINITIALIZED;
2736ba597c5SAnurag S. Maskey 			}
2746ba597c5SAnurag S. Maskey 		} else {
2756ba597c5SAnurag S. Maskey 			if (going_online) {
2766ba597c5SAnurag S. Maskey 				state = NWAM_STATE_ONLINE;
2776ba597c5SAnurag S. Maskey 				aux_state = NWAM_AUX_STATE_ACTIVE;
2786ba597c5SAnurag S. Maskey 			} else {
2796ba597c5SAnurag S. Maskey 				disable_succeeded = B_TRUE;
2806ba597c5SAnurag S. Maskey 			}
2816ba597c5SAnurag S. Maskey 		}
2826ba597c5SAnurag S. Maskey 	}
2836ba597c5SAnurag S. Maskey 
2846ba597c5SAnurag S. Maskey 	if (disable_succeeded) {
2856ba597c5SAnurag S. Maskey 		/*
2866ba597c5SAnurag S. Maskey 		 * If aux state is "manual disable", we know
2876ba597c5SAnurag S. Maskey 		 * this was a disable request, otherwise it was
2886ba597c5SAnurag S. Maskey 		 * _fini request or a condition satisfaction
2896ba597c5SAnurag S. Maskey 		 * failure.
2906ba597c5SAnurag S. Maskey 		 */
2916ba597c5SAnurag S. Maskey 		switch (object->nwamd_object_aux_state) {
2926ba597c5SAnurag S. Maskey 		case NWAM_AUX_STATE_MANUAL_DISABLE:
2936ba597c5SAnurag S. Maskey 			state = NWAM_STATE_DISABLED;
2946ba597c5SAnurag S. Maskey 			aux_state = NWAM_AUX_STATE_MANUAL_DISABLE;
2956ba597c5SAnurag S. Maskey 			break;
2966ba597c5SAnurag S. Maskey 		case NWAM_AUX_STATE_UNINITIALIZED:
2976ba597c5SAnurag S. Maskey 			state = NWAM_STATE_UNINITIALIZED;
2986ba597c5SAnurag S. Maskey 			aux_state = NWAM_AUX_STATE_UNINITIALIZED;
2996ba597c5SAnurag S. Maskey 			break;
3006ba597c5SAnurag S. Maskey 		default:
3016ba597c5SAnurag S. Maskey 			state = NWAM_STATE_OFFLINE;
3026ba597c5SAnurag S. Maskey 			aux_state = NWAM_AUX_STATE_CONDITIONS_NOT_MET;
3036ba597c5SAnurag S. Maskey 			break;
3046ba597c5SAnurag S. Maskey 		}
3056ba597c5SAnurag S. Maskey 	}
3066ba597c5SAnurag S. Maskey 
3076ba597c5SAnurag S. Maskey 	/* If state/aux state are uninitialized/unintialized, destroy the ENM */
3086ba597c5SAnurag S. Maskey 	if (state == NWAM_STATE_UNINITIALIZED &&
3096ba597c5SAnurag S. Maskey 	    aux_state == NWAM_AUX_STATE_UNINITIALIZED) {
3106ba597c5SAnurag S. Maskey 		object->nwamd_object_state = state;
3116ba597c5SAnurag S. Maskey 		object->nwamd_object_aux_state = aux_state;
3126ba597c5SAnurag S. Maskey 		(void) nwamd_object_release_and_destroy_after_preserve(object);
3136ba597c5SAnurag S. Maskey 	} else {
3146ba597c5SAnurag S. Maskey 		nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM,
3156ba597c5SAnurag S. Maskey 		    object->nwamd_object_name, state, aux_state);
3166ba597c5SAnurag S. Maskey 		(void) nwamd_object_release_after_preserve(object);
3176ba597c5SAnurag S. Maskey 	}
3186ba597c5SAnurag S. Maskey 
319874067a0SAnurag S. Maskey done:
320874067a0SAnurag S. Maskey 	/* object_name was malloc() before this thread was created, free() it */
321874067a0SAnurag S. Maskey 	free(object_name);
322874067a0SAnurag S. Maskey 	free(argv);
323874067a0SAnurag S. Maskey 	free(copy);
324874067a0SAnurag S. Maskey 	nwam_value_free(scriptval);
3256ba597c5SAnurag S. Maskey 	return (NULL);
3266ba597c5SAnurag S. Maskey }
3276ba597c5SAnurag S. Maskey 
3286ba597c5SAnurag S. Maskey /*
3296ba597c5SAnurag S. Maskey  * Run start/stop method for ENM in a separate thread.  The object lock is not
3306ba597c5SAnurag S. Maskey  * held across threads, so we duplicate the object name for the method
3316ba597c5SAnurag S. Maskey  * execution thread.  Returns true if thread is successfully launched.
3326ba597c5SAnurag S. Maskey  */
3336ba597c5SAnurag S. Maskey boolean_t
nwamd_enm_run_method(nwamd_object_t object)3346ba597c5SAnurag S. Maskey nwamd_enm_run_method(nwamd_object_t object)
3356ba597c5SAnurag S. Maskey {
3366ba597c5SAnurag S. Maskey 	char *name;
3376ba597c5SAnurag S. Maskey 	pthread_t script;
3386ba597c5SAnurag S. Maskey 
3396ba597c5SAnurag S. Maskey 	/*
3406ba597c5SAnurag S. Maskey 	 * Launch separate thread to wait for execution of script
3416ba597c5SAnurag S. Maskey 	 * to complete.  Do not hold object lock across threads.
3426ba597c5SAnurag S. Maskey 	 */
3436ba597c5SAnurag S. Maskey 	if ((name = strdup(object->nwamd_object_name)) == NULL) {
3446ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_enm_run_method: %s: out of memory",
3456ba597c5SAnurag S. Maskey 		    object->nwamd_object_name);
3466ba597c5SAnurag S. Maskey 		return (B_FALSE);
3476ba597c5SAnurag S. Maskey 	}
3486ba597c5SAnurag S. Maskey 
3496ba597c5SAnurag S. Maskey 	if (pthread_create(&script, NULL,
3506ba597c5SAnurag S. Maskey 	    nwamd_enm_activate_deactivate_thread, name) != 0) {
3516ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_enm_run_method: could not create "
3526ba597c5SAnurag S. Maskey 		    "enm script thread for %s", name);
3536ba597c5SAnurag S. Maskey 		free(name);
3546ba597c5SAnurag S. Maskey 		return (B_FALSE);
3556ba597c5SAnurag S. Maskey 	}
3566ba597c5SAnurag S. Maskey 	/* "name" will be freed by the newly-created thread. */
3576ba597c5SAnurag S. Maskey 
3586ba597c5SAnurag S. Maskey 	/* detach thread so that it doesn't become a zombie */
3596ba597c5SAnurag S. Maskey 	(void) pthread_detach(script);
3606ba597c5SAnurag S. Maskey 
3616ba597c5SAnurag S. Maskey 	return (B_TRUE);
362