14eaa4710SRishi Srivatsavai /*
24eaa4710SRishi Srivatsavai  * CDDL HEADER START
34eaa4710SRishi Srivatsavai  *
44eaa4710SRishi Srivatsavai  * The contents of this file are subject to the terms of the
54eaa4710SRishi Srivatsavai  * Common Development and Distribution License (the "License").
64eaa4710SRishi Srivatsavai  * You may not use this file except in compliance with the License.
74eaa4710SRishi Srivatsavai  *
84eaa4710SRishi Srivatsavai  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94eaa4710SRishi Srivatsavai  * or http://www.opensolaris.org/os/licensing.
104eaa4710SRishi Srivatsavai  * See the License for the specific language governing permissions
114eaa4710SRishi Srivatsavai  * and limitations under the License.
124eaa4710SRishi Srivatsavai  *
134eaa4710SRishi Srivatsavai  * When distributing Covered Code, include this CDDL HEADER in each
144eaa4710SRishi Srivatsavai  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154eaa4710SRishi Srivatsavai  * If applicable, add the following below this CDDL HEADER, with the
164eaa4710SRishi Srivatsavai  * fields enclosed by brackets "[]" replaced with your own identifying
174eaa4710SRishi Srivatsavai  * information: Portions Copyright [yyyy] [name of copyright owner]
184eaa4710SRishi Srivatsavai  *
194eaa4710SRishi Srivatsavai  * CDDL HEADER END
204eaa4710SRishi Srivatsavai  */
214eaa4710SRishi Srivatsavai /*
2232715170SCathy Zhou  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
234eaa4710SRishi Srivatsavai  */
244eaa4710SRishi Srivatsavai 
254eaa4710SRishi Srivatsavai #include <stdio.h>
264eaa4710SRishi Srivatsavai #include <sys/types.h>
274eaa4710SRishi Srivatsavai #include <string.h>
284eaa4710SRishi Srivatsavai #include <fcntl.h>
294eaa4710SRishi Srivatsavai #include <unistd.h>
304eaa4710SRishi Srivatsavai #include <stropts.h>
314eaa4710SRishi Srivatsavai #include <ctype.h>
324eaa4710SRishi Srivatsavai #include <errno.h>
334eaa4710SRishi Srivatsavai #include <stdlib.h>
344eaa4710SRishi Srivatsavai #include <door.h>
354eaa4710SRishi Srivatsavai #include <sys/mman.h>
364eaa4710SRishi Srivatsavai #include <libscf.h>
374eaa4710SRishi Srivatsavai #include <libscf_priv.h>
384eaa4710SRishi Srivatsavai #include <libdllink.h>
394eaa4710SRishi Srivatsavai #include <libdlbridge.h>
404eaa4710SRishi Srivatsavai #include <libdladm_impl.h>
414eaa4710SRishi Srivatsavai #include <stp_in.h>
424eaa4710SRishi Srivatsavai #include <net/bridge.h>
434eaa4710SRishi Srivatsavai #include <net/trill.h>
444eaa4710SRishi Srivatsavai #include <sys/socket.h>
4556a3cd3dSRishi Srivatsavai #include <sys/dld_ioc.h>
464eaa4710SRishi Srivatsavai 
474eaa4710SRishi Srivatsavai /*
484eaa4710SRishi Srivatsavai  * Bridge Administration Library.
494eaa4710SRishi Srivatsavai  *
50bbf21555SRichard Lowe  * This library is used by administration tools such as dladm(8) to configure
514eaa4710SRishi Srivatsavai  * bridges, and by the bridge daemon to retrieve configuration information.
524eaa4710SRishi Srivatsavai  */
534eaa4710SRishi Srivatsavai 
544eaa4710SRishi Srivatsavai #define	BRIDGE_SVC_NAME	"network/bridge"
554eaa4710SRishi Srivatsavai #define	TRILL_SVC_NAME	"network/routing/trill"
564eaa4710SRishi Srivatsavai 
574eaa4710SRishi Srivatsavai #define	DEFAULT_TIMEOUT	60000000
584eaa4710SRishi Srivatsavai #define	INIT_WAIT_USECS	50000
594eaa4710SRishi Srivatsavai #define	MAXPORTS	256
604eaa4710SRishi Srivatsavai 
614eaa4710SRishi Srivatsavai typedef struct scf_state {
624eaa4710SRishi Srivatsavai 	scf_handle_t *ss_handle;
634eaa4710SRishi Srivatsavai 	scf_instance_t *ss_inst;
644eaa4710SRishi Srivatsavai 	scf_service_t *ss_svc;
654eaa4710SRishi Srivatsavai 	scf_snapshot_t *ss_snap;
664eaa4710SRishi Srivatsavai 	scf_propertygroup_t *ss_pg;
674eaa4710SRishi Srivatsavai 	scf_property_t *ss_prop;
684eaa4710SRishi Srivatsavai } scf_state_t;
694eaa4710SRishi Srivatsavai 
704eaa4710SRishi Srivatsavai static void
shut_down_scf(scf_state_t * sstate)714eaa4710SRishi Srivatsavai shut_down_scf(scf_state_t *sstate)
724eaa4710SRishi Srivatsavai {
734eaa4710SRishi Srivatsavai 	scf_instance_destroy(sstate->ss_inst);
744eaa4710SRishi Srivatsavai 	(void) scf_handle_unbind(sstate->ss_handle);
754eaa4710SRishi Srivatsavai 	scf_handle_destroy(sstate->ss_handle);
764eaa4710SRishi Srivatsavai }
774eaa4710SRishi Srivatsavai 
784eaa4710SRishi Srivatsavai static char *
alloc_fmri(const char * service,const char * instance_name)794eaa4710SRishi Srivatsavai alloc_fmri(const char *service, const char *instance_name)
804eaa4710SRishi Srivatsavai {
814eaa4710SRishi Srivatsavai 	ssize_t max_fmri;
824eaa4710SRishi Srivatsavai 	char *fmri;
834eaa4710SRishi Srivatsavai 
844eaa4710SRishi Srivatsavai 	/* If the limit is unknown, then use an arbitrary value */
854eaa4710SRishi Srivatsavai 	if ((max_fmri = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) == -1)
864eaa4710SRishi Srivatsavai 		max_fmri = 1024;
874eaa4710SRishi Srivatsavai 	if ((fmri = malloc(max_fmri)) != NULL) {
884eaa4710SRishi Srivatsavai 		(void) snprintf(fmri, max_fmri, "svc:/%s:%s", service,
894eaa4710SRishi Srivatsavai 		    instance_name);
904eaa4710SRishi Srivatsavai 	}
914eaa4710SRishi Srivatsavai 	return (fmri);
924eaa4710SRishi Srivatsavai }
934eaa4710SRishi Srivatsavai 
944eaa4710SRishi Srivatsavai /*
954eaa4710SRishi Srivatsavai  * Start up SCF and bind the requested instance alone.
964eaa4710SRishi Srivatsavai  */
974eaa4710SRishi Srivatsavai static int
bind_instance(const char * service,const char * instance_name,scf_state_t * sstate)984eaa4710SRishi Srivatsavai bind_instance(const char *service, const char *instance_name,
994eaa4710SRishi Srivatsavai     scf_state_t *sstate)
1004eaa4710SRishi Srivatsavai {
1014eaa4710SRishi Srivatsavai 	char *fmri = NULL;
1024eaa4710SRishi Srivatsavai 
1034eaa4710SRishi Srivatsavai 	(void) memset(sstate, 0, sizeof (*sstate));
1044eaa4710SRishi Srivatsavai 
1054eaa4710SRishi Srivatsavai 	if ((sstate->ss_handle = scf_handle_create(SCF_VERSION)) == NULL)
1064eaa4710SRishi Srivatsavai 		return (-1);
1074eaa4710SRishi Srivatsavai 
1084eaa4710SRishi Srivatsavai 	if (scf_handle_bind(sstate->ss_handle) != 0)
1094eaa4710SRishi Srivatsavai 		goto failure;
1104eaa4710SRishi Srivatsavai 	sstate->ss_inst = scf_instance_create(sstate->ss_handle);
1114eaa4710SRishi Srivatsavai 	if (sstate->ss_inst == NULL)
1124eaa4710SRishi Srivatsavai 		goto failure;
1134eaa4710SRishi Srivatsavai 
1144eaa4710SRishi Srivatsavai 	fmri = alloc_fmri(service, instance_name);
1154eaa4710SRishi Srivatsavai 
1164eaa4710SRishi Srivatsavai 	if (scf_handle_decode_fmri(sstate->ss_handle, fmri, NULL, NULL,
1174eaa4710SRishi Srivatsavai 	    sstate->ss_inst, NULL, NULL,
1184eaa4710SRishi Srivatsavai 	    SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0)
1194eaa4710SRishi Srivatsavai 		goto failure;
1204eaa4710SRishi Srivatsavai 	free(fmri);
1214eaa4710SRishi Srivatsavai 	return (0);
1224eaa4710SRishi Srivatsavai 
1234eaa4710SRishi Srivatsavai failure:
1244eaa4710SRishi Srivatsavai 	free(fmri);
1254eaa4710SRishi Srivatsavai 	shut_down_scf(sstate);
1264eaa4710SRishi Srivatsavai 	return (-1);
1274eaa4710SRishi Srivatsavai }
1284eaa4710SRishi Srivatsavai 
1294eaa4710SRishi Srivatsavai /*
1304eaa4710SRishi Srivatsavai  * Start up SCF and an exact FMRI.  This is used for creating new instances and
1314eaa4710SRishi Srivatsavai  * enable/disable actions.
1324eaa4710SRishi Srivatsavai  */
1334eaa4710SRishi Srivatsavai static dladm_status_t
exact_instance(const char * fmri,scf_state_t * sstate)1344eaa4710SRishi Srivatsavai exact_instance(const char *fmri, scf_state_t *sstate)
1354eaa4710SRishi Srivatsavai {
1364eaa4710SRishi Srivatsavai 	dladm_status_t status;
1374eaa4710SRishi Srivatsavai 
1384eaa4710SRishi Srivatsavai 	(void) memset(sstate, 0, sizeof (*sstate));
1394eaa4710SRishi Srivatsavai 
1404eaa4710SRishi Srivatsavai 	if ((sstate->ss_handle = scf_handle_create(SCF_VERSION)) == NULL)
1414eaa4710SRishi Srivatsavai 		return (DLADM_STATUS_NOMEM);
1424eaa4710SRishi Srivatsavai 
1434eaa4710SRishi Srivatsavai 	status = DLADM_STATUS_FAILED;
1444eaa4710SRishi Srivatsavai 	if (scf_handle_bind(sstate->ss_handle) != 0)
1454eaa4710SRishi Srivatsavai 		goto failure;
1464eaa4710SRishi Srivatsavai 	sstate->ss_svc = scf_service_create(sstate->ss_handle);
1474eaa4710SRishi Srivatsavai 	if (sstate->ss_svc == NULL)
1484eaa4710SRishi Srivatsavai 		goto failure;
1494eaa4710SRishi Srivatsavai 	if (scf_handle_decode_fmri(sstate->ss_handle, fmri, NULL,
1504eaa4710SRishi Srivatsavai 	    sstate->ss_svc, NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) {
1514eaa4710SRishi Srivatsavai 		if (scf_error() == SCF_ERROR_NOT_FOUND)
1524eaa4710SRishi Srivatsavai 			status = DLADM_STATUS_OPTMISSING;
1534eaa4710SRishi Srivatsavai 		goto failure;
1544eaa4710SRishi Srivatsavai 	}
1554eaa4710SRishi Srivatsavai 	sstate->ss_inst = scf_instance_create(sstate->ss_handle);
1564eaa4710SRishi Srivatsavai 	if (sstate->ss_inst == NULL)
1574eaa4710SRishi Srivatsavai 		goto failure;
1584eaa4710SRishi Srivatsavai 	return (DLADM_STATUS_OK);
1594eaa4710SRishi Srivatsavai 
1604eaa4710SRishi Srivatsavai failure:
1614eaa4710SRishi Srivatsavai 	shut_down_scf(sstate);
1624eaa4710SRishi Srivatsavai 	return (status);
1634eaa4710SRishi Srivatsavai }
1644eaa4710SRishi Srivatsavai 
1654eaa4710SRishi Srivatsavai static void
drop_composed(scf_state_t * sstate)1664eaa4710SRishi Srivatsavai drop_composed(scf_state_t *sstate)
1674eaa4710SRishi Srivatsavai {
1684eaa4710SRishi Srivatsavai 	scf_property_destroy(sstate->ss_prop);
1694eaa4710SRishi Srivatsavai 	scf_pg_destroy(sstate->ss_pg);
1704eaa4710SRishi Srivatsavai 	scf_snapshot_destroy(sstate->ss_snap);
1714eaa4710SRishi Srivatsavai }
1724eaa4710SRishi Srivatsavai 
1734eaa4710SRishi Srivatsavai /*
1744eaa4710SRishi Srivatsavai  * This function sets up a composed view of the configuration information for
1754eaa4710SRishi Srivatsavai  * the specified instance.  When this is done, the get_property() function
1764eaa4710SRishi Srivatsavai  * should be able to return individual parameters.
1774eaa4710SRishi Srivatsavai  */
1784eaa4710SRishi Srivatsavai static int
get_composed_properties(const char * lpg,boolean_t snap,scf_state_t * sstate)1794eaa4710SRishi Srivatsavai get_composed_properties(const char *lpg, boolean_t snap, scf_state_t *sstate)
1804eaa4710SRishi Srivatsavai {
1814eaa4710SRishi Srivatsavai 	sstate->ss_snap = NULL;
1824eaa4710SRishi Srivatsavai 	sstate->ss_pg = NULL;
1834eaa4710SRishi Srivatsavai 	sstate->ss_prop = NULL;
1844eaa4710SRishi Srivatsavai 
1854eaa4710SRishi Srivatsavai 	if (snap) {
1864eaa4710SRishi Srivatsavai 		sstate->ss_snap = scf_snapshot_create(sstate->ss_handle);
1874eaa4710SRishi Srivatsavai 		if (sstate->ss_snap == NULL)
1884eaa4710SRishi Srivatsavai 			goto failure;
1894eaa4710SRishi Srivatsavai 		if (scf_instance_get_snapshot(sstate->ss_inst, "running",
1904eaa4710SRishi Srivatsavai 		    sstate->ss_snap) != 0)
1914eaa4710SRishi Srivatsavai 			goto failure;
1924eaa4710SRishi Srivatsavai 	}
1934eaa4710SRishi Srivatsavai 	if ((sstate->ss_pg = scf_pg_create(sstate->ss_handle)) == NULL)
1944eaa4710SRishi Srivatsavai 		goto failure;
1954eaa4710SRishi Srivatsavai 	if (scf_instance_get_pg_composed(sstate->ss_inst, sstate->ss_snap, lpg,
1964eaa4710SRishi Srivatsavai 	    sstate->ss_pg) != 0)
1974eaa4710SRishi Srivatsavai 		goto failure;
1984eaa4710SRishi Srivatsavai 	if ((sstate->ss_prop = scf_property_create(sstate->ss_handle)) ==
1994eaa4710SRishi Srivatsavai 	    NULL)
2004eaa4710SRishi Srivatsavai 		goto failure;
2014eaa4710SRishi Srivatsavai 	return (0);
2024eaa4710SRishi Srivatsavai 
2034eaa4710SRishi Srivatsavai failure:
2044eaa4710SRishi Srivatsavai 	drop_composed(sstate);
2054eaa4710SRishi Srivatsavai 	return (-1);
2064eaa4710SRishi Srivatsavai }
2074eaa4710SRishi Srivatsavai 
2084eaa4710SRishi Srivatsavai static int
get_count(const char * lprop,scf_state_t * sstate,uint64_t * answer)2094eaa4710SRishi Srivatsavai get_count(const char *lprop, scf_state_t *sstate, uint64_t *answer)
2104eaa4710SRishi Srivatsavai {
2114eaa4710SRishi Srivatsavai 	scf_value_t *val;
2124eaa4710SRishi Srivatsavai 	int retv;
2134eaa4710SRishi Srivatsavai 
2144eaa4710SRishi Srivatsavai 	if (scf_pg_get_property(sstate->ss_pg, lprop, sstate->ss_prop) != 0)
2154eaa4710SRishi Srivatsavai 		return (-1);
2164eaa4710SRishi Srivatsavai 	if ((val = scf_value_create(sstate->ss_handle)) == NULL)
2174eaa4710SRishi Srivatsavai 		return (-1);
2184eaa4710SRishi Srivatsavai 
2194eaa4710SRishi Srivatsavai 	if (scf_property_get_value(sstate->ss_prop, val) == 0 &&
2204eaa4710SRishi Srivatsavai 	    scf_value_get_count(val, answer) == 0)
2214eaa4710SRishi Srivatsavai 		retv = 0;
2224eaa4710SRishi Srivatsavai 	else
2234eaa4710SRishi Srivatsavai 		retv = -1;
2244eaa4710SRishi Srivatsavai 	scf_value_destroy(val);
2254eaa4710SRishi Srivatsavai 	return (retv);
2264eaa4710SRishi Srivatsavai }
2274eaa4710SRishi Srivatsavai 
2284eaa4710SRishi Srivatsavai static int
get_boolean(const char * lprop,scf_state_t * sstate,boolean_t * answer)2294eaa4710SRishi Srivatsavai get_boolean(const char *lprop, scf_state_t *sstate, boolean_t *answer)
2304eaa4710SRishi Srivatsavai {
2314eaa4710SRishi Srivatsavai 	scf_value_t *val;
2324eaa4710SRishi Srivatsavai 	int retv;
2334eaa4710SRishi Srivatsavai 	uint8_t bval;
2344eaa4710SRishi Srivatsavai 
2354eaa4710SRishi Srivatsavai 	if (scf_pg_get_property(sstate->ss_pg, lprop, sstate->ss_prop) != 0)
2364eaa4710SRishi Srivatsavai 		return (-1);
2374eaa4710SRishi Srivatsavai 	if ((val = scf_value_create(sstate->ss_handle)) == NULL)
2384eaa4710SRishi Srivatsavai 		return (-1);
2394eaa4710SRishi Srivatsavai 
2404eaa4710SRishi Srivatsavai 	if (scf_property_get_value(sstate->ss_prop, val) == 0 &&
2414eaa4710SRishi Srivatsavai 	    scf_value_get_boolean(val, &bval) == 0) {
2424eaa4710SRishi Srivatsavai 		retv = 0;
2434eaa4710SRishi Srivatsavai 		*answer = bval != 0;
2444eaa4710SRishi Srivatsavai 	} else {
2454eaa4710SRishi Srivatsavai 		retv = -1;
2464eaa4710SRishi Srivatsavai 	}
2474eaa4710SRishi Srivatsavai 	scf_value_destroy(val);
2484eaa4710SRishi Srivatsavai 	return (retv);
2494eaa4710SRishi Srivatsavai }
2504eaa4710SRishi Srivatsavai 
2514eaa4710SRishi Srivatsavai static dladm_status_t
bridge_door_call(const char * instname,bridge_door_type_t dtype,datalink_id_t linkid,void ** bufp,size_t inlen,size_t * buflenp,boolean_t is_list)2524eaa4710SRishi Srivatsavai bridge_door_call(const char *instname, bridge_door_type_t dtype,
2534eaa4710SRishi Srivatsavai     datalink_id_t linkid, void **bufp, size_t inlen, size_t *buflenp,
2544eaa4710SRishi Srivatsavai     boolean_t is_list)
2554eaa4710SRishi Srivatsavai {
2564eaa4710SRishi Srivatsavai 	char doorname[MAXPATHLEN];
2574eaa4710SRishi Srivatsavai 	int did, retv, etmp;
2584eaa4710SRishi Srivatsavai 	bridge_door_cmd_t *bdc;
2594eaa4710SRishi Srivatsavai 	door_arg_t arg;
2604eaa4710SRishi Srivatsavai 
2614eaa4710SRishi Srivatsavai 	(void) snprintf(doorname, sizeof (doorname), "%s/%s", DOOR_DIRNAME,
2624eaa4710SRishi Srivatsavai 	    instname);
2634eaa4710SRishi Srivatsavai 
2644eaa4710SRishi Srivatsavai 	/* Knock on the door */
2654eaa4710SRishi Srivatsavai 	did = open(doorname, O_RDONLY | O_NOFOLLOW | O_NONBLOCK);
2664eaa4710SRishi Srivatsavai 	if (did == -1)
2674eaa4710SRishi Srivatsavai 		return (dladm_errno2status(errno));
2684eaa4710SRishi Srivatsavai 
2694eaa4710SRishi Srivatsavai 	if ((bdc = malloc(sizeof (*bdc) + inlen)) == NULL) {
2704eaa4710SRishi Srivatsavai 		(void) close(did);
2714eaa4710SRishi Srivatsavai 		return (DLADM_STATUS_NOMEM);
2724eaa4710SRishi Srivatsavai 	}
2734eaa4710SRishi Srivatsavai 	bdc->bdc_type = dtype;
2744eaa4710SRishi Srivatsavai 	bdc->bdc_linkid = linkid;
2754eaa4710SRishi Srivatsavai 	if (inlen != 0)
2764eaa4710SRishi Srivatsavai 		(void) memcpy(bdc + 1, *bufp, inlen);
2774eaa4710SRishi Srivatsavai 
2784eaa4710SRishi Srivatsavai 	(void) memset(&arg, 0, sizeof (arg));
2794eaa4710SRishi Srivatsavai 	arg.data_ptr = (char *)bdc;
2804eaa4710SRishi Srivatsavai 	arg.data_size = sizeof (*bdc) + inlen;
2814eaa4710SRishi Srivatsavai 	arg.rbuf = *bufp;
2824eaa4710SRishi Srivatsavai 	arg.rsize = *buflenp;
2834eaa4710SRishi Srivatsavai 
2844eaa4710SRishi Srivatsavai 	/* The door_call function doesn't restart, so take care of that */
2854eaa4710SRishi Srivatsavai 	do {
2864eaa4710SRishi Srivatsavai 		errno = 0;
2874eaa4710SRishi Srivatsavai 		if ((retv = door_call(did, &arg)) == 0)
2884eaa4710SRishi Srivatsavai 			break;
2894eaa4710SRishi Srivatsavai 	} while (errno == EINTR);
2904eaa4710SRishi Srivatsavai 
2914eaa4710SRishi Srivatsavai 	/* If we get an unexpected response, then return an error */
2924eaa4710SRishi Srivatsavai 	if (retv == 0) {
2934eaa4710SRishi Srivatsavai 		/* The daemon returns a single int for errors */
2944eaa4710SRishi Srivatsavai 		/* LINTED: pointer alignment */
2954eaa4710SRishi Srivatsavai 		if (arg.data_size == sizeof (int) && *(int *)arg.rbuf != 0) {
2964eaa4710SRishi Srivatsavai 			retv = -1;
2974eaa4710SRishi Srivatsavai 			/* LINTED: pointer alignment */
2984eaa4710SRishi Srivatsavai 			errno = *(int *)arg.rbuf;
2994eaa4710SRishi Srivatsavai 		}
3004eaa4710SRishi Srivatsavai 		/* Terminated daemon returns with zero data */
3014eaa4710SRishi Srivatsavai 		if (arg.data_size == 0) {
3024eaa4710SRishi Srivatsavai 			retv = -1;
3034eaa4710SRishi Srivatsavai 			errno = EBADF;
3044eaa4710SRishi Srivatsavai 		}
3054eaa4710SRishi Srivatsavai 	}
3064eaa4710SRishi Srivatsavai 
3074eaa4710SRishi Srivatsavai 	if (retv == 0) {
3084eaa4710SRishi Srivatsavai 		if (arg.rbuf != *bufp) {
3094eaa4710SRishi Srivatsavai 			if (is_list) {
3104eaa4710SRishi Srivatsavai 				void *newp;
3114eaa4710SRishi Srivatsavai 
3124eaa4710SRishi Srivatsavai 				newp = realloc(*bufp, arg.data_size);
3134eaa4710SRishi Srivatsavai 				if (newp == NULL) {
3144eaa4710SRishi Srivatsavai 					retv = -1;
3154eaa4710SRishi Srivatsavai 				} else {
3164eaa4710SRishi Srivatsavai 					*bufp = newp;
3174eaa4710SRishi Srivatsavai 					(void) memcpy(*bufp, arg.rbuf,
3184eaa4710SRishi Srivatsavai 					    arg.data_size);
3194eaa4710SRishi Srivatsavai 				}
3204eaa4710SRishi Srivatsavai 			}
3214eaa4710SRishi Srivatsavai 			(void) munmap(arg.rbuf, arg.rsize);
3224eaa4710SRishi Srivatsavai 		}
3234eaa4710SRishi Srivatsavai 		if (is_list) {
3244eaa4710SRishi Srivatsavai 			*buflenp = arg.data_size;
3254eaa4710SRishi Srivatsavai 		} else if (arg.data_size != *buflenp || arg.rbuf != *bufp) {
3264eaa4710SRishi Srivatsavai 			errno = EINVAL;
3274eaa4710SRishi Srivatsavai 			retv = -1;
3284eaa4710SRishi Srivatsavai 		}
3294eaa4710SRishi Srivatsavai 	}
3304eaa4710SRishi Srivatsavai 
3314eaa4710SRishi Srivatsavai 	etmp = errno;
3324eaa4710SRishi Srivatsavai 	(void) close(did);
3334eaa4710SRishi Srivatsavai 
3344eaa4710SRishi Srivatsavai 	/* Revoked door is the same as no door at all */
3354eaa4710SRishi Srivatsavai 	if (etmp == EBADF)
3364eaa4710SRishi Srivatsavai 		etmp = ENOENT;
3374eaa4710SRishi Srivatsavai 
3384eaa4710SRishi Srivatsavai 	return (retv == 0 ? DLADM_STATUS_OK : dladm_errno2status(etmp));
3394eaa4710SRishi Srivatsavai }
3404eaa4710SRishi Srivatsavai 
3414eaa4710SRishi Srivatsavai /*
3424eaa4710SRishi Srivatsavai  * Wrapper function for making per-port calls.
3434eaa4710SRishi Srivatsavai  */
3444eaa4710SRishi Srivatsavai static dladm_status_t
port_door_call(dladm_handle_t handle,datalink_id_t linkid,bridge_door_type_t dtype,void * buf,size_t inlen,size_t buflen)3454eaa4710SRishi Srivatsavai port_door_call(dladm_handle_t handle, datalink_id_t linkid,
3464eaa4710SRishi Srivatsavai     bridge_door_type_t dtype, void *buf, size_t inlen, size_t buflen)
3474eaa4710SRishi Srivatsavai {
3484eaa4710SRishi Srivatsavai 	char bridge[MAXLINKNAMELEN];
3494eaa4710SRishi Srivatsavai 	dladm_status_t status;
3504eaa4710SRishi Srivatsavai 
3514eaa4710SRishi Srivatsavai 	status = dladm_bridge_getlink(handle, linkid, bridge, sizeof (bridge));
3524eaa4710SRishi Srivatsavai 	if (status != DLADM_STATUS_OK)
3534eaa4710SRishi Srivatsavai 		return (status);
3544eaa4710SRishi Srivatsavai 	return (bridge_door_call(bridge, dtype, linkid, &buf, inlen, &buflen,
3554eaa4710SRishi Srivatsavai 	    B_FALSE));
3564eaa4710SRishi Srivatsavai }
3574eaa4710SRishi Srivatsavai 
3584eaa4710SRishi Srivatsavai static dladm_status_t
bridge_refresh(const char * bridge)3594eaa4710SRishi Srivatsavai bridge_refresh(const char *bridge)
3604eaa4710SRishi Srivatsavai {
3614eaa4710SRishi Srivatsavai 	dladm_status_t status;
3624eaa4710SRishi Srivatsavai 	int twoints[2];
3634eaa4710SRishi Srivatsavai 	void *bdptr;
3644eaa4710SRishi Srivatsavai 	size_t buflen;
3654eaa4710SRishi Srivatsavai 	char *fmri;
3664eaa4710SRishi Srivatsavai 	int refresh_count;
3674eaa4710SRishi Srivatsavai 
3684eaa4710SRishi Srivatsavai 	buflen = sizeof (twoints);
3694eaa4710SRishi Srivatsavai 	bdptr = twoints;
3704eaa4710SRishi Srivatsavai 	status = bridge_door_call(bridge, bdcBridgeGetRefreshCount,
3714eaa4710SRishi Srivatsavai 	    DATALINK_INVALID_LINKID, &bdptr, 0, &buflen, B_FALSE);
3724eaa4710SRishi Srivatsavai 	if (status == DLADM_STATUS_NOTFOUND)
3734eaa4710SRishi Srivatsavai 		return (DLADM_STATUS_OK);
3744eaa4710SRishi Srivatsavai 	if (status != DLADM_STATUS_OK)
3754eaa4710SRishi Srivatsavai 		return (status);
3764eaa4710SRishi Srivatsavai 	refresh_count = twoints[0];
3774eaa4710SRishi Srivatsavai 	if ((fmri = alloc_fmri(BRIDGE_SVC_NAME, bridge)) == NULL)
3784eaa4710SRishi Srivatsavai 		return (DLADM_STATUS_NOMEM);
3794eaa4710SRishi Srivatsavai 	status = smf_refresh_instance(fmri) == 0 ?
3804eaa4710SRishi Srivatsavai 	    DLADM_STATUS_OK : DLADM_STATUS_FAILED;
3814eaa4710SRishi Srivatsavai 	free(fmri);
3824eaa4710SRishi Srivatsavai 	if (status == DLADM_STATUS_OK) {
3834eaa4710SRishi Srivatsavai 		int i = 0;
3844eaa4710SRishi Srivatsavai 
3854eaa4710SRishi Srivatsavai 		/*
3864eaa4710SRishi Srivatsavai 		 * SMF doesn't give any synchronous behavior or dependency
3874eaa4710SRishi Srivatsavai 		 * ordering for refresh operations, so we have to invent our
3884eaa4710SRishi Srivatsavai 		 * own mechanism here.  Get the refresh counter from the
3894eaa4710SRishi Srivatsavai 		 * daemon, and wait for it to change.  It's not pretty, but
3904eaa4710SRishi Srivatsavai 		 * it's sufficient.
3914eaa4710SRishi Srivatsavai 		 */
3924eaa4710SRishi Srivatsavai 		while (++i <= 10) {
3934eaa4710SRishi Srivatsavai 			buflen = sizeof (twoints);
3944eaa4710SRishi Srivatsavai 			bdptr = twoints;
3954eaa4710SRishi Srivatsavai 			status = bridge_door_call(bridge,
3964eaa4710SRishi Srivatsavai 			    bdcBridgeGetRefreshCount, DATALINK_INVALID_LINKID,
3974eaa4710SRishi Srivatsavai 			    &bdptr, 0, &buflen, B_FALSE);
3984eaa4710SRishi Srivatsavai 			if (status != DLADM_STATUS_OK)
3994eaa4710SRishi Srivatsavai 				break;
4004eaa4710SRishi Srivatsavai 			if (twoints[0] != refresh_count)
4014eaa4710SRishi Srivatsavai 				break;
4024eaa4710SRishi Srivatsavai 			(void) usleep(100000);
4034eaa4710SRishi Srivatsavai 		}
4044eaa4710SRishi Srivatsavai 		fmri = alloc_fmri(TRILL_SVC_NAME, bridge);
4054eaa4710SRishi Srivatsavai 		if (fmri == NULL)
4064eaa4710SRishi Srivatsavai 			return (DLADM_STATUS_NOMEM);
4074eaa4710SRishi Srivatsavai 		status = smf_refresh_instance(fmri) == 0 ||
4084eaa4710SRishi Srivatsavai 		    scf_error() == SCF_ERROR_NOT_FOUND ?
4094eaa4710SRishi Srivatsavai 		    DLADM_STATUS_OK : DLADM_STATUS_FAILED;
4104eaa4710SRishi Srivatsavai 		free(fmri);
4114eaa4710SRishi Srivatsavai 	}
4124eaa4710SRishi Srivatsavai 	return (status);
4134eaa4710SRishi Srivatsavai }
4144eaa4710SRishi Srivatsavai 
4154eaa4710SRishi Srivatsavai /*
4164eaa4710SRishi Srivatsavai  * Look up bridge property values from SCF and return them.
4174eaa4710SRishi Srivatsavai  */
4184eaa4710SRishi Srivatsavai dladm_status_t
dladm_bridge_get_properties(const char * instance_name,UID_STP_CFG_T * cfg,dladm_bridge_prot_t * brprotp)4194eaa4710SRishi Srivatsavai dladm_bridge_get_properties(const char *instance_name, UID_STP_CFG_T *cfg,
4204eaa4710SRishi Srivatsavai     dladm_bridge_prot_t *brprotp)
4214eaa4710SRishi Srivatsavai {
4224eaa4710SRishi Srivatsavai 	scf_state_t sstate;
4234eaa4710SRishi Srivatsavai 	uint64_t value;
4244eaa4710SRishi Srivatsavai 	boolean_t trill_enabled;
4254eaa4710SRishi Srivatsavai 
4264eaa4710SRishi Srivatsavai 	cfg->field_mask = 0;
4274eaa4710SRishi Srivatsavai 	cfg->bridge_priority = DEF_BR_PRIO;
4284eaa4710SRishi Srivatsavai 	cfg->max_age = DEF_BR_MAXAGE;
4294eaa4710SRishi Srivatsavai 	cfg->hello_time = DEF_BR_HELLOT;
4304eaa4710SRishi Srivatsavai 	cfg->forward_delay = DEF_BR_FWDELAY;
4314eaa4710SRishi Srivatsavai 	cfg->force_version = DEF_FORCE_VERS;
4324eaa4710SRishi Srivatsavai 
4334eaa4710SRishi Srivatsavai 	(void) strlcpy(cfg->vlan_name, instance_name, sizeof (cfg->vlan_name));
4344eaa4710SRishi Srivatsavai 
4354eaa4710SRishi Srivatsavai 	*brprotp = DLADM_BRIDGE_PROT_STP;
4364eaa4710SRishi Srivatsavai 
4374eaa4710SRishi Srivatsavai 	/* It's ok for this to be missing; it's installed separately */
4384eaa4710SRishi Srivatsavai 	if (bind_instance(TRILL_SVC_NAME, instance_name, &sstate) == 0) {
4394eaa4710SRishi Srivatsavai 		trill_enabled = B_FALSE;
4404eaa4710SRishi Srivatsavai 		if (get_composed_properties(SCF_PG_GENERAL, B_FALSE, &sstate) ==
4414eaa4710SRishi Srivatsavai 		    0) {
4424eaa4710SRishi Srivatsavai 			(void) get_boolean(SCF_PROPERTY_ENABLED, &sstate,
4434eaa4710SRishi Srivatsavai 			    &trill_enabled);
4444eaa4710SRishi Srivatsavai 			if (trill_enabled)
4454eaa4710SRishi Srivatsavai 				*brprotp = DLADM_BRIDGE_PROT_TRILL;
4464eaa4710SRishi Srivatsavai 			drop_composed(&sstate);
4474eaa4710SRishi Srivatsavai 		}
4484eaa4710SRishi Srivatsavai 		if (get_composed_properties(SCF_PG_GENERAL_OVR, B_FALSE,
4494eaa4710SRishi Srivatsavai 		    &sstate) == 0) {
4504eaa4710SRishi Srivatsavai 			(void) get_boolean(SCF_PROPERTY_ENABLED, &sstate,
4514eaa4710SRishi Srivatsavai 			    &trill_enabled);
4524eaa4710SRishi Srivatsavai 			if (trill_enabled)
4534eaa4710SRishi Srivatsavai 				*brprotp = DLADM_BRIDGE_PROT_TRILL;
4544eaa4710SRishi Srivatsavai 			drop_composed(&sstate);
4554eaa4710SRishi Srivatsavai 		}
4564eaa4710SRishi Srivatsavai 		shut_down_scf(&sstate);
4574eaa4710SRishi Srivatsavai 	}
4584eaa4710SRishi Srivatsavai 
4594eaa4710SRishi Srivatsavai 	cfg->stp_enabled = (*brprotp == DLADM_BRIDGE_PROT_STP) ?
4604eaa4710SRishi Srivatsavai 	    STP_ENABLED : STP_DISABLED;
4614eaa4710SRishi Srivatsavai 	cfg->field_mask |= BR_CFG_STATE;
4624eaa4710SRishi Srivatsavai 
4634eaa4710SRishi Srivatsavai 	if (bind_instance(BRIDGE_SVC_NAME, instance_name, &sstate) != 0)
4644eaa4710SRishi Srivatsavai 		return (DLADM_STATUS_REPOSITORYINVAL);
4654eaa4710SRishi Srivatsavai 
4664eaa4710SRishi Srivatsavai 	if (get_composed_properties("config", B_TRUE, &sstate) != 0) {
4674eaa4710SRishi Srivatsavai 		shut_down_scf(&sstate);
4684eaa4710SRishi Srivatsavai 		return (DLADM_STATUS_REPOSITORYINVAL);
4694eaa4710SRishi Srivatsavai 	}
4704eaa4710SRishi Srivatsavai 
4714eaa4710SRishi Srivatsavai 	if (get_count("priority", &sstate, &value) == 0) {
4724eaa4710SRishi Srivatsavai 		cfg->bridge_priority = value;
4734eaa4710SRishi Srivatsavai 		cfg->field_mask |= BR_CFG_PRIO;
4744eaa4710SRishi Srivatsavai 	}
4754eaa4710SRishi Srivatsavai 	if (get_count("max-age", &sstate, &value) == 0) {
4764eaa4710SRishi Srivatsavai 		cfg->max_age = value / IEEE_TIMER_SCALE;
4774eaa4710SRishi Srivatsavai 		cfg->field_mask |= BR_CFG_AGE;
4784eaa4710SRishi Srivatsavai 	}
4794eaa4710SRishi Srivatsavai 	if (get_count("hello-time", &sstate, &value) == 0) {
4804eaa4710SRishi Srivatsavai 		cfg->hello_time = value / IEEE_TIMER_SCALE;
4814eaa4710SRishi Srivatsavai 		cfg->field_mask |= BR_CFG_HELLO;
4824eaa4710SRishi Srivatsavai 	}
4834eaa4710SRishi Srivatsavai 	if (get_count("forward-delay", &sstate, &value) == 0) {
4844eaa4710SRishi Srivatsavai 		cfg->forward_delay = value / IEEE_TIMER_SCALE;
4854eaa4710SRishi Srivatsavai 		cfg->field_mask |= BR_CFG_DELAY;
4864eaa4710SRishi Srivatsavai 	}
4874eaa4710SRishi Srivatsavai 	if (get_count("force-protocol", &sstate, &value) == 0) {
4884eaa4710SRishi Srivatsavai 		cfg->force_version = value;
4894eaa4710SRishi Srivatsavai 		cfg->field_mask |= BR_CFG_FORCE_VER;
4904eaa4710SRishi Srivatsavai 	}
4914eaa4710SRishi Srivatsavai 
4924eaa4710SRishi Srivatsavai 	drop_composed(&sstate);
4934eaa4710SRishi Srivatsavai 	shut_down_scf(&sstate);
4944eaa4710SRishi Srivatsavai 	return (DLADM_STATUS_OK);
4954eaa4710SRishi Srivatsavai }
4964eaa4710SRishi Srivatsavai 
4974eaa4710SRishi Srivatsavai /*
4984eaa4710SRishi Srivatsavai  * Retrieve special non-settable and undocumented parameters.
4994eaa4710SRishi Srivatsavai  */
5004eaa4710SRishi Srivatsavai dladm_status_t
dladm_bridge_get_privprop(const char * instance_name,boolean_t * debugp,uint32_t * tablemaxp)5014eaa4710SRishi Srivatsavai dladm_bridge_get_privprop(const char *instance_name, boolean_t *debugp,
5024eaa4710SRishi Srivatsavai     uint32_t *tablemaxp)
5034eaa4710SRishi Srivatsavai {
5044eaa4710SRishi Srivatsavai 	scf_state_t sstate;
5054eaa4710SRishi Srivatsavai 	uint64_t value;
5064eaa4710SRishi Srivatsavai 
5074eaa4710SRishi Srivatsavai 	*debugp = B_FALSE;
5084eaa4710SRishi Srivatsavai 	*tablemaxp = 10000;
5094eaa4710SRishi Srivatsavai 
5104eaa4710SRishi Srivatsavai 	if (bind_instance(BRIDGE_SVC_NAME, instance_name, &sstate) != 0)
5114eaa4710SRishi Srivatsavai 		return (DLADM_STATUS_REPOSITORYINVAL);
5124eaa4710SRishi Srivatsavai 
5134eaa4710SRishi Srivatsavai 	if (get_composed_properties("config", B_TRUE, &sstate) != 0) {
5144eaa4710SRishi Srivatsavai 		shut_down_scf(&sstate);
5154eaa4710SRishi Srivatsavai 		return (DLADM_STATUS_REPOSITORYINVAL);
5164eaa4710SRishi Srivatsavai 	}
5174eaa4710SRishi Srivatsavai 
5184eaa4710SRishi Srivatsavai 	(void) get_boolean("debug", &sstate, debugp);
5194eaa4710SRishi Srivatsavai 	if (get_count("table-maximum", &sstate, &value) == 0)
5204eaa4710SRishi Srivatsavai 		*tablemaxp = (uint32_t)value;
5214eaa4710SRishi Srivatsavai 
5224eaa4710SRishi Srivatsavai 	drop_composed(&sstate);
5234eaa4710SRishi Srivatsavai 	shut_down_scf(&sstate);
5244eaa4710SRishi Srivatsavai 	return (DLADM_STATUS_OK);
5254eaa4710SRishi Srivatsavai }
5264eaa4710SRishi Srivatsavai 
5274eaa4710SRishi Srivatsavai static boolean_t
set_count_property(scf_handle_t * handle,scf_transaction_t * tran,const char * propname,uint64_t propval)5284eaa4710SRishi Srivatsavai set_count_property(scf_handle_t *handle, scf_transaction_t *tran,
5294eaa4710SRishi Srivatsavai     const char *propname, uint64_t propval)
5304eaa4710SRishi Srivatsavai {
5314eaa4710SRishi Srivatsavai 	scf_transaction_entry_t *entry;
5324eaa4710SRishi Srivatsavai 	scf_value_t *value = NULL;
5334eaa4710SRishi Srivatsavai 
5344eaa4710SRishi Srivatsavai 	if ((entry = scf_entry_create(handle)) == NULL)
5354eaa4710SRishi Srivatsavai 		return (B_FALSE);
5364eaa4710SRishi Srivatsavai 
5374eaa4710SRishi Srivatsavai 	if ((value = scf_value_create(handle)) == NULL)
5384eaa4710SRishi Srivatsavai 		goto out;
5394eaa4710SRishi Srivatsavai 	if (scf_transaction_property_new(tran, entry, propname,
5404eaa4710SRishi Srivatsavai 	    SCF_TYPE_COUNT) != 0 &&
5414eaa4710SRishi Srivatsavai 	    scf_transaction_property_change(tran, entry, propname,
5424eaa4710SRishi Srivatsavai 	    SCF_TYPE_COUNT) != 0)
5434eaa4710SRishi Srivatsavai 		goto out;
5444eaa4710SRishi Srivatsavai 	scf_value_set_count(value, propval);
5454eaa4710SRishi Srivatsavai 	if (scf_entry_add_value(entry, value) == 0)
5464eaa4710SRishi Srivatsavai 		return (B_TRUE);
5474eaa4710SRishi Srivatsavai 
5484eaa4710SRishi Srivatsavai out:
5494eaa4710SRishi Srivatsavai 	if (value != NULL)
5504eaa4710SRishi Srivatsavai 		scf_value_destroy(value);
5514eaa4710SRishi Srivatsavai 
5524eaa4710SRishi Srivatsavai 	scf_entry_destroy_children(entry);
5534eaa4710SRishi Srivatsavai 	scf_entry_destroy(entry);
5544eaa4710SRishi Srivatsavai 
5554eaa4710SRishi Srivatsavai 	return (B_FALSE);
5564eaa4710SRishi Srivatsavai }
5574eaa4710SRishi Srivatsavai 
5584eaa4710SRishi Srivatsavai static boolean_t
set_string_property(scf_handle_t * handle,scf_transaction_t * tran,const char * propname,const char * propval)5594eaa4710SRishi Srivatsavai set_string_property(scf_handle_t *handle, scf_transaction_t *tran,
5604eaa4710SRishi Srivatsavai     const char *propname, const char *propval)
5614eaa4710SRishi Srivatsavai {
5624eaa4710SRishi Srivatsavai 	scf_transaction_entry_t *entry;
5634eaa4710SRishi Srivatsavai 	scf_value_t *value = NULL;
5644eaa4710SRishi Srivatsavai 
5654eaa4710SRishi Srivatsavai 	if ((entry = scf_entry_create(handle)) == NULL)
5664eaa4710SRishi Srivatsavai 		return (B_FALSE);
5674eaa4710SRishi Srivatsavai 
5684eaa4710SRishi Srivatsavai 	if ((value = scf_value_create(handle)) == NULL)
5694eaa4710SRishi Srivatsavai 		goto out;
5704eaa4710SRishi Srivatsavai 	if (scf_transaction_property_new(tran, entry, propname,
5714eaa4710SRishi Srivatsavai 	    SCF_TYPE_ASTRING) != 0 &&
5724eaa4710SRishi Srivatsavai 	    scf_transaction_property_change(tran, entry, propname,
5734eaa4710SRishi Srivatsavai 	    SCF_TYPE_ASTRING) != 0)
5744eaa4710SRishi Srivatsavai 		goto out;
5754eaa4710SRishi Srivatsavai 	if (scf_value_set_astring(value, propval) != 0)
5764eaa4710SRishi Srivatsavai 		goto out;
5774eaa4710SRishi Srivatsavai 	if (scf_entry_add_value(entry, value) == 0)
5784eaa4710SRishi Srivatsavai 		return (B_TRUE);
5794eaa4710SRishi Srivatsavai 
5804eaa4710SRishi Srivatsavai out:
5814eaa4710SRishi Srivatsavai 	if (value != NULL)
5824eaa4710SRishi Srivatsavai 		scf_value_destroy(value);
5834eaa4710SRishi Srivatsavai 
5844eaa4710SRishi Srivatsavai 	scf_entry_destroy_children(entry);
5854eaa4710SRishi Srivatsavai 	scf_entry_destroy(entry);
5864eaa4710SRishi Srivatsavai 
5874eaa4710SRishi Srivatsavai 	return (B_FALSE);
5884eaa4710SRishi Srivatsavai }
5894eaa4710SRishi Srivatsavai 
5904eaa4710SRishi Srivatsavai static boolean_t
set_fmri_property(scf_handle_t * handle,scf_transaction_t * tran,const char * propname,const char * propval)5914eaa4710SRishi Srivatsavai set_fmri_property(scf_handle_t *handle, scf_transaction_t *tran,
5924eaa4710SRishi Srivatsavai     const char *propname, const char *propval)
5934eaa4710SRishi Srivatsavai {
5944eaa4710SRishi Srivatsavai 	scf_transaction_entry_t *entry;
5954eaa4710SRishi Srivatsavai 	scf_value_t *value = NULL;
5964eaa4710SRishi Srivatsavai 
5974eaa4710SRishi Srivatsavai 	if ((entry = scf_entry_create(handle)) == NULL)
5984eaa4710SRishi Srivatsavai 		return (B_FALSE);
5994eaa4710SRishi Srivatsavai 
6004eaa4710SRishi Srivatsavai 	if ((value = scf_value_create(handle)) == NULL)
6014eaa4710SRishi Srivatsavai 		goto out;
6024eaa4710SRishi Srivatsavai 	if (scf_transaction_property_new(tran, entry, propname,
6034eaa4710SRishi Srivatsavai 	    SCF_TYPE_FMRI) != 0 &&
6044eaa4710SRishi Srivatsavai 	    scf_transaction_property_change(tran, entry, propname,
6054eaa4710SRishi Srivatsavai 	    SCF_TYPE_FMRI) != 0)
6064eaa4710SRishi Srivatsavai 		goto out;
6074eaa4710SRishi Srivatsavai 	if (scf_value_set_from_string(value, SCF_TYPE_FMRI, propval) != 0)
6084eaa4710SRishi Srivatsavai 		goto out;
6094eaa4710SRishi Srivatsavai 	if (scf_entry_add_value(entry, value) == 0)
6104eaa4710SRishi Srivatsavai 		return (B_TRUE);
6114eaa4710SRishi Srivatsavai 
6124eaa4710SRishi Srivatsavai out:
6134eaa4710SRishi Srivatsavai 	if (value != NULL)
6144eaa4710SRishi Srivatsavai 		scf_value_destroy(value);
6154eaa4710SRishi Srivatsavai 
6164eaa4710SRishi Srivatsavai 	scf_entry_destroy_children(entry);
6174eaa4710SRishi Srivatsavai 	scf_entry_destroy(entry);
6184eaa4710SRishi Srivatsavai 
6194eaa4710SRishi Srivatsavai 	return (B_FALSE);
6204eaa4710SRishi Srivatsavai }
6214eaa4710SRishi Srivatsavai 
6224eaa4710SRishi Srivatsavai static dladm_status_t
dladm_bridge_persist_conf(dladm_handle_t handle,const char * link,datalink_id_t linkid)6234eaa4710SRishi Srivatsavai dladm_bridge_persist_conf(dladm_handle_t handle, const char *link,
6244eaa4710SRishi Srivatsavai     datalink_id_t linkid)
6254eaa4710SRishi Srivatsavai {
62632715170SCathy Zhou 	dladm_conf_t conf;
6274eaa4710SRishi Srivatsavai 	dladm_status_t status;
6284eaa4710SRishi Srivatsavai 
6294eaa4710SRishi Srivatsavai 	status = dladm_create_conf(handle, link, linkid, DATALINK_CLASS_BRIDGE,
6304eaa4710SRishi Srivatsavai 	    DL_ETHER, &conf);
6314eaa4710SRishi Srivatsavai 	if (status == DLADM_STATUS_OK) {
6324eaa4710SRishi Srivatsavai 		/*
6334eaa4710SRishi Srivatsavai 		 * Create the datalink entry for the bridge.  Note that all of
6344eaa4710SRishi Srivatsavai 		 * the real configuration information is in SMF.
6354eaa4710SRishi Srivatsavai 		 */
6364eaa4710SRishi Srivatsavai 		status = dladm_write_conf(handle, conf);
6374eaa4710SRishi Srivatsavai 		dladm_destroy_conf(handle, conf);
6384eaa4710SRishi Srivatsavai 	}
6394eaa4710SRishi Srivatsavai 	return (status);
6404eaa4710SRishi Srivatsavai }
6414eaa4710SRishi Srivatsavai 
6424eaa4710SRishi Srivatsavai /* Convert bridge protection option string to dladm_bridge_prot_t */
6434eaa4710SRishi Srivatsavai dladm_status_t
dladm_bridge_str2prot(const char * str,dladm_bridge_prot_t * brprotp)6444eaa4710SRishi Srivatsavai dladm_bridge_str2prot(const char *str, dladm_bridge_prot_t *brprotp)
6454eaa4710SRishi Srivatsavai {
6464eaa4710SRishi Srivatsavai 	if (strcmp(str, "stp") == 0)
6474eaa4710SRishi Srivatsavai 		*brprotp = DLADM_BRIDGE_PROT_STP;
6484eaa4710SRishi Srivatsavai 	else if (strcmp(str, "trill") == 0)
6494eaa4710SRishi Srivatsavai 		*brprotp = DLADM_BRIDGE_PROT_TRILL;
6504eaa4710SRishi Srivatsavai 	else
6514eaa4710SRishi Srivatsavai 		return (DLADM_STATUS_BADARG);
6524eaa4710SRishi Srivatsavai 	return (DLADM_STATUS_OK);
6534eaa4710SRishi Srivatsavai }
6544eaa4710SRishi Srivatsavai 
6554eaa4710SRishi Srivatsavai /* Convert bridge protection option from dladm_bridge_prot_t to string */
6564eaa4710SRishi Srivatsavai const char *
dladm_bridge_prot2str(dladm_bridge_prot_t brprot)6574eaa4710SRishi Srivatsavai dladm_bridge_prot2str(dladm_bridge_prot_t brprot)
6584eaa4710SRishi Srivatsavai {
6594eaa4710SRishi Srivatsavai 	switch (brprot) {
6604eaa4710SRishi Srivatsavai 	case DLADM_BRIDGE_PROT_STP:
6614eaa4710SRishi Srivatsavai 		return ("stp");
6624eaa4710SRishi Srivatsavai 	case DLADM_BRIDGE_PROT_TRILL:
6634eaa4710SRishi Srivatsavai 		return ("trill");
6644eaa4710SRishi Srivatsavai 	default:
6654eaa4710SRishi Srivatsavai 		return ("unknown");
6664eaa4710SRishi Srivatsavai 	}
6674eaa4710SRishi Srivatsavai }
6684eaa4710SRishi Srivatsavai 
6694eaa4710SRishi Srivatsavai static dladm_status_t
enable_instance(const char * service_name,const char * instance)6704eaa4710SRishi Srivatsavai enable_instance(const char *service_name, const char *instance)
6714eaa4710SRishi Srivatsavai {
6724eaa4710SRishi Srivatsavai 	dladm_status_t status;
6734eaa4710SRishi Srivatsavai 	char *fmri = alloc_fmri(service_name, instance);
6744eaa4710SRishi Srivatsavai 
6754eaa4710SRishi Srivatsavai 	if (fmri == NULL)
6764eaa4710SRishi Srivatsavai 		return (DLADM_STATUS_NOMEM);
6774eaa4710SRishi Srivatsavai 	status = smf_enable_instance(fmri, 0) == 0 ?
6784eaa4710SRishi Srivatsavai 	    DLADM_STATUS_OK : DLADM_STATUS_FAILED;
6794eaa4710SRishi Srivatsavai 	free(fmri);
6804eaa4710SRishi Srivatsavai 	return (status);
6814eaa4710SRishi Srivatsavai }
6824eaa4710SRishi Srivatsavai 
6834eaa4710SRishi Srivatsavai /*
6844eaa4710SRishi Srivatsavai  * Shut down a possibly-running service instance.  If this is a permanent
6854eaa4710SRishi Srivatsavai  * change, then delete it from the system.
6864eaa4710SRishi Srivatsavai  */
6874eaa4710SRishi Srivatsavai static dladm_status_t
shut_down_instance(const char * service_name,const char * instance,uint32_t flags)6884eaa4710SRishi Srivatsavai shut_down_instance(const char *service_name, const char *instance,
6894eaa4710SRishi Srivatsavai     uint32_t flags)
6904eaa4710SRishi Srivatsavai {
6914eaa4710SRishi Srivatsavai 	dladm_status_t status;
6924eaa4710SRishi Srivatsavai 	char *fmri = alloc_fmri(service_name, instance);
6934eaa4710SRishi Srivatsavai 	char *state;
6944eaa4710SRishi Srivatsavai 	scf_state_t sstate;
6954eaa4710SRishi Srivatsavai 
6964eaa4710SRishi Srivatsavai 	if (fmri == NULL)
6974eaa4710SRishi Srivatsavai 		return (DLADM_STATUS_NOMEM);
6984eaa4710SRishi Srivatsavai 
6994eaa4710SRishi Srivatsavai 	if (smf_disable_instance(fmri,
7004eaa4710SRishi Srivatsavai 	    flags & DLADM_OPT_PERSIST ? 0 : SMF_TEMPORARY) == 0) {
7014eaa4710SRishi Srivatsavai 		useconds_t usecs, umax;
7024eaa4710SRishi Srivatsavai 
7034eaa4710SRishi Srivatsavai 		/* If we can disable, then wait for it to happen. */
7044eaa4710SRishi Srivatsavai 		umax = DEFAULT_TIMEOUT;
7054eaa4710SRishi Srivatsavai 		for (usecs = INIT_WAIT_USECS; umax != 0; umax -= usecs) {
7064eaa4710SRishi Srivatsavai 			state = smf_get_state(fmri);
7074eaa4710SRishi Srivatsavai 			if (state != NULL &&
7084eaa4710SRishi Srivatsavai 			    strcmp(state, SCF_STATE_STRING_DISABLED) == 0)
7094eaa4710SRishi Srivatsavai 				break;
7104eaa4710SRishi Srivatsavai 			free(state);
7114eaa4710SRishi Srivatsavai 			usecs *= 2;
7124eaa4710SRishi Srivatsavai 			if (usecs > umax)
7134eaa4710SRishi Srivatsavai 				usecs = umax;
7144eaa4710SRishi Srivatsavai 			(void) usleep(usecs);
7154eaa4710SRishi Srivatsavai 		}
7164eaa4710SRishi Srivatsavai 		if (umax == 0) {
7174eaa4710SRishi Srivatsavai 			state = smf_get_state(fmri);
7184eaa4710SRishi Srivatsavai 			if (state != NULL &&
7194eaa4710SRishi Srivatsavai 			    strcmp(state, SCF_STATE_STRING_DISABLED) == 0)
7204eaa4710SRishi Srivatsavai 				umax = 1;
7214eaa4710SRishi Srivatsavai 		}
7224eaa4710SRishi Srivatsavai 		free(state);
7234eaa4710SRishi Srivatsavai 		status = umax != 0 ? DLADM_STATUS_OK : DLADM_STATUS_FAILED;
7244eaa4710SRishi Srivatsavai 	} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
7254eaa4710SRishi Srivatsavai 		free(fmri);
7264eaa4710SRishi Srivatsavai 		return (DLADM_STATUS_OK);
7274eaa4710SRishi Srivatsavai 	} else {
7284eaa4710SRishi Srivatsavai 		status = DLADM_STATUS_FAILED;
7294eaa4710SRishi Srivatsavai 	}
7304eaa4710SRishi Srivatsavai 
7314eaa4710SRishi Srivatsavai 	free(fmri);
7324eaa4710SRishi Srivatsavai 	if (status == DLADM_STATUS_OK && (flags & DLADM_OPT_PERSIST) &&
7334eaa4710SRishi Srivatsavai 	    bind_instance(service_name, instance, &sstate) == 0) {
7344eaa4710SRishi Srivatsavai 		(void) scf_instance_delete(sstate.ss_inst);
7354eaa4710SRishi Srivatsavai 		shut_down_scf(&sstate);
7364eaa4710SRishi Srivatsavai 	}
7374eaa4710SRishi Srivatsavai 
7384eaa4710SRishi Srivatsavai 	return (status);
7394eaa4710SRishi Srivatsavai }
7404eaa4710SRishi Srivatsavai 
7414eaa4710SRishi Srivatsavai static dladm_status_t
disable_trill(const char * instance,uint32_t flags)7424eaa4710SRishi Srivatsavai disable_trill(const char *instance, uint32_t flags)
7434eaa4710SRishi Srivatsavai {
7444eaa4710SRishi Srivatsavai 	return (shut_down_instance(TRILL_SVC_NAME, instance, flags));
7454eaa4710SRishi Srivatsavai }
7464eaa4710SRishi Srivatsavai 
7474eaa4710SRishi Srivatsavai /*
7484eaa4710SRishi Srivatsavai  * To enable TRILL, we must create a new instance of the TRILL service, then
7494eaa4710SRishi Srivatsavai  * add proper dependencies to it, and finally mark it as enabled.  The
7504eaa4710SRishi Srivatsavai  * dependencies will keep it from going on-line until the bridge is running.
7514eaa4710SRishi Srivatsavai  */
7524eaa4710SRishi Srivatsavai static dladm_status_t
enable_trill(const char * instance)7534eaa4710SRishi Srivatsavai enable_trill(const char *instance)
7544eaa4710SRishi Srivatsavai {
7554eaa4710SRishi Srivatsavai 	dladm_status_t status = DLADM_STATUS_FAILED;
7564eaa4710SRishi Srivatsavai 	char *fmri = NULL;
7574eaa4710SRishi Srivatsavai 	scf_state_t sstate;
7584eaa4710SRishi Srivatsavai 	scf_transaction_t *tran = NULL;
7594eaa4710SRishi Srivatsavai 	boolean_t new_instance = B_FALSE;
7604eaa4710SRishi Srivatsavai 	boolean_t new_pg = B_FALSE;
7614eaa4710SRishi Srivatsavai 	int rv;
7624eaa4710SRishi Srivatsavai 
7634eaa4710SRishi Srivatsavai 	/*
7644eaa4710SRishi Srivatsavai 	 * This check is here in case the user has installed and then removed
7654eaa4710SRishi Srivatsavai 	 * the package.  SMF should remove the manifest, but currently does
7664eaa4710SRishi Srivatsavai 	 * not.
7674eaa4710SRishi Srivatsavai 	 */
7684eaa4710SRishi Srivatsavai 	if (access("/usr/sbin/trilld", F_OK) != 0)
7694eaa4710SRishi Srivatsavai 		return (DLADM_STATUS_OPTMISSING);
7704eaa4710SRishi Srivatsavai 
7714eaa4710SRishi Srivatsavai 	if ((status = exact_instance(TRILL_SVC_NAME, &sstate)) !=
7724eaa4710SRishi Srivatsavai 	    DLADM_STATUS_OK)
7734eaa4710SRishi Srivatsavai 		goto out;
7744eaa4710SRishi Srivatsavai 
7754eaa4710SRishi Srivatsavai 	status = DLADM_STATUS_FAILED;
7764eaa4710SRishi Srivatsavai 	if (scf_service_get_instance(sstate.ss_svc, instance, sstate.ss_inst) !=
7774eaa4710SRishi Srivatsavai 	    0) {
7784eaa4710SRishi Srivatsavai 		if (scf_service_add_instance(sstate.ss_svc, instance,
7794eaa4710SRishi Srivatsavai 		    sstate.ss_inst) != 0)
7804eaa4710SRishi Srivatsavai 			goto out;
7814eaa4710SRishi Srivatsavai 		new_instance = B_TRUE;
7824eaa4710SRishi Srivatsavai 	}
7834eaa4710SRishi Srivatsavai 
7844eaa4710SRishi Srivatsavai 	if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL)
7854eaa4710SRishi Srivatsavai 		goto out;
7864eaa4710SRishi Srivatsavai 
7874eaa4710SRishi Srivatsavai 	if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL)
7884eaa4710SRishi Srivatsavai 		goto out;
7894eaa4710SRishi Srivatsavai 
7904eaa4710SRishi Srivatsavai 	if (scf_instance_get_pg(sstate.ss_inst, "bridging",
7914eaa4710SRishi Srivatsavai 	    sstate.ss_pg) == 0) {
7924eaa4710SRishi Srivatsavai 		status = DLADM_STATUS_OK;
7934eaa4710SRishi Srivatsavai 		goto out;
7944eaa4710SRishi Srivatsavai 	}
7954eaa4710SRishi Srivatsavai 
7964eaa4710SRishi Srivatsavai 	if ((fmri = alloc_fmri(BRIDGE_SVC_NAME, instance)) == NULL)
7974eaa4710SRishi Srivatsavai 		goto out;
7984eaa4710SRishi Srivatsavai 
7994eaa4710SRishi Srivatsavai 	if (scf_instance_add_pg(sstate.ss_inst, "bridging",
8004eaa4710SRishi Srivatsavai 	    SCF_GROUP_DEPENDENCY, 0, sstate.ss_pg) != 0)
8014eaa4710SRishi Srivatsavai 		goto out;
8024eaa4710SRishi Srivatsavai 
8034eaa4710SRishi Srivatsavai 	new_pg = B_TRUE;
8044eaa4710SRishi Srivatsavai 	do {
8054eaa4710SRishi Srivatsavai 		if (scf_transaction_start(tran, sstate.ss_pg) != 0)
8064eaa4710SRishi Srivatsavai 			goto out;
8074eaa4710SRishi Srivatsavai 
8084eaa4710SRishi Srivatsavai 		if (!set_string_property(sstate.ss_handle, tran,
8094eaa4710SRishi Srivatsavai 		    SCF_PROPERTY_GROUPING, SCF_DEP_REQUIRE_ALL))
8104eaa4710SRishi Srivatsavai 			goto out;
8114eaa4710SRishi Srivatsavai 		if (!set_string_property(sstate.ss_handle, tran,
8124eaa4710SRishi Srivatsavai 		    SCF_PROPERTY_RESTART_ON, SCF_DEP_RESET_ON_RESTART))
8134eaa4710SRishi Srivatsavai 			goto out;
8144eaa4710SRishi Srivatsavai 		if (!set_string_property(sstate.ss_handle, tran,
8154eaa4710SRishi Srivatsavai 		    SCF_PROPERTY_TYPE, "service"))
8164eaa4710SRishi Srivatsavai 			goto out;
8174eaa4710SRishi Srivatsavai 		if (!set_fmri_property(sstate.ss_handle, tran,
8184eaa4710SRishi Srivatsavai 		    SCF_PROPERTY_ENTITIES, fmri))
8194eaa4710SRishi Srivatsavai 			goto out;
8204eaa4710SRishi Srivatsavai 
8214eaa4710SRishi Srivatsavai 		rv = scf_transaction_commit(tran);
8224eaa4710SRishi Srivatsavai 		scf_transaction_reset(tran);
8234eaa4710SRishi Srivatsavai 		if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1)
8244eaa4710SRishi Srivatsavai 			goto out;
8254eaa4710SRishi Srivatsavai 	} while (rv == 0);
8264eaa4710SRishi Srivatsavai 	if (rv != 1)
8274eaa4710SRishi Srivatsavai 		goto out;
8284eaa4710SRishi Srivatsavai 
8294eaa4710SRishi Srivatsavai 	status = DLADM_STATUS_OK;
8304eaa4710SRishi Srivatsavai 
8314eaa4710SRishi Srivatsavai out:
8324eaa4710SRishi Srivatsavai 	free(fmri);
8334eaa4710SRishi Srivatsavai 	if (tran != NULL) {
8344eaa4710SRishi Srivatsavai 		scf_transaction_destroy_children(tran);
8354eaa4710SRishi Srivatsavai 		scf_transaction_destroy(tran);
8364eaa4710SRishi Srivatsavai 	}
8374eaa4710SRishi Srivatsavai 
8384eaa4710SRishi Srivatsavai 	if (status != DLADM_STATUS_OK && new_pg)
8394eaa4710SRishi Srivatsavai 		(void) scf_pg_delete(sstate.ss_pg);
8404eaa4710SRishi Srivatsavai 
8414eaa4710SRishi Srivatsavai 	drop_composed(&sstate);
8424eaa4710SRishi Srivatsavai 
8434eaa4710SRishi Srivatsavai 	/*
8444eaa4710SRishi Srivatsavai 	 * If we created an instance and then failed, then remove the instance
8454eaa4710SRishi Srivatsavai 	 * from the system.
8464eaa4710SRishi Srivatsavai 	 */
8474eaa4710SRishi Srivatsavai 	if (status != DLADM_STATUS_OK && new_instance)
8484eaa4710SRishi Srivatsavai 		(void) scf_instance_delete(sstate.ss_inst);
8494eaa4710SRishi Srivatsavai 
8504eaa4710SRishi Srivatsavai 	shut_down_scf(&sstate);
8514eaa4710SRishi Srivatsavai 
8524eaa4710SRishi Srivatsavai 	if (status == DLADM_STATUS_OK)
8534eaa4710SRishi Srivatsavai 		status = enable_instance(TRILL_SVC_NAME, instance);
8544eaa4710SRishi Srivatsavai 
8554eaa4710SRishi Srivatsavai 	return (status);
8564eaa4710SRishi Srivatsavai }
8574eaa4710SRishi Srivatsavai 
8584eaa4710SRishi Srivatsavai /*
8594eaa4710SRishi Srivatsavai  * Create a new bridge or modify an existing one.  Update the SMF configuration
8604eaa4710SRishi Srivatsavai  * and add links.
8614eaa4710SRishi Srivatsavai  *
8624eaa4710SRishi Srivatsavai  * Input timer values are in IEEE scaled (* 256) format.
8634eaa4710SRishi Srivatsavai  */
8644eaa4710SRishi Srivatsavai dladm_status_t
dladm_bridge_configure(dladm_handle_t handle,const char * name,const UID_STP_CFG_T * cfg,dladm_bridge_prot_t brprot,uint32_t flags)8654eaa4710SRishi Srivatsavai dladm_bridge_configure(dladm_handle_t handle, const char *name,
8664eaa4710SRishi Srivatsavai     const UID_STP_CFG_T *cfg, dladm_bridge_prot_t brprot, uint32_t flags)
8674eaa4710SRishi Srivatsavai {
8684eaa4710SRishi Srivatsavai 	dladm_status_t status;
8694eaa4710SRishi Srivatsavai 	scf_state_t sstate;
8704eaa4710SRishi Srivatsavai 	scf_transaction_t *tran = NULL;
8714eaa4710SRishi Srivatsavai 	boolean_t new_instance = B_FALSE;
8724eaa4710SRishi Srivatsavai 	boolean_t new_pg = B_FALSE;
8734eaa4710SRishi Srivatsavai 	datalink_id_t linkid = DATALINK_INVALID_LINKID;
8744eaa4710SRishi Srivatsavai 	char linkname[MAXLINKNAMELEN];
8754eaa4710SRishi Srivatsavai 	int rv;
8764eaa4710SRishi Srivatsavai 
8774eaa4710SRishi Srivatsavai 	if (!dladm_valid_bridgename(name))
8784eaa4710SRishi Srivatsavai 		return (DLADM_STATUS_FAILED);
8794eaa4710SRishi Srivatsavai 
8804eaa4710SRishi Srivatsavai 	if (flags & DLADM_OPT_CREATE) {
8814eaa4710SRishi Srivatsavai 		/*
8824eaa4710SRishi Srivatsavai 		 * This check is here in case the user has installed and then
8834eaa4710SRishi Srivatsavai 		 * removed the package.  SMF should remove the manifest, but
8844eaa4710SRishi Srivatsavai 		 * currently does not.
8854eaa4710SRishi Srivatsavai 		 */
8864eaa4710SRishi Srivatsavai 		if (access("/usr/lib/bridged", F_OK) != 0)
8874eaa4710SRishi Srivatsavai 			return (DLADM_STATUS_OPTMISSING);
8884eaa4710SRishi Srivatsavai 
8894eaa4710SRishi Srivatsavai 		(void) snprintf(linkname, sizeof (linkname), "%s0", name);
8904eaa4710SRishi Srivatsavai 		status = dladm_create_datalink_id(handle, linkname,
8914eaa4710SRishi Srivatsavai 		    DATALINK_CLASS_BRIDGE, DL_ETHER,
8924eaa4710SRishi Srivatsavai 		    flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST), &linkid);
8934eaa4710SRishi Srivatsavai 		if (status != DLADM_STATUS_OK)
8944eaa4710SRishi Srivatsavai 			return (status);
8954eaa4710SRishi Srivatsavai 
8964eaa4710SRishi Srivatsavai 		if ((flags & DLADM_OPT_PERSIST) &&
8974eaa4710SRishi Srivatsavai 		    (status = dladm_bridge_persist_conf(handle, linkname,
8984eaa4710SRishi Srivatsavai 		    linkid) != DLADM_STATUS_OK))
8994eaa4710SRishi Srivatsavai 			goto dladm_fail;
9004eaa4710SRishi Srivatsavai 	}
9014eaa4710SRishi Srivatsavai 
9024eaa4710SRishi Srivatsavai 	if (brprot == DLADM_BRIDGE_PROT_TRILL)
9034eaa4710SRishi Srivatsavai 		status = enable_trill(name);
9044eaa4710SRishi Srivatsavai 	else
9054eaa4710SRishi Srivatsavai 		status = disable_trill(name, flags);
9064eaa4710SRishi Srivatsavai 	if (status != DLADM_STATUS_OK)
9074eaa4710SRishi Srivatsavai 		goto dladm_fail;
9084eaa4710SRishi Srivatsavai 
9094eaa4710SRishi Srivatsavai 	if ((status = exact_instance(BRIDGE_SVC_NAME, &sstate)) !=
9104eaa4710SRishi Srivatsavai 	    DLADM_STATUS_OK)
9114eaa4710SRishi Srivatsavai 		goto out;
9124eaa4710SRishi Srivatsavai 
9134eaa4710SRishi Srivatsavai 	/* set up for a series of scf calls */
9144eaa4710SRishi Srivatsavai 	status = DLADM_STATUS_FAILED;
9154eaa4710SRishi Srivatsavai 
9164eaa4710SRishi Srivatsavai 	if (scf_service_get_instance(sstate.ss_svc, name, sstate.ss_inst) ==
9174eaa4710SRishi Srivatsavai 	    0) {
9184eaa4710SRishi Srivatsavai 		if (flags & DLADM_OPT_CREATE) {
9194eaa4710SRishi Srivatsavai 			status = DLADM_STATUS_EXIST;
9204eaa4710SRishi Srivatsavai 			goto out;
9214eaa4710SRishi Srivatsavai 		}
9224eaa4710SRishi Srivatsavai 	} else {
9234eaa4710SRishi Srivatsavai 		if (!(flags & DLADM_OPT_CREATE)) {
9244eaa4710SRishi Srivatsavai 			status = DLADM_STATUS_NOTFOUND;
9254eaa4710SRishi Srivatsavai 			goto out;
9264eaa4710SRishi Srivatsavai 		}
9274eaa4710SRishi Srivatsavai 		if (scf_service_add_instance(sstate.ss_svc, name,
9284eaa4710SRishi Srivatsavai 		    sstate.ss_inst) != 0)
9294eaa4710SRishi Srivatsavai 			goto out;
9304eaa4710SRishi Srivatsavai 		new_instance = B_TRUE;
9314eaa4710SRishi Srivatsavai 	}
9324eaa4710SRishi Srivatsavai 
9334eaa4710SRishi Srivatsavai 	if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL)
9344eaa4710SRishi Srivatsavai 		goto out;
9354eaa4710SRishi Srivatsavai 
936*0663b557SToomas Soome 	if (cfg->field_mask & (BR_CFG_ALL)) {
9374eaa4710SRishi Srivatsavai 		if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL)
9384eaa4710SRishi Srivatsavai 			goto out;
9394eaa4710SRishi Srivatsavai 		if (scf_instance_add_pg(sstate.ss_inst, "config",
9404eaa4710SRishi Srivatsavai 		    SCF_GROUP_APPLICATION, 0, sstate.ss_pg) == 0) {
9414eaa4710SRishi Srivatsavai 			new_pg = B_TRUE;
9424eaa4710SRishi Srivatsavai 		} else if (scf_instance_get_pg(sstate.ss_inst, "config",
9434eaa4710SRishi Srivatsavai 		    sstate.ss_pg) != 0) {
9444eaa4710SRishi Srivatsavai 			goto out;
9454eaa4710SRishi Srivatsavai 		}
9464eaa4710SRishi Srivatsavai 		do {
9474eaa4710SRishi Srivatsavai 			if (scf_transaction_start(tran, sstate.ss_pg) != 0)
9484eaa4710SRishi Srivatsavai 				goto out;
9494eaa4710SRishi Srivatsavai 
9504eaa4710SRishi Srivatsavai 			if ((cfg->field_mask & BR_CFG_PRIO) &&
9514eaa4710SRishi Srivatsavai 			    !set_count_property(sstate.ss_handle, tran,
9524eaa4710SRishi Srivatsavai 			    "priority", cfg->bridge_priority))
9534eaa4710SRishi Srivatsavai 				goto out;
9544eaa4710SRishi Srivatsavai 			if ((cfg->field_mask & BR_CFG_AGE) &&
9554eaa4710SRishi Srivatsavai 			    !set_count_property(sstate.ss_handle, tran,
9564eaa4710SRishi Srivatsavai 			    "max-age", cfg->max_age * IEEE_TIMER_SCALE))
9574eaa4710SRishi Srivatsavai 				goto out;
9584eaa4710SRishi Srivatsavai 			if ((cfg->field_mask & BR_CFG_HELLO) &&
9594eaa4710SRishi Srivatsavai 			    !set_count_property(sstate.ss_handle, tran,
9604eaa4710SRishi Srivatsavai 			    "hello-time", cfg->hello_time * IEEE_TIMER_SCALE))
9614eaa4710SRishi Srivatsavai 				goto out;
9624eaa4710SRishi Srivatsavai 			if ((cfg->field_mask & BR_CFG_DELAY) &&
9634eaa4710SRishi Srivatsavai 			    !set_count_property(sstate.ss_handle, tran,
9644eaa4710SRishi Srivatsavai 			    "forward-delay",
9654eaa4710SRishi Srivatsavai 			    cfg->forward_delay * IEEE_TIMER_SCALE))
9664eaa4710SRishi Srivatsavai 				goto out;
9674eaa4710SRishi Srivatsavai 			if ((cfg->field_mask & BR_CFG_FORCE_VER) &&
9684eaa4710SRishi Srivatsavai 			    !set_count_property(sstate.ss_handle, tran,
9694eaa4710SRishi Srivatsavai 			    "force-protocol", cfg->force_version))
9704eaa4710SRishi Srivatsavai 				goto out;
9714eaa4710SRishi Srivatsavai 
9724eaa4710SRishi Srivatsavai 			rv = scf_transaction_commit(tran);
9734eaa4710SRishi Srivatsavai 			scf_transaction_reset(tran);
9744eaa4710SRishi Srivatsavai 			if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1)
9754eaa4710SRishi Srivatsavai 				goto out;
9764eaa4710SRishi Srivatsavai 		} while (rv == 0);
9774eaa4710SRishi Srivatsavai 		if (rv != 1)
9784eaa4710SRishi Srivatsavai 			goto out;
9794eaa4710SRishi Srivatsavai 	}
9804eaa4710SRishi Srivatsavai 
9814eaa4710SRishi Srivatsavai 	/*
9824eaa4710SRishi Srivatsavai 	 * If we're modifying an existing and running bridge, then tell the
9834eaa4710SRishi Srivatsavai 	 * daemon to update the requested values.
9844eaa4710SRishi Srivatsavai 	 */
9854eaa4710SRishi Srivatsavai 	if ((flags & DLADM_OPT_ACTIVE) && !(flags & DLADM_OPT_CREATE))
9864eaa4710SRishi Srivatsavai 		status = bridge_refresh(name);
9874eaa4710SRishi Srivatsavai 	else
9884eaa4710SRishi Srivatsavai 		status = DLADM_STATUS_OK;
9894eaa4710SRishi Srivatsavai 
9904eaa4710SRishi Srivatsavai out:
9914eaa4710SRishi Srivatsavai 	if (tran != NULL) {
9924eaa4710SRishi Srivatsavai 		scf_transaction_destroy_children(tran);
9934eaa4710SRishi Srivatsavai 		scf_transaction_destroy(tran);
9944eaa4710SRishi Srivatsavai 	}
9954eaa4710SRishi Srivatsavai 
9964eaa4710SRishi Srivatsavai 	if (status != DLADM_STATUS_OK && new_pg)
9974eaa4710SRishi Srivatsavai 		(void) scf_pg_delete(sstate.ss_pg);
9984eaa4710SRishi Srivatsavai 
9994eaa4710SRishi Srivatsavai 	drop_composed(&sstate);
10004eaa4710SRishi Srivatsavai 
10014eaa4710SRishi Srivatsavai 	/*
10024eaa4710SRishi Srivatsavai 	 * If we created an instance and then failed, then remove the instance
10034eaa4710SRishi Srivatsavai 	 * from the system.
10044eaa4710SRishi Srivatsavai 	 */
10054eaa4710SRishi Srivatsavai 	if (status != DLADM_STATUS_OK && new_instance)
10064eaa4710SRishi Srivatsavai 		(void) scf_instance_delete(sstate.ss_inst);
10074eaa4710SRishi Srivatsavai 
10084eaa4710SRishi Srivatsavai 	shut_down_scf(&sstate);
10094eaa4710SRishi Srivatsavai 
10104eaa4710SRishi Srivatsavai 	/*
10114eaa4710SRishi Srivatsavai 	 * Remove the bridge linkid if we've allocated one in this function but
10124eaa4710SRishi Srivatsavai 	 * we've failed to set up the SMF properties.
10134eaa4710SRishi Srivatsavai 	 */
10144eaa4710SRishi Srivatsavai dladm_fail:
10154eaa4710SRishi Srivatsavai 	if (status != DLADM_STATUS_OK && linkid != DATALINK_INVALID_LINKID) {
10164eaa4710SRishi Srivatsavai 		(void) dladm_remove_conf(handle, linkid);
10174eaa4710SRishi Srivatsavai 		(void) dladm_destroy_datalink_id(handle, linkid, flags);
10184eaa4710SRishi Srivatsavai 	}
10194eaa4710SRishi Srivatsavai 
10204eaa4710SRishi Srivatsavai 	return (status);
10214eaa4710SRishi Srivatsavai }
10224eaa4710SRishi Srivatsavai 
10234eaa4710SRishi Srivatsavai /*
10244eaa4710SRishi Srivatsavai  * Enable a newly-created bridge in SMF by creating "general/enabled" and
10254eaa4710SRishi Srivatsavai  * deleting any "general_ovr/enabled" (used for temporary services).
10264eaa4710SRishi Srivatsavai  */
10274eaa4710SRishi Srivatsavai dladm_status_t
dladm_bridge_enable(const char * name)10284eaa4710SRishi Srivatsavai dladm_bridge_enable(const char *name)
10294eaa4710SRishi Srivatsavai {
10304eaa4710SRishi Srivatsavai 	return (enable_instance(BRIDGE_SVC_NAME, name));
10314eaa4710SRishi Srivatsavai }
10324eaa4710SRishi Srivatsavai 
10334eaa4710SRishi Srivatsavai /*
10344eaa4710SRishi Srivatsavai  * Set a link as a member of a bridge, or remove bridge membership.  If the
10354eaa4710SRishi Srivatsavai  * DLADM_OPT_CREATE flag is set, then we assume that the daemon isn't running.
10364eaa4710SRishi Srivatsavai  * In all other cases, we must tell the daemon to add or delete the link in
10374eaa4710SRishi Srivatsavai  * order to stay in sync.
10384eaa4710SRishi Srivatsavai  */
10394eaa4710SRishi Srivatsavai dladm_status_t
dladm_bridge_setlink(dladm_handle_t handle,datalink_id_t linkid,const char * bridge)10404eaa4710SRishi Srivatsavai dladm_bridge_setlink(dladm_handle_t handle, datalink_id_t linkid,
10414eaa4710SRishi Srivatsavai     const char *bridge)
10424eaa4710SRishi Srivatsavai {
10434eaa4710SRishi Srivatsavai 	dladm_status_t status;
10444eaa4710SRishi Srivatsavai 	dladm_conf_t conf;
10454eaa4710SRishi Srivatsavai 	char oldbridge[MAXLINKNAMELEN];
10464eaa4710SRishi Srivatsavai 	boolean_t has_oldbridge;
10474eaa4710SRishi Srivatsavai 	boolean_t changed = B_FALSE;
10484eaa4710SRishi Srivatsavai 
10494eaa4710SRishi Srivatsavai 	if (*bridge != '\0' && !dladm_valid_bridgename(bridge))
10504eaa4710SRishi Srivatsavai 		return (DLADM_STATUS_FAILED);
10514eaa4710SRishi Srivatsavai 
105232715170SCathy Zhou 	status = dladm_open_conf(handle, linkid, &conf);
105332715170SCathy Zhou 	if (status != DLADM_STATUS_OK)
10544eaa4710SRishi Srivatsavai 		return (status);
10554eaa4710SRishi Srivatsavai 
10564eaa4710SRishi Srivatsavai 	has_oldbridge = B_FALSE;
10574eaa4710SRishi Srivatsavai 	status = dladm_get_conf_field(handle, conf, FBRIDGE, oldbridge,
10584eaa4710SRishi Srivatsavai 	    sizeof (oldbridge));
10594eaa4710SRishi Srivatsavai 	if (status == DLADM_STATUS_OK) {
10604eaa4710SRishi Srivatsavai 		/*
10614eaa4710SRishi Srivatsavai 		 * Don't allow a link to be reassigned directly from one bridge
10624eaa4710SRishi Srivatsavai 		 * to another.  It must be removed first.
10634eaa4710SRishi Srivatsavai 		 */
10644eaa4710SRishi Srivatsavai 		if (*oldbridge != '\0' && *bridge != '\0') {
10654eaa4710SRishi Srivatsavai 			status = DLADM_STATUS_EXIST;
10664eaa4710SRishi Srivatsavai 			goto out;
10674eaa4710SRishi Srivatsavai 		}
10684eaa4710SRishi Srivatsavai 		has_oldbridge = B_TRUE;
10694eaa4710SRishi Srivatsavai 	} else if (status != DLADM_STATUS_NOTFOUND) {
10704eaa4710SRishi Srivatsavai 		goto out;
10714eaa4710SRishi Srivatsavai 	}
10724eaa4710SRishi Srivatsavai 
10734eaa4710SRishi Srivatsavai 	if (*bridge != '\0') {
10744eaa4710SRishi Srivatsavai 		status = dladm_set_conf_field(handle, conf, FBRIDGE,
10754eaa4710SRishi Srivatsavai 		    DLADM_TYPE_STR, bridge);
10764eaa4710SRishi Srivatsavai 		changed = B_TRUE;
10774eaa4710SRishi Srivatsavai 	} else if (has_oldbridge) {
10784eaa4710SRishi Srivatsavai 		status = dladm_unset_conf_field(handle, conf, FBRIDGE);
10794eaa4710SRishi Srivatsavai 		changed = B_TRUE;
10804eaa4710SRishi Srivatsavai 	} else {
10814eaa4710SRishi Srivatsavai 		status = DLADM_STATUS_OK;
10824eaa4710SRishi Srivatsavai 		goto out;
10834eaa4710SRishi Srivatsavai 	}
10844eaa4710SRishi Srivatsavai 	if (status == DLADM_STATUS_OK)
10854eaa4710SRishi Srivatsavai 		status = dladm_write_conf(handle, conf);
10864eaa4710SRishi Srivatsavai 
10874eaa4710SRishi Srivatsavai out:
10884eaa4710SRishi Srivatsavai 	dladm_destroy_conf(handle, conf);
10894eaa4710SRishi Srivatsavai 	if (changed && status == DLADM_STATUS_OK) {
10904eaa4710SRishi Srivatsavai 		if (bridge[0] == '\0')
10914eaa4710SRishi Srivatsavai 			bridge = oldbridge;
10924eaa4710SRishi Srivatsavai 		status = bridge_refresh(bridge);
10934eaa4710SRishi Srivatsavai 	}
10944eaa4710SRishi Srivatsavai 	return (status);
10954eaa4710SRishi Srivatsavai }
10964eaa4710SRishi Srivatsavai 
10974eaa4710SRishi Srivatsavai /*
10984eaa4710SRishi Srivatsavai  * Get the name of the bridge of which the given linkid is a member.
10994eaa4710SRishi Srivatsavai  */
11004eaa4710SRishi Srivatsavai dladm_status_t
dladm_bridge_getlink(dladm_handle_t handle,datalink_id_t linkid,char * bridge,size_t bridgelen)11014eaa4710SRishi Srivatsavai dladm_bridge_getlink(dladm_handle_t handle, datalink_id_t linkid, char *bridge,
11024eaa4710SRishi Srivatsavai     size_t bridgelen)
11034eaa4710SRishi Srivatsavai {
11044eaa4710SRishi Srivatsavai 	dladm_status_t status;
11054eaa4710SRishi Srivatsavai 	dladm_conf_t conf;
11064eaa4710SRishi Srivatsavai 
110732715170SCathy Zhou 	if ((status = dladm_getsnap_conf(handle, linkid, &conf)) !=
11084eaa4710SRishi Srivatsavai 	    DLADM_STATUS_OK)
11094eaa4710SRishi Srivatsavai 		return (status);
11104eaa4710SRishi Srivatsavai 
11114eaa4710SRishi Srivatsavai 	*bridge = '\0';
11124eaa4710SRishi Srivatsavai 	status = dladm_get_conf_field(handle, conf, FBRIDGE, bridge, bridgelen);
11134eaa4710SRishi Srivatsavai 	if (status == DLADM_STATUS_OK && *bridge == '\0')
11144eaa4710SRishi Srivatsavai 		status = DLADM_STATUS_NOTFOUND;
11154eaa4710SRishi Srivatsavai 
11164eaa4710SRishi Srivatsavai 	dladm_destroy_conf(handle, conf);
11174eaa4710SRishi Srivatsavai 	return (status);
11184eaa4710SRishi Srivatsavai }
11194eaa4710SRishi Srivatsavai 
11204eaa4710SRishi Srivatsavai dladm_status_t
dladm_bridge_refresh(dladm_handle_t handle,datalink_id_t linkid)11214eaa4710SRishi Srivatsavai dladm_bridge_refresh(dladm_handle_t handle, datalink_id_t linkid)
11224eaa4710SRishi Srivatsavai {
11234eaa4710SRishi Srivatsavai 	char bridge[MAXLINKNAMELEN];
11244eaa4710SRishi Srivatsavai 	dladm_status_t status;
11254eaa4710SRishi Srivatsavai 
11264eaa4710SRishi Srivatsavai 	status = dladm_bridge_getlink(handle, linkid, bridge, sizeof (bridge));
11274eaa4710SRishi Srivatsavai 	if (status == DLADM_STATUS_NOTFOUND)
11284eaa4710SRishi Srivatsavai 		return (DLADM_STATUS_OK);
11294eaa4710SRishi Srivatsavai 	if (status == DLADM_STATUS_OK)
11304eaa4710SRishi Srivatsavai 		status = bridge_refresh(bridge);
11314eaa4710SRishi Srivatsavai 	return (status);
11324eaa4710SRishi Srivatsavai }
11334eaa4710SRishi Srivatsavai 
11344eaa4710SRishi Srivatsavai typedef struct bridge_held_arg_s {
11354eaa4710SRishi Srivatsavai 	const char	*bha_bridge;
11364eaa4710SRishi Srivatsavai 	boolean_t	bha_isheld;
11374eaa4710SRishi Srivatsavai } bridge_held_arg_t;
11384eaa4710SRishi Srivatsavai 
11394eaa4710SRishi Srivatsavai static int
i_dladm_bridge_is_held(dladm_handle_t handle,datalink_id_t linkid,void * arg)11404eaa4710SRishi Srivatsavai i_dladm_bridge_is_held(dladm_handle_t handle, datalink_id_t linkid, void *arg)
11414eaa4710SRishi Srivatsavai {
11424eaa4710SRishi Srivatsavai 	dladm_status_t status = DLADM_STATUS_FAILED;
11434eaa4710SRishi Srivatsavai 	dladm_conf_t conf;
11444eaa4710SRishi Srivatsavai 	char bridge[MAXLINKNAMELEN];
114532715170SCathy Zhou 	bridge_held_arg_t *bha = arg;
11464eaa4710SRishi Srivatsavai 
114732715170SCathy Zhou 	if ((status = dladm_getsnap_conf(handle, linkid, &conf)) !=
11484eaa4710SRishi Srivatsavai 	    DLADM_STATUS_OK)
11494eaa4710SRishi Srivatsavai 		return (DLADM_WALK_CONTINUE);
11504eaa4710SRishi Srivatsavai 	status = dladm_get_conf_field(handle, conf, FBRIDGE, bridge,
11514eaa4710SRishi Srivatsavai 	    sizeof (bridge));
11524eaa4710SRishi Srivatsavai 	if (status == DLADM_STATUS_OK && strcmp(bha->bha_bridge, bridge) == 0) {
11534eaa4710SRishi Srivatsavai 		bha->bha_isheld = B_TRUE;
11544eaa4710SRishi Srivatsavai 		dladm_destroy_conf(handle, conf);
11554eaa4710SRishi Srivatsavai 		return (DLADM_WALK_TERMINATE);
11564eaa4710SRishi Srivatsavai 	} else {
11574eaa4710SRishi Srivatsavai 		dladm_destroy_conf(handle, conf);
11584eaa4710SRishi Srivatsavai 		return (DLADM_WALK_CONTINUE);
11594eaa4710SRishi Srivatsavai 	}
11604eaa4710SRishi Srivatsavai }
11614eaa4710SRishi Srivatsavai 
11624eaa4710SRishi Srivatsavai /*
11634eaa4710SRishi Srivatsavai  * Delete a previously created bridge.
11644eaa4710SRishi Srivatsavai  */
11654eaa4710SRishi Srivatsavai dladm_status_t
dladm_bridge_delete(dladm_handle_t handle,const char * bridge,uint32_t flags)11664eaa4710SRishi Srivatsavai dladm_bridge_delete(dladm_handle_t handle, const char *bridge, uint32_t flags)
11674eaa4710SRishi Srivatsavai {
11684eaa4710SRishi Srivatsavai 	datalink_id_t linkid;
11694eaa4710SRishi Srivatsavai 	datalink_class_t class;
11704eaa4710SRishi Srivatsavai 	dladm_status_t status;
11714eaa4710SRishi Srivatsavai 	char linkname[MAXLINKNAMELEN];
11724eaa4710SRishi Srivatsavai 
11734eaa4710SRishi Srivatsavai 	if (!dladm_valid_bridgename(bridge))
11744eaa4710SRishi Srivatsavai 		return (DLADM_STATUS_LINKINVAL);
11754eaa4710SRishi Srivatsavai 
11764eaa4710SRishi Srivatsavai 	/* Get the datalink ID for this bridge */
11774eaa4710SRishi Srivatsavai 	(void) snprintf(linkname, sizeof (linkname), "%s0", bridge);
11784eaa4710SRishi Srivatsavai 	if (dladm_name2info(handle, linkname, &linkid, NULL, NULL, NULL) !=
11794eaa4710SRishi Srivatsavai 	    DLADM_STATUS_OK)
11804eaa4710SRishi Srivatsavai 		linkid = DATALINK_INVALID_LINKID;
11814eaa4710SRishi Srivatsavai 	else if (dladm_datalink_id2info(handle, linkid, NULL, &class, NULL,
11824eaa4710SRishi Srivatsavai 	    NULL, 0) != DLADM_STATUS_OK)
11834eaa4710SRishi Srivatsavai 		linkid = DATALINK_INVALID_LINKID;
11844eaa4710SRishi Srivatsavai 	else if (class != DATALINK_CLASS_BRIDGE)
11854eaa4710SRishi Srivatsavai 		return (DLADM_STATUS_BADARG);
11864eaa4710SRishi Srivatsavai 
11874eaa4710SRishi Srivatsavai 	if ((flags & DLADM_OPT_ACTIVE) && linkid == DATALINK_INVALID_LINKID)
11884eaa4710SRishi Srivatsavai 		return (DLADM_STATUS_BADARG);
11894eaa4710SRishi Srivatsavai 
11904eaa4710SRishi Srivatsavai 	if (flags & DLADM_OPT_PERSIST) {
11914eaa4710SRishi Srivatsavai 		bridge_held_arg_t arg;
11924eaa4710SRishi Srivatsavai 
11934eaa4710SRishi Srivatsavai 		arg.bha_bridge = bridge;
11944eaa4710SRishi Srivatsavai 		arg.bha_isheld = B_FALSE;
11954eaa4710SRishi Srivatsavai 
11964eaa4710SRishi Srivatsavai 		/*
11974eaa4710SRishi Srivatsavai 		 * See whether there are any persistent links using this
11984eaa4710SRishi Srivatsavai 		 * bridge.  If so, we fail the operation.
11994eaa4710SRishi Srivatsavai 		 */
12004eaa4710SRishi Srivatsavai 		(void) dladm_walk_datalink_id(i_dladm_bridge_is_held, handle,
12014eaa4710SRishi Srivatsavai 		    &arg, DATALINK_CLASS_PHYS | DATALINK_CLASS_AGGR |
12024eaa4710SRishi Srivatsavai 		    DATALINK_CLASS_ETHERSTUB | DATALINK_CLASS_SIMNET,
12034eaa4710SRishi Srivatsavai 		    DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
12044eaa4710SRishi Srivatsavai 		if (arg.bha_isheld)
12054eaa4710SRishi Srivatsavai 			return (DLADM_STATUS_LINKBUSY);
12064eaa4710SRishi Srivatsavai 	}
12074eaa4710SRishi Srivatsavai 
12084eaa4710SRishi Srivatsavai 	if ((status = disable_trill(bridge, flags)) != DLADM_STATUS_OK)
12094eaa4710SRishi Srivatsavai 		goto out;
12104eaa4710SRishi Srivatsavai 
12114eaa4710SRishi Srivatsavai 	/* Disable or remove the SMF instance */
12124eaa4710SRishi Srivatsavai 	status = shut_down_instance(BRIDGE_SVC_NAME, bridge, flags);
12134eaa4710SRishi Srivatsavai 	if (status != DLADM_STATUS_OK)
12144eaa4710SRishi Srivatsavai 		goto out;
12154eaa4710SRishi Srivatsavai 
12164eaa4710SRishi Srivatsavai 	if (flags & DLADM_OPT_ACTIVE) {
12174eaa4710SRishi Srivatsavai 		/*
12184eaa4710SRishi Srivatsavai 		 * Delete ACTIVE linkprop now that daemon is gone.
12194eaa4710SRishi Srivatsavai 		 */
12204eaa4710SRishi Srivatsavai 		(void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0,
12214eaa4710SRishi Srivatsavai 		    DLADM_OPT_ACTIVE);
12224eaa4710SRishi Srivatsavai 		(void) dladm_destroy_datalink_id(handle, linkid,
12234eaa4710SRishi Srivatsavai 		    DLADM_OPT_ACTIVE);
12244eaa4710SRishi Srivatsavai 	}
12254eaa4710SRishi Srivatsavai 
12264eaa4710SRishi Srivatsavai 	if (flags & DLADM_OPT_PERSIST) {
12274eaa4710SRishi Srivatsavai 		(void) dladm_remove_conf(handle, linkid);
12284eaa4710SRishi Srivatsavai 		(void) dladm_destroy_datalink_id(handle, linkid,
12294eaa4710SRishi Srivatsavai 		    DLADM_OPT_PERSIST);
12304eaa4710SRishi Srivatsavai 	}
12314eaa4710SRishi Srivatsavai 
12324eaa4710SRishi Srivatsavai out:
12334eaa4710SRishi Srivatsavai 
12344eaa4710SRishi Srivatsavai 	return (status);
12354eaa4710SRishi Srivatsavai }
12364eaa4710SRishi Srivatsavai 
12374eaa4710SRishi Srivatsavai /* Check if given name is valid for bridges */
12384eaa4710SRishi Srivatsavai boolean_t
dladm_valid_bridgename(const char * bridge)12394eaa4710SRishi Srivatsavai dladm_valid_bridgename(const char *bridge)
12404eaa4710SRishi Srivatsavai {
12414eaa4710SRishi Srivatsavai 	size_t		len = strnlen(bridge, MAXLINKNAMELEN);
12424eaa4710SRishi Srivatsavai 	const char	*cp;
12434eaa4710SRishi Srivatsavai 
12444eaa4710SRishi Srivatsavai 	if (len == MAXLINKNAMELEN)
12454eaa4710SRishi Srivatsavai 		return (B_FALSE);
12464eaa4710SRishi Srivatsavai 
12474eaa4710SRishi Srivatsavai 	/*
12484eaa4710SRishi Srivatsavai 	 * The bridge name cannot start or end with a digit.
12494eaa4710SRishi Srivatsavai 	 */
12504eaa4710SRishi Srivatsavai 	if (isdigit(bridge[0]) || isdigit(bridge[len - 1]))
12514eaa4710SRishi Srivatsavai 		return (B_FALSE);
12524eaa4710SRishi Srivatsavai 
12534eaa4710SRishi Srivatsavai 	/*
12544eaa4710SRishi Srivatsavai 	 * The legal characters within a bridge name are:
12554eaa4710SRishi Srivatsavai 	 * alphanumeric (a-z,  A-Z,  0-9), and the underscore ('_').
12564eaa4710SRishi Srivatsavai 	 */
12574eaa4710SRishi Srivatsavai 	for (cp = bridge; *cp != '\0'; cp++) {
12584eaa4710SRishi Srivatsavai 		if (!isalnum(*cp) && *cp != '_')
12594eaa4710SRishi Srivatsavai 			return (B_FALSE);
12604eaa4710SRishi Srivatsavai 	}
12614eaa4710SRishi Srivatsavai 
12624eaa4710SRishi Srivatsavai 	return (B_TRUE);
12634eaa4710SRishi Srivatsavai }
12644eaa4710SRishi Srivatsavai 
12654eaa4710SRishi Srivatsavai /*
12664eaa4710SRishi Srivatsavai  * Convert a bridge-related observability node name back into the name of the
12674eaa4710SRishi Srivatsavai  * bridge.  Returns B_FALSE without making changes if the input name is not in
12684eaa4710SRishi Srivatsavai  * a legal format.
12694eaa4710SRishi Srivatsavai  */
12704eaa4710SRishi Srivatsavai boolean_t
dladm_observe_to_bridge(char * link)12714eaa4710SRishi Srivatsavai dladm_observe_to_bridge(char *link)
12724eaa4710SRishi Srivatsavai {
12734eaa4710SRishi Srivatsavai 	int llen;
12744eaa4710SRishi Srivatsavai 
12754eaa4710SRishi Srivatsavai 	llen = strnlen(link, MAXLINKNAMELEN);
12764eaa4710SRishi Srivatsavai 	if (llen < 2 || link[llen - 1] != '0' || isdigit(link[llen - 2]))
12774eaa4710SRishi Srivatsavai 		return (B_FALSE);
12784eaa4710SRishi Srivatsavai 	link[llen - 1] = '\0';
12794eaa4710SRishi Srivatsavai 	return (B_TRUE);
12804eaa4710SRishi Srivatsavai }
12814eaa4710SRishi Srivatsavai 
12824eaa4710SRishi Srivatsavai /*
12834eaa4710SRishi Srivatsavai  * Get bridge property values from the running daemon and return them in a
12844eaa4710SRishi Srivatsavai  * common structure.
12854eaa4710SRishi Srivatsavai  */
12864eaa4710SRishi Srivatsavai dladm_status_t
dladm_bridge_run_properties(const char * instname,UID_STP_CFG_T * smcfg,dladm_bridge_prot_t * brprotp)12874eaa4710SRishi Srivatsavai dladm_bridge_run_properties(const char *instname, UID_STP_CFG_T *smcfg,
12884eaa4710SRishi Srivatsavai     dladm_bridge_prot_t *brprotp)
12894eaa4710SRishi Srivatsavai {
12904eaa4710SRishi Srivatsavai 	dladm_status_t status;
12914eaa4710SRishi Srivatsavai 	bridge_door_cfg_t bdcf;
12924eaa4710SRishi Srivatsavai 	bridge_door_cfg_t *bdcfp = &bdcf;
12934eaa4710SRishi Srivatsavai 	size_t buflen = sizeof (bdcf);
12944eaa4710SRishi Srivatsavai 
12954eaa4710SRishi Srivatsavai 	status = bridge_door_call(instname, bdcBridgeGetConfig,
12964eaa4710SRishi Srivatsavai 	    DATALINK_INVALID_LINKID, (void **)&bdcfp, 0, &buflen, B_FALSE);
12974eaa4710SRishi Srivatsavai 	if (status == DLADM_STATUS_OK) {
12984eaa4710SRishi Srivatsavai 		*smcfg = bdcfp->bdcf_cfg;
12994eaa4710SRishi Srivatsavai 		*brprotp = bdcfp->bdcf_prot;
13004eaa4710SRishi Srivatsavai 	} else {
13014eaa4710SRishi Srivatsavai 		smcfg->field_mask = 0;
13024eaa4710SRishi Srivatsavai 		*brprotp = DLADM_BRIDGE_PROT_STP;
13034eaa4710SRishi Srivatsavai 	}
13044eaa4710SRishi Srivatsavai 	return (status);
13054eaa4710SRishi Srivatsavai }
13064eaa4710SRishi Srivatsavai 
13074eaa4710SRishi Srivatsavai /*
13084eaa4710SRishi Srivatsavai  * Get bridge state from the running daemon and return in structure borrowed
13094eaa4710SRishi Srivatsavai  * from librstp.
13104eaa4710SRishi Srivatsavai  */
13114eaa4710SRishi Srivatsavai dladm_status_t
dladm_bridge_state(const char * instname,UID_STP_STATE_T * statep)13124eaa4710SRishi Srivatsavai dladm_bridge_state(const char *instname, UID_STP_STATE_T *statep)
13134eaa4710SRishi Srivatsavai {
13144eaa4710SRishi Srivatsavai 	size_t buflen = sizeof (*statep);
13154eaa4710SRishi Srivatsavai 
13164eaa4710SRishi Srivatsavai 	return (bridge_door_call(instname, bdcBridgeGetState,
13174eaa4710SRishi Srivatsavai 	    DATALINK_INVALID_LINKID, (void **)&statep, 0, &buflen, B_FALSE));
13184eaa4710SRishi Srivatsavai }
13194eaa4710SRishi Srivatsavai 
13204eaa4710SRishi Srivatsavai /* Returns list of ports (datalink_id_t values) assigned to a bridge instance */
13214eaa4710SRishi Srivatsavai datalink_id_t *
dladm_bridge_get_portlist(const char * instname,uint_t * nports)13224eaa4710SRishi Srivatsavai dladm_bridge_get_portlist(const char *instname, uint_t *nports)
13234eaa4710SRishi Srivatsavai {
13244eaa4710SRishi Srivatsavai 	size_t buflen = sizeof (int) + MAXPORTS * sizeof (datalink_id_t);
13254eaa4710SRishi Srivatsavai 	int *rbuf;
13264eaa4710SRishi Srivatsavai 
13274eaa4710SRishi Srivatsavai 	if ((rbuf = malloc(buflen)) == NULL)
13284eaa4710SRishi Srivatsavai 		return (NULL);
13294eaa4710SRishi Srivatsavai 	if (bridge_door_call(instname, bdcBridgeGetPorts,
13304eaa4710SRishi Srivatsavai 	    DATALINK_INVALID_LINKID, (void **)&rbuf, 0, &buflen, B_TRUE) !=
13314eaa4710SRishi Srivatsavai 	    DLADM_STATUS_OK) {
13324eaa4710SRishi Srivatsavai 		free(rbuf);
13334eaa4710SRishi Srivatsavai 		return (NULL);
13344eaa4710SRishi Srivatsavai 	} else {
13354eaa4710SRishi Srivatsavai 		/*
13364eaa4710SRishi Srivatsavai 		 * Returns an array of datalink_id_t values for all the ports
13374eaa4710SRishi Srivatsavai 		 * part of the bridge instance. First entry in the array is the
13384eaa4710SRishi Srivatsavai 		 * number of ports.
13394eaa4710SRishi Srivatsavai 		 */
13404eaa4710SRishi Srivatsavai 		*nports = *rbuf;
13414eaa4710SRishi Srivatsavai 		return ((datalink_id_t *)(rbuf + 1));
13424eaa4710SRishi Srivatsavai 	}
13434eaa4710SRishi Srivatsavai }
13444eaa4710SRishi Srivatsavai 
13454eaa4710SRishi Srivatsavai void
dladm_bridge_free_portlist(datalink_id_t * dlp)13464eaa4710SRishi Srivatsavai dladm_bridge_free_portlist(datalink_id_t *dlp)
13474eaa4710SRishi Srivatsavai {
13484eaa4710SRishi Srivatsavai 	free((int *)dlp - 1);
13494eaa4710SRishi Srivatsavai }
13504eaa4710SRishi Srivatsavai 
13514eaa4710SRishi Srivatsavai /* Retrieve Bridge port configuration values */
13524eaa4710SRishi Srivatsavai dladm_status_t
dladm_bridge_get_port_cfg(dladm_handle_t handle,datalink_id_t linkid,int field,int * valuep)13534eaa4710SRishi Srivatsavai dladm_bridge_get_port_cfg(dladm_handle_t handle, datalink_id_t linkid,
13544eaa4710SRishi Srivatsavai     int field, int *valuep)
13554eaa4710SRishi Srivatsavai {
13564eaa4710SRishi Srivatsavai 	UID_STP_PORT_CFG_T portcfg;
13574eaa4710SRishi Srivatsavai 	dladm_status_t status;
13584eaa4710SRishi Srivatsavai 
13594eaa4710SRishi Srivatsavai 	status = port_door_call(handle, linkid, bdcPortGetConfig, &portcfg,
13604eaa4710SRishi Srivatsavai 	    0, sizeof (portcfg));
13614eaa4710SRishi Srivatsavai 	if (status != DLADM_STATUS_OK)
13624eaa4710SRishi Srivatsavai 		return (status);
13634eaa4710SRishi Srivatsavai 
13644eaa4710SRishi Srivatsavai 	switch (field) {
13654eaa4710SRishi Srivatsavai 	case PT_CFG_COST:
13664eaa4710SRishi Srivatsavai 		*valuep = portcfg.admin_port_path_cost;
13674eaa4710SRishi Srivatsavai 		break;
13684eaa4710SRishi Srivatsavai 	case PT_CFG_PRIO:
13694eaa4710SRishi Srivatsavai 		*valuep = portcfg.port_priority;
13704eaa4710SRishi Srivatsavai 		break;
13714eaa4710SRishi Srivatsavai 	case PT_CFG_P2P:
13724eaa4710SRishi Srivatsavai 		*valuep = portcfg.admin_point2point;
13734eaa4710SRishi Srivatsavai 		break;
13744eaa4710SRishi Srivatsavai 	case PT_CFG_EDGE:
13754eaa4710SRishi Srivatsavai 		*valuep = portcfg.admin_edge;
13764eaa4710SRishi Srivatsavai 		break;
13774eaa4710SRishi Srivatsavai 	case PT_CFG_NON_STP:
13784eaa4710SRishi Srivatsavai 		*valuep = !portcfg.admin_non_stp;
13794eaa4710SRishi Srivatsavai 		break;
13804eaa4710SRishi Srivatsavai 	case PT_CFG_MCHECK:
13814eaa4710SRishi Srivatsavai 		*valuep = (portcfg.field_mask & PT_CFG_MCHECK) ? 1 : 0;
13824eaa4710SRishi Srivatsavai 		break;
13834eaa4710SRishi Srivatsavai 	}
13844eaa4710SRishi Srivatsavai 	return (status);
13854eaa4710SRishi Srivatsavai }
13864eaa4710SRishi Srivatsavai 
13874eaa4710SRishi Srivatsavai /* Retreive Bridge port status (disabled, bad SDU etc.) */
13884eaa4710SRishi Srivatsavai dladm_status_t
dladm_bridge_link_state(dladm_handle_t handle,datalink_id_t linkid,UID_STP_PORT_STATE_T * spsp)13894eaa4710SRishi Srivatsavai dladm_bridge_link_state(dladm_handle_t handle, datalink_id_t linkid,
13904eaa4710SRishi Srivatsavai     UID_STP_PORT_STATE_T *spsp)
13914eaa4710SRishi Srivatsavai {
13924eaa4710SRishi Srivatsavai 	return (port_door_call(handle, linkid, bdcPortGetState, spsp, 0,
13934eaa4710SRishi Srivatsavai 	    sizeof (*spsp)));
13944eaa4710SRishi Srivatsavai }
13954eaa4710SRishi Srivatsavai 
13964eaa4710SRishi Srivatsavai /* Retrieve Bridge forwarding status of the given link */
13974eaa4710SRishi Srivatsavai dladm_status_t
dladm_bridge_get_forwarding(dladm_handle_t handle,datalink_id_t linkid,uint_t * valuep)13984eaa4710SRishi Srivatsavai dladm_bridge_get_forwarding(dladm_handle_t handle, datalink_id_t linkid,
13994eaa4710SRishi Srivatsavai     uint_t *valuep)
14004eaa4710SRishi Srivatsavai {
14014eaa4710SRishi Srivatsavai 	int twoints[2];
14024eaa4710SRishi Srivatsavai 	dladm_status_t status;
14034eaa4710SRishi Srivatsavai 
14044eaa4710SRishi Srivatsavai 	status = port_door_call(handle, linkid, bdcPortGetForwarding, twoints,
14054eaa4710SRishi Srivatsavai 	    0, sizeof (twoints));
14064eaa4710SRishi Srivatsavai 	if (status == DLADM_STATUS_OK)
14074eaa4710SRishi Srivatsavai 		*valuep = twoints[0];
14084eaa4710SRishi Srivatsavai 	return (status);
14094eaa4710SRishi Srivatsavai }
14104eaa4710SRishi Srivatsavai 
14114eaa4710SRishi Srivatsavai /* Retrieve Bridge forwarding table entries */
14124eaa4710SRishi Srivatsavai bridge_listfwd_t *
dladm_bridge_get_fwdtable(dladm_handle_t handle,const char * bridge,uint_t * nfwd)14134eaa4710SRishi Srivatsavai dladm_bridge_get_fwdtable(dladm_handle_t handle, const char *bridge,
14144eaa4710SRishi Srivatsavai     uint_t *nfwd)
14154eaa4710SRishi Srivatsavai {
14164eaa4710SRishi Srivatsavai 	bridge_listfwd_t *blf = NULL, *newblf, blfread;
14174eaa4710SRishi Srivatsavai 	uint_t nblf = 0, maxblf = 0;
14184eaa4710SRishi Srivatsavai 	static uint8_t zero_addr[ETHERADDRL];
14194eaa4710SRishi Srivatsavai 	int rc;
14204eaa4710SRishi Srivatsavai 
14214eaa4710SRishi Srivatsavai 	(void) memset(&blfread, 0, sizeof (blfread));
14224eaa4710SRishi Srivatsavai 	(void) snprintf(blfread.blf_name, sizeof (blfread.blf_name),
14234eaa4710SRishi Srivatsavai 	    "%s0", bridge);
14244eaa4710SRishi Srivatsavai 	for (;;) {
14254eaa4710SRishi Srivatsavai 		if (nblf >= maxblf) {
14264eaa4710SRishi Srivatsavai 			maxblf = maxblf == 0 ? 64 : (maxblf << 1);
14274eaa4710SRishi Srivatsavai 			newblf = realloc(blf, maxblf * sizeof (*blf));
14284eaa4710SRishi Srivatsavai 			if (newblf == NULL) {
14294eaa4710SRishi Srivatsavai 				free(blf);
14304eaa4710SRishi Srivatsavai 				blf = NULL;
14314eaa4710SRishi Srivatsavai 				break;
14324eaa4710SRishi Srivatsavai 			}
14334eaa4710SRishi Srivatsavai 			blf = newblf;
14344eaa4710SRishi Srivatsavai 		}
14354eaa4710SRishi Srivatsavai 		rc = ioctl(dladm_dld_fd(handle), BRIDGE_IOC_LISTFWD, &blfread);
14364eaa4710SRishi Srivatsavai 		if (rc != 0) {
14374eaa4710SRishi Srivatsavai 			free(blf);
14384eaa4710SRishi Srivatsavai 			blf = NULL;
14394eaa4710SRishi Srivatsavai 			break;
14404eaa4710SRishi Srivatsavai 		}
14414eaa4710SRishi Srivatsavai 		if (memcmp(blfread.blf_dest, zero_addr, ETHERADDRL) == 0)
14424eaa4710SRishi Srivatsavai 			break;
14434eaa4710SRishi Srivatsavai 		blf[nblf++] = blfread;
14444eaa4710SRishi Srivatsavai 	}
14454eaa4710SRishi Srivatsavai 	if (blf != NULL)
14464eaa4710SRishi Srivatsavai 		*nfwd = nblf;
14474eaa4710SRishi Srivatsavai 	return (blf);
14484eaa4710SRishi Srivatsavai }
14494eaa4710SRishi Srivatsavai 
14504eaa4710SRishi Srivatsavai void
dladm_bridge_free_fwdtable(bridge_listfwd_t * blf)14514eaa4710SRishi Srivatsavai dladm_bridge_free_fwdtable(bridge_listfwd_t *blf)
14524eaa4710SRishi Srivatsavai {
14534eaa4710SRishi Srivatsavai 	free(blf);
14544eaa4710SRishi Srivatsavai }
14554eaa4710SRishi Srivatsavai 
14564eaa4710SRishi Srivatsavai /* Retrieve list of TRILL nicknames from the TRILL module */
14574eaa4710SRishi Srivatsavai trill_listnick_t *
dladm_bridge_get_trillnick(const char * bridge,uint_t * nnick)14584eaa4710SRishi Srivatsavai dladm_bridge_get_trillnick(const char *bridge, uint_t *nnick)
14594eaa4710SRishi Srivatsavai {
14604eaa4710SRishi Srivatsavai 	int fd;
14614eaa4710SRishi Srivatsavai 	char brcopy[MAXLINKNAMELEN];
14624eaa4710SRishi Srivatsavai 	trill_listnick_t *tln = NULL, *newtln, tlnread;
14634eaa4710SRishi Srivatsavai 	uint_t ntln = 0, maxtln = 0;
14644eaa4710SRishi Srivatsavai 
14654eaa4710SRishi Srivatsavai 	if ((fd = socket(PF_TRILL, SOCK_DGRAM, 0)) == -1)
14664eaa4710SRishi Srivatsavai 		return (NULL);
14674eaa4710SRishi Srivatsavai 	(void) strlcpy(brcopy, bridge, sizeof (brcopy));
14684eaa4710SRishi Srivatsavai 	if (ioctl(fd, TRILL_GETBRIDGE, &brcopy) < 0) {
14694eaa4710SRishi Srivatsavai 		(void) close(fd);
14704eaa4710SRishi Srivatsavai 		return (NULL);
14714eaa4710SRishi Srivatsavai 	}
14724eaa4710SRishi Srivatsavai 	(void) memset(&tlnread, 0, sizeof (tlnread));
14734eaa4710SRishi Srivatsavai 	for (;;) {
14744eaa4710SRishi Srivatsavai 		if (ntln >= maxtln) {
14754eaa4710SRishi Srivatsavai 			maxtln = maxtln == 0 ? 64 : (maxtln << 1);
14764eaa4710SRishi Srivatsavai 			newtln = realloc(tln, maxtln * sizeof (*tln));
14774eaa4710SRishi Srivatsavai 			if (newtln == NULL) {
14784eaa4710SRishi Srivatsavai 				free(tln);
14794eaa4710SRishi Srivatsavai 				tln = NULL;
14804eaa4710SRishi Srivatsavai 				break;
14814eaa4710SRishi Srivatsavai 			}
14824eaa4710SRishi Srivatsavai 			tln = newtln;
14834eaa4710SRishi Srivatsavai 		}
14844eaa4710SRishi Srivatsavai 		if (ioctl(fd, TRILL_LISTNICK, &tlnread) == -1) {
14854eaa4710SRishi Srivatsavai 			free(tln);
14864eaa4710SRishi Srivatsavai 			tln = NULL;
14874eaa4710SRishi Srivatsavai 			break;
14884eaa4710SRishi Srivatsavai 		}
14894eaa4710SRishi Srivatsavai 		if (tlnread.tln_nick == 0)
14904eaa4710SRishi Srivatsavai 			break;
14914eaa4710SRishi Srivatsavai 		tln[ntln++] = tlnread;
14924eaa4710SRishi Srivatsavai 	}
14934eaa4710SRishi Srivatsavai 	(void) close(fd);
14944eaa4710SRishi Srivatsavai 	if (tln != NULL)
14954eaa4710SRishi Srivatsavai 		*nnick = ntln;
14964eaa4710SRishi Srivatsavai 	return (tln);
14974eaa4710SRishi Srivatsavai }
14984eaa4710SRishi Srivatsavai 
14994eaa4710SRishi Srivatsavai void
dladm_bridge_free_trillnick(trill_listnick_t * tln)15004eaa4710SRishi Srivatsavai dladm_bridge_free_trillnick(trill_listnick_t *tln)
15014eaa4710SRishi Srivatsavai {
15024eaa4710SRishi Srivatsavai 	free(tln);
15034eaa4710SRishi Srivatsavai }
15044eaa4710SRishi Srivatsavai 
15054eaa4710SRishi Srivatsavai /* Retrieve any stored TRILL nickname from TRILL SMF service */
15064eaa4710SRishi Srivatsavai uint16_t
dladm_bridge_get_nick(const char * bridge)15074eaa4710SRishi Srivatsavai dladm_bridge_get_nick(const char *bridge)
15084eaa4710SRishi Srivatsavai {
15094eaa4710SRishi Srivatsavai 	scf_state_t sstate;
15104eaa4710SRishi Srivatsavai 	uint64_t value;
15114eaa4710SRishi Srivatsavai 	uint16_t nickname = RBRIDGE_NICKNAME_NONE;
15124eaa4710SRishi Srivatsavai 
15134eaa4710SRishi Srivatsavai 	if (bind_instance(TRILL_SVC_NAME, bridge, &sstate) != 0)
15144eaa4710SRishi Srivatsavai 		return (nickname);
15154eaa4710SRishi Srivatsavai 
15164eaa4710SRishi Srivatsavai 	if (get_composed_properties("config", B_TRUE, &sstate) == 0 &&
15174eaa4710SRishi Srivatsavai 	    get_count("nickname", &sstate, &value) == 0)
15184eaa4710SRishi Srivatsavai 		nickname = value;
15194eaa4710SRishi Srivatsavai 	shut_down_scf(&sstate);
15204eaa4710SRishi Srivatsavai 	return (nickname);
15214eaa4710SRishi Srivatsavai }
15224eaa4710SRishi Srivatsavai 
15234eaa4710SRishi Srivatsavai /* Stores TRILL nickname in SMF configuraiton for the TRILL service */
15244eaa4710SRishi Srivatsavai void
dladm_bridge_set_nick(const char * bridge,uint16_t nick)15254eaa4710SRishi Srivatsavai dladm_bridge_set_nick(const char *bridge, uint16_t nick)
15264eaa4710SRishi Srivatsavai {
15274eaa4710SRishi Srivatsavai 	scf_state_t sstate;
15284eaa4710SRishi Srivatsavai 	scf_transaction_t *tran = NULL;
15294eaa4710SRishi Srivatsavai 	boolean_t new_pg = B_FALSE;
15304eaa4710SRishi Srivatsavai 	int rv = 0;
15314eaa4710SRishi Srivatsavai 	char *fmri;
15324eaa4710SRishi Srivatsavai 
15334eaa4710SRishi Srivatsavai 	if (exact_instance(TRILL_SVC_NAME, &sstate) != DLADM_STATUS_OK)
15344eaa4710SRishi Srivatsavai 		return;
15354eaa4710SRishi Srivatsavai 
15364eaa4710SRishi Srivatsavai 	if (scf_service_get_instance(sstate.ss_svc, bridge, sstate.ss_inst) !=
15374eaa4710SRishi Srivatsavai 	    0)
15384eaa4710SRishi Srivatsavai 		goto out;
15394eaa4710SRishi Srivatsavai 	if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL)
15404eaa4710SRishi Srivatsavai 		goto out;
15414eaa4710SRishi Srivatsavai 	if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL)
15424eaa4710SRishi Srivatsavai 		goto out;
15434eaa4710SRishi Srivatsavai 	if (scf_instance_add_pg(sstate.ss_inst, "config",
15444eaa4710SRishi Srivatsavai 	    SCF_GROUP_APPLICATION, 0, sstate.ss_pg) == 0) {
15454eaa4710SRishi Srivatsavai 		new_pg = B_TRUE;
15464eaa4710SRishi Srivatsavai 	} else if (scf_instance_get_pg(sstate.ss_inst, "config",
15474eaa4710SRishi Srivatsavai 	    sstate.ss_pg) != 0) {
15484eaa4710SRishi Srivatsavai 		goto out;
15494eaa4710SRishi Srivatsavai 	}
15504eaa4710SRishi Srivatsavai 	do {
15514eaa4710SRishi Srivatsavai 		if (scf_transaction_start(tran, sstate.ss_pg) != 0)
15524eaa4710SRishi Srivatsavai 			goto out;
15534eaa4710SRishi Srivatsavai 		if (!set_count_property(sstate.ss_handle, tran, "nickname",
15544eaa4710SRishi Srivatsavai 		    nick))
15554eaa4710SRishi Srivatsavai 			goto out;
15564eaa4710SRishi Srivatsavai 		rv = scf_transaction_commit(tran);
15574eaa4710SRishi Srivatsavai 		scf_transaction_reset(tran);
15584eaa4710SRishi Srivatsavai 		if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1)
15594eaa4710SRishi Srivatsavai 			goto out;
15604eaa4710SRishi Srivatsavai 	} while (rv == 0);
15614eaa4710SRishi Srivatsavai 
15624eaa4710SRishi Srivatsavai out:
15634eaa4710SRishi Srivatsavai 	if (tran != NULL) {
15644eaa4710SRishi Srivatsavai 		scf_transaction_destroy_children(tran);
15654eaa4710SRishi Srivatsavai 		scf_transaction_destroy(tran);
15664eaa4710SRishi Srivatsavai 	}
15674eaa4710SRishi Srivatsavai 
15684eaa4710SRishi Srivatsavai 	if (rv != 1 && new_pg)
15694eaa4710SRishi Srivatsavai 		(void) scf_pg_delete(sstate.ss_pg);
15704eaa4710SRishi Srivatsavai 
15714eaa4710SRishi Srivatsavai 	drop_composed(&sstate);
15724eaa4710SRishi Srivatsavai 	shut_down_scf(&sstate);
15734eaa4710SRishi Srivatsavai 	if (rv == 1 && (fmri = alloc_fmri(TRILL_SVC_NAME, bridge)) != NULL) {
15744eaa4710SRishi Srivatsavai 		(void) smf_refresh_instance(fmri);
15754eaa4710SRishi Srivatsavai 		free(fmri);
15764eaa4710SRishi Srivatsavai 	}
15774eaa4710SRishi Srivatsavai }
1578