110491SRishi.Srivatsavai@Sun.COM /*
210491SRishi.Srivatsavai@Sun.COM  * CDDL HEADER START
310491SRishi.Srivatsavai@Sun.COM  *
410491SRishi.Srivatsavai@Sun.COM  * The contents of this file are subject to the terms of the
510491SRishi.Srivatsavai@Sun.COM  * Common Development and Distribution License (the "License").
610491SRishi.Srivatsavai@Sun.COM  * You may not use this file except in compliance with the License.
710491SRishi.Srivatsavai@Sun.COM  *
810491SRishi.Srivatsavai@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910491SRishi.Srivatsavai@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1010491SRishi.Srivatsavai@Sun.COM  * See the License for the specific language governing permissions
1110491SRishi.Srivatsavai@Sun.COM  * and limitations under the License.
1210491SRishi.Srivatsavai@Sun.COM  *
1310491SRishi.Srivatsavai@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1410491SRishi.Srivatsavai@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510491SRishi.Srivatsavai@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1610491SRishi.Srivatsavai@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1710491SRishi.Srivatsavai@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1810491SRishi.Srivatsavai@Sun.COM  *
1910491SRishi.Srivatsavai@Sun.COM  * CDDL HEADER END
2010491SRishi.Srivatsavai@Sun.COM  */
2110491SRishi.Srivatsavai@Sun.COM /*
2210491SRishi.Srivatsavai@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2310491SRishi.Srivatsavai@Sun.COM  * Use is subject to license terms.
2410491SRishi.Srivatsavai@Sun.COM  */
2510491SRishi.Srivatsavai@Sun.COM 
2610491SRishi.Srivatsavai@Sun.COM #include <stdio.h>
2710491SRishi.Srivatsavai@Sun.COM #include <sys/types.h>
2810491SRishi.Srivatsavai@Sun.COM #include <string.h>
2910491SRishi.Srivatsavai@Sun.COM #include <fcntl.h>
3010491SRishi.Srivatsavai@Sun.COM #include <unistd.h>
3110491SRishi.Srivatsavai@Sun.COM #include <stropts.h>
3210491SRishi.Srivatsavai@Sun.COM #include <ctype.h>
3310491SRishi.Srivatsavai@Sun.COM #include <errno.h>
3410491SRishi.Srivatsavai@Sun.COM #include <stdlib.h>
3510491SRishi.Srivatsavai@Sun.COM #include <door.h>
3610491SRishi.Srivatsavai@Sun.COM #include <sys/mman.h>
3710491SRishi.Srivatsavai@Sun.COM #include <libscf.h>
3810491SRishi.Srivatsavai@Sun.COM #include <libscf_priv.h>
3910491SRishi.Srivatsavai@Sun.COM #include <libdllink.h>
4010491SRishi.Srivatsavai@Sun.COM #include <libdlbridge.h>
4110491SRishi.Srivatsavai@Sun.COM #include <libdladm_impl.h>
4210491SRishi.Srivatsavai@Sun.COM #include <stp_in.h>
4310491SRishi.Srivatsavai@Sun.COM #include <net/bridge.h>
4410491SRishi.Srivatsavai@Sun.COM #include <net/trill.h>
4510491SRishi.Srivatsavai@Sun.COM #include <sys/socket.h>
46*10530SRishi.Srivatsavai@Sun.COM #include <sys/dld_ioc.h>
4710491SRishi.Srivatsavai@Sun.COM 
4810491SRishi.Srivatsavai@Sun.COM /*
4910491SRishi.Srivatsavai@Sun.COM  * Bridge Administration Library.
5010491SRishi.Srivatsavai@Sun.COM  *
5110491SRishi.Srivatsavai@Sun.COM  * This library is used by administration tools such as dladm(1M) to configure
5210491SRishi.Srivatsavai@Sun.COM  * bridges, and by the bridge daemon to retrieve configuration information.
5310491SRishi.Srivatsavai@Sun.COM  */
5410491SRishi.Srivatsavai@Sun.COM 
5510491SRishi.Srivatsavai@Sun.COM #define	BRIDGE_SVC_NAME	"network/bridge"
5610491SRishi.Srivatsavai@Sun.COM #define	TRILL_SVC_NAME	"network/routing/trill"
5710491SRishi.Srivatsavai@Sun.COM 
5810491SRishi.Srivatsavai@Sun.COM #define	DEFAULT_TIMEOUT	60000000
5910491SRishi.Srivatsavai@Sun.COM #define	INIT_WAIT_USECS	50000
6010491SRishi.Srivatsavai@Sun.COM #define	MAXPORTS	256
6110491SRishi.Srivatsavai@Sun.COM 
6210491SRishi.Srivatsavai@Sun.COM typedef struct scf_state {
6310491SRishi.Srivatsavai@Sun.COM 	scf_handle_t *ss_handle;
6410491SRishi.Srivatsavai@Sun.COM 	scf_instance_t *ss_inst;
6510491SRishi.Srivatsavai@Sun.COM 	scf_service_t *ss_svc;
6610491SRishi.Srivatsavai@Sun.COM 	scf_snapshot_t *ss_snap;
6710491SRishi.Srivatsavai@Sun.COM 	scf_propertygroup_t *ss_pg;
6810491SRishi.Srivatsavai@Sun.COM 	scf_property_t *ss_prop;
6910491SRishi.Srivatsavai@Sun.COM } scf_state_t;
7010491SRishi.Srivatsavai@Sun.COM 
7110491SRishi.Srivatsavai@Sun.COM static void
7210491SRishi.Srivatsavai@Sun.COM shut_down_scf(scf_state_t *sstate)
7310491SRishi.Srivatsavai@Sun.COM {
7410491SRishi.Srivatsavai@Sun.COM 	scf_instance_destroy(sstate->ss_inst);
7510491SRishi.Srivatsavai@Sun.COM 	(void) scf_handle_unbind(sstate->ss_handle);
7610491SRishi.Srivatsavai@Sun.COM 	scf_handle_destroy(sstate->ss_handle);
7710491SRishi.Srivatsavai@Sun.COM }
7810491SRishi.Srivatsavai@Sun.COM 
7910491SRishi.Srivatsavai@Sun.COM static char *
8010491SRishi.Srivatsavai@Sun.COM alloc_fmri(const char *service, const char *instance_name)
8110491SRishi.Srivatsavai@Sun.COM {
8210491SRishi.Srivatsavai@Sun.COM 	ssize_t max_fmri;
8310491SRishi.Srivatsavai@Sun.COM 	char *fmri;
8410491SRishi.Srivatsavai@Sun.COM 
8510491SRishi.Srivatsavai@Sun.COM 	/* If the limit is unknown, then use an arbitrary value */
8610491SRishi.Srivatsavai@Sun.COM 	if ((max_fmri = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) == -1)
8710491SRishi.Srivatsavai@Sun.COM 		max_fmri = 1024;
8810491SRishi.Srivatsavai@Sun.COM 	if ((fmri = malloc(max_fmri)) != NULL) {
8910491SRishi.Srivatsavai@Sun.COM 		(void) snprintf(fmri, max_fmri, "svc:/%s:%s", service,
9010491SRishi.Srivatsavai@Sun.COM 		    instance_name);
9110491SRishi.Srivatsavai@Sun.COM 	}
9210491SRishi.Srivatsavai@Sun.COM 	return (fmri);
9310491SRishi.Srivatsavai@Sun.COM }
9410491SRishi.Srivatsavai@Sun.COM 
9510491SRishi.Srivatsavai@Sun.COM /*
9610491SRishi.Srivatsavai@Sun.COM  * Start up SCF and bind the requested instance alone.
9710491SRishi.Srivatsavai@Sun.COM  */
9810491SRishi.Srivatsavai@Sun.COM static int
9910491SRishi.Srivatsavai@Sun.COM bind_instance(const char *service, const char *instance_name,
10010491SRishi.Srivatsavai@Sun.COM     scf_state_t *sstate)
10110491SRishi.Srivatsavai@Sun.COM {
10210491SRishi.Srivatsavai@Sun.COM 	char *fmri = NULL;
10310491SRishi.Srivatsavai@Sun.COM 
10410491SRishi.Srivatsavai@Sun.COM 	(void) memset(sstate, 0, sizeof (*sstate));
10510491SRishi.Srivatsavai@Sun.COM 
10610491SRishi.Srivatsavai@Sun.COM 	if ((sstate->ss_handle = scf_handle_create(SCF_VERSION)) == NULL)
10710491SRishi.Srivatsavai@Sun.COM 		return (-1);
10810491SRishi.Srivatsavai@Sun.COM 
10910491SRishi.Srivatsavai@Sun.COM 	if (scf_handle_bind(sstate->ss_handle) != 0)
11010491SRishi.Srivatsavai@Sun.COM 		goto failure;
11110491SRishi.Srivatsavai@Sun.COM 	sstate->ss_inst = scf_instance_create(sstate->ss_handle);
11210491SRishi.Srivatsavai@Sun.COM 	if (sstate->ss_inst == NULL)
11310491SRishi.Srivatsavai@Sun.COM 		goto failure;
11410491SRishi.Srivatsavai@Sun.COM 
11510491SRishi.Srivatsavai@Sun.COM 	fmri = alloc_fmri(service, instance_name);
11610491SRishi.Srivatsavai@Sun.COM 
11710491SRishi.Srivatsavai@Sun.COM 	if (scf_handle_decode_fmri(sstate->ss_handle, fmri, NULL, NULL,
11810491SRishi.Srivatsavai@Sun.COM 	    sstate->ss_inst, NULL, NULL,
11910491SRishi.Srivatsavai@Sun.COM 	    SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0)
12010491SRishi.Srivatsavai@Sun.COM 		goto failure;
12110491SRishi.Srivatsavai@Sun.COM 	free(fmri);
12210491SRishi.Srivatsavai@Sun.COM 	return (0);
12310491SRishi.Srivatsavai@Sun.COM 
12410491SRishi.Srivatsavai@Sun.COM failure:
12510491SRishi.Srivatsavai@Sun.COM 	free(fmri);
12610491SRishi.Srivatsavai@Sun.COM 	shut_down_scf(sstate);
12710491SRishi.Srivatsavai@Sun.COM 	return (-1);
12810491SRishi.Srivatsavai@Sun.COM }
12910491SRishi.Srivatsavai@Sun.COM 
13010491SRishi.Srivatsavai@Sun.COM /*
13110491SRishi.Srivatsavai@Sun.COM  * Start up SCF and an exact FMRI.  This is used for creating new instances and
13210491SRishi.Srivatsavai@Sun.COM  * enable/disable actions.
13310491SRishi.Srivatsavai@Sun.COM  */
13410491SRishi.Srivatsavai@Sun.COM static dladm_status_t
13510491SRishi.Srivatsavai@Sun.COM exact_instance(const char *fmri, scf_state_t *sstate)
13610491SRishi.Srivatsavai@Sun.COM {
13710491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
13810491SRishi.Srivatsavai@Sun.COM 
13910491SRishi.Srivatsavai@Sun.COM 	(void) memset(sstate, 0, sizeof (*sstate));
14010491SRishi.Srivatsavai@Sun.COM 
14110491SRishi.Srivatsavai@Sun.COM 	if ((sstate->ss_handle = scf_handle_create(SCF_VERSION)) == NULL)
14210491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_NOMEM);
14310491SRishi.Srivatsavai@Sun.COM 
14410491SRishi.Srivatsavai@Sun.COM 	status = DLADM_STATUS_FAILED;
14510491SRishi.Srivatsavai@Sun.COM 	if (scf_handle_bind(sstate->ss_handle) != 0)
14610491SRishi.Srivatsavai@Sun.COM 		goto failure;
14710491SRishi.Srivatsavai@Sun.COM 	sstate->ss_svc = scf_service_create(sstate->ss_handle);
14810491SRishi.Srivatsavai@Sun.COM 	if (sstate->ss_svc == NULL)
14910491SRishi.Srivatsavai@Sun.COM 		goto failure;
15010491SRishi.Srivatsavai@Sun.COM 	if (scf_handle_decode_fmri(sstate->ss_handle, fmri, NULL,
15110491SRishi.Srivatsavai@Sun.COM 	    sstate->ss_svc, NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) {
15210491SRishi.Srivatsavai@Sun.COM 		if (scf_error() == SCF_ERROR_NOT_FOUND)
15310491SRishi.Srivatsavai@Sun.COM 			status = DLADM_STATUS_OPTMISSING;
15410491SRishi.Srivatsavai@Sun.COM 		goto failure;
15510491SRishi.Srivatsavai@Sun.COM 	}
15610491SRishi.Srivatsavai@Sun.COM 	sstate->ss_inst = scf_instance_create(sstate->ss_handle);
15710491SRishi.Srivatsavai@Sun.COM 	if (sstate->ss_inst == NULL)
15810491SRishi.Srivatsavai@Sun.COM 		goto failure;
15910491SRishi.Srivatsavai@Sun.COM 	return (DLADM_STATUS_OK);
16010491SRishi.Srivatsavai@Sun.COM 
16110491SRishi.Srivatsavai@Sun.COM failure:
16210491SRishi.Srivatsavai@Sun.COM 	shut_down_scf(sstate);
16310491SRishi.Srivatsavai@Sun.COM 	return (status);
16410491SRishi.Srivatsavai@Sun.COM }
16510491SRishi.Srivatsavai@Sun.COM 
16610491SRishi.Srivatsavai@Sun.COM static void
16710491SRishi.Srivatsavai@Sun.COM drop_composed(scf_state_t *sstate)
16810491SRishi.Srivatsavai@Sun.COM {
16910491SRishi.Srivatsavai@Sun.COM 	scf_property_destroy(sstate->ss_prop);
17010491SRishi.Srivatsavai@Sun.COM 	scf_pg_destroy(sstate->ss_pg);
17110491SRishi.Srivatsavai@Sun.COM 	scf_snapshot_destroy(sstate->ss_snap);
17210491SRishi.Srivatsavai@Sun.COM }
17310491SRishi.Srivatsavai@Sun.COM 
17410491SRishi.Srivatsavai@Sun.COM /*
17510491SRishi.Srivatsavai@Sun.COM  * This function sets up a composed view of the configuration information for
17610491SRishi.Srivatsavai@Sun.COM  * the specified instance.  When this is done, the get_property() function
17710491SRishi.Srivatsavai@Sun.COM  * should be able to return individual parameters.
17810491SRishi.Srivatsavai@Sun.COM  */
17910491SRishi.Srivatsavai@Sun.COM static int
18010491SRishi.Srivatsavai@Sun.COM get_composed_properties(const char *lpg, boolean_t snap, scf_state_t *sstate)
18110491SRishi.Srivatsavai@Sun.COM {
18210491SRishi.Srivatsavai@Sun.COM 	sstate->ss_snap = NULL;
18310491SRishi.Srivatsavai@Sun.COM 	sstate->ss_pg = NULL;
18410491SRishi.Srivatsavai@Sun.COM 	sstate->ss_prop = NULL;
18510491SRishi.Srivatsavai@Sun.COM 
18610491SRishi.Srivatsavai@Sun.COM 	if (snap) {
18710491SRishi.Srivatsavai@Sun.COM 		sstate->ss_snap = scf_snapshot_create(sstate->ss_handle);
18810491SRishi.Srivatsavai@Sun.COM 		if (sstate->ss_snap == NULL)
18910491SRishi.Srivatsavai@Sun.COM 			goto failure;
19010491SRishi.Srivatsavai@Sun.COM 		if (scf_instance_get_snapshot(sstate->ss_inst, "running",
19110491SRishi.Srivatsavai@Sun.COM 		    sstate->ss_snap) != 0)
19210491SRishi.Srivatsavai@Sun.COM 			goto failure;
19310491SRishi.Srivatsavai@Sun.COM 	}
19410491SRishi.Srivatsavai@Sun.COM 	if ((sstate->ss_pg = scf_pg_create(sstate->ss_handle)) == NULL)
19510491SRishi.Srivatsavai@Sun.COM 		goto failure;
19610491SRishi.Srivatsavai@Sun.COM 	if (scf_instance_get_pg_composed(sstate->ss_inst, sstate->ss_snap, lpg,
19710491SRishi.Srivatsavai@Sun.COM 	    sstate->ss_pg) != 0)
19810491SRishi.Srivatsavai@Sun.COM 		goto failure;
19910491SRishi.Srivatsavai@Sun.COM 	if ((sstate->ss_prop = scf_property_create(sstate->ss_handle)) ==
20010491SRishi.Srivatsavai@Sun.COM 	    NULL)
20110491SRishi.Srivatsavai@Sun.COM 		goto failure;
20210491SRishi.Srivatsavai@Sun.COM 	return (0);
20310491SRishi.Srivatsavai@Sun.COM 
20410491SRishi.Srivatsavai@Sun.COM failure:
20510491SRishi.Srivatsavai@Sun.COM 	drop_composed(sstate);
20610491SRishi.Srivatsavai@Sun.COM 	return (-1);
20710491SRishi.Srivatsavai@Sun.COM }
20810491SRishi.Srivatsavai@Sun.COM 
20910491SRishi.Srivatsavai@Sun.COM static int
21010491SRishi.Srivatsavai@Sun.COM get_count(const char *lprop, scf_state_t *sstate, uint64_t *answer)
21110491SRishi.Srivatsavai@Sun.COM {
21210491SRishi.Srivatsavai@Sun.COM 	scf_value_t *val;
21310491SRishi.Srivatsavai@Sun.COM 	int retv;
21410491SRishi.Srivatsavai@Sun.COM 
21510491SRishi.Srivatsavai@Sun.COM 	if (scf_pg_get_property(sstate->ss_pg, lprop, sstate->ss_prop) != 0)
21610491SRishi.Srivatsavai@Sun.COM 		return (-1);
21710491SRishi.Srivatsavai@Sun.COM 	if ((val = scf_value_create(sstate->ss_handle)) == NULL)
21810491SRishi.Srivatsavai@Sun.COM 		return (-1);
21910491SRishi.Srivatsavai@Sun.COM 
22010491SRishi.Srivatsavai@Sun.COM 	if (scf_property_get_value(sstate->ss_prop, val) == 0 &&
22110491SRishi.Srivatsavai@Sun.COM 	    scf_value_get_count(val, answer) == 0)
22210491SRishi.Srivatsavai@Sun.COM 		retv = 0;
22310491SRishi.Srivatsavai@Sun.COM 	else
22410491SRishi.Srivatsavai@Sun.COM 		retv = -1;
22510491SRishi.Srivatsavai@Sun.COM 	scf_value_destroy(val);
22610491SRishi.Srivatsavai@Sun.COM 	return (retv);
22710491SRishi.Srivatsavai@Sun.COM }
22810491SRishi.Srivatsavai@Sun.COM 
22910491SRishi.Srivatsavai@Sun.COM static int
23010491SRishi.Srivatsavai@Sun.COM get_boolean(const char *lprop, scf_state_t *sstate, boolean_t *answer)
23110491SRishi.Srivatsavai@Sun.COM {
23210491SRishi.Srivatsavai@Sun.COM 	scf_value_t *val;
23310491SRishi.Srivatsavai@Sun.COM 	int retv;
23410491SRishi.Srivatsavai@Sun.COM 	uint8_t bval;
23510491SRishi.Srivatsavai@Sun.COM 
23610491SRishi.Srivatsavai@Sun.COM 	if (scf_pg_get_property(sstate->ss_pg, lprop, sstate->ss_prop) != 0)
23710491SRishi.Srivatsavai@Sun.COM 		return (-1);
23810491SRishi.Srivatsavai@Sun.COM 	if ((val = scf_value_create(sstate->ss_handle)) == NULL)
23910491SRishi.Srivatsavai@Sun.COM 		return (-1);
24010491SRishi.Srivatsavai@Sun.COM 
24110491SRishi.Srivatsavai@Sun.COM 	if (scf_property_get_value(sstate->ss_prop, val) == 0 &&
24210491SRishi.Srivatsavai@Sun.COM 	    scf_value_get_boolean(val, &bval) == 0) {
24310491SRishi.Srivatsavai@Sun.COM 		retv = 0;
24410491SRishi.Srivatsavai@Sun.COM 		*answer = bval != 0;
24510491SRishi.Srivatsavai@Sun.COM 	} else {
24610491SRishi.Srivatsavai@Sun.COM 		retv = -1;
24710491SRishi.Srivatsavai@Sun.COM 	}
24810491SRishi.Srivatsavai@Sun.COM 	scf_value_destroy(val);
24910491SRishi.Srivatsavai@Sun.COM 	return (retv);
25010491SRishi.Srivatsavai@Sun.COM }
25110491SRishi.Srivatsavai@Sun.COM 
25210491SRishi.Srivatsavai@Sun.COM static dladm_status_t
25310491SRishi.Srivatsavai@Sun.COM bridge_door_call(const char *instname, bridge_door_type_t dtype,
25410491SRishi.Srivatsavai@Sun.COM     datalink_id_t linkid, void **bufp, size_t inlen, size_t *buflenp,
25510491SRishi.Srivatsavai@Sun.COM     boolean_t is_list)
25610491SRishi.Srivatsavai@Sun.COM {
25710491SRishi.Srivatsavai@Sun.COM 	char doorname[MAXPATHLEN];
25810491SRishi.Srivatsavai@Sun.COM 	int did, retv, etmp;
25910491SRishi.Srivatsavai@Sun.COM 	bridge_door_cmd_t *bdc;
26010491SRishi.Srivatsavai@Sun.COM 	door_arg_t arg;
26110491SRishi.Srivatsavai@Sun.COM 
26210491SRishi.Srivatsavai@Sun.COM 	(void) snprintf(doorname, sizeof (doorname), "%s/%s", DOOR_DIRNAME,
26310491SRishi.Srivatsavai@Sun.COM 	    instname);
26410491SRishi.Srivatsavai@Sun.COM 
26510491SRishi.Srivatsavai@Sun.COM 	/* Knock on the door */
26610491SRishi.Srivatsavai@Sun.COM 	did = open(doorname, O_RDONLY | O_NOFOLLOW | O_NONBLOCK);
26710491SRishi.Srivatsavai@Sun.COM 	if (did == -1)
26810491SRishi.Srivatsavai@Sun.COM 		return (dladm_errno2status(errno));
26910491SRishi.Srivatsavai@Sun.COM 
27010491SRishi.Srivatsavai@Sun.COM 	if ((bdc = malloc(sizeof (*bdc) + inlen)) == NULL) {
27110491SRishi.Srivatsavai@Sun.COM 		(void) close(did);
27210491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_NOMEM);
27310491SRishi.Srivatsavai@Sun.COM 	}
27410491SRishi.Srivatsavai@Sun.COM 	bdc->bdc_type = dtype;
27510491SRishi.Srivatsavai@Sun.COM 	bdc->bdc_linkid = linkid;
27610491SRishi.Srivatsavai@Sun.COM 	if (inlen != 0)
27710491SRishi.Srivatsavai@Sun.COM 		(void) memcpy(bdc + 1, *bufp, inlen);
27810491SRishi.Srivatsavai@Sun.COM 
27910491SRishi.Srivatsavai@Sun.COM 	(void) memset(&arg, 0, sizeof (arg));
28010491SRishi.Srivatsavai@Sun.COM 	arg.data_ptr = (char *)bdc;
28110491SRishi.Srivatsavai@Sun.COM 	arg.data_size = sizeof (*bdc) + inlen;
28210491SRishi.Srivatsavai@Sun.COM 	arg.rbuf = *bufp;
28310491SRishi.Srivatsavai@Sun.COM 	arg.rsize = *buflenp;
28410491SRishi.Srivatsavai@Sun.COM 
28510491SRishi.Srivatsavai@Sun.COM 	/* The door_call function doesn't restart, so take care of that */
28610491SRishi.Srivatsavai@Sun.COM 	do {
28710491SRishi.Srivatsavai@Sun.COM 		errno = 0;
28810491SRishi.Srivatsavai@Sun.COM 		if ((retv = door_call(did, &arg)) == 0)
28910491SRishi.Srivatsavai@Sun.COM 			break;
29010491SRishi.Srivatsavai@Sun.COM 	} while (errno == EINTR);
29110491SRishi.Srivatsavai@Sun.COM 
29210491SRishi.Srivatsavai@Sun.COM 	/* If we get an unexpected response, then return an error */
29310491SRishi.Srivatsavai@Sun.COM 	if (retv == 0) {
29410491SRishi.Srivatsavai@Sun.COM 		/* The daemon returns a single int for errors */
29510491SRishi.Srivatsavai@Sun.COM 		/* LINTED: pointer alignment */
29610491SRishi.Srivatsavai@Sun.COM 		if (arg.data_size == sizeof (int) && *(int *)arg.rbuf != 0) {
29710491SRishi.Srivatsavai@Sun.COM 			retv = -1;
29810491SRishi.Srivatsavai@Sun.COM 			/* LINTED: pointer alignment */
29910491SRishi.Srivatsavai@Sun.COM 			errno = *(int *)arg.rbuf;
30010491SRishi.Srivatsavai@Sun.COM 		}
30110491SRishi.Srivatsavai@Sun.COM 		/* Terminated daemon returns with zero data */
30210491SRishi.Srivatsavai@Sun.COM 		if (arg.data_size == 0) {
30310491SRishi.Srivatsavai@Sun.COM 			retv = -1;
30410491SRishi.Srivatsavai@Sun.COM 			errno = EBADF;
30510491SRishi.Srivatsavai@Sun.COM 		}
30610491SRishi.Srivatsavai@Sun.COM 	}
30710491SRishi.Srivatsavai@Sun.COM 
30810491SRishi.Srivatsavai@Sun.COM 	if (retv == 0) {
30910491SRishi.Srivatsavai@Sun.COM 		if (arg.rbuf != *bufp) {
31010491SRishi.Srivatsavai@Sun.COM 			if (is_list) {
31110491SRishi.Srivatsavai@Sun.COM 				void *newp;
31210491SRishi.Srivatsavai@Sun.COM 
31310491SRishi.Srivatsavai@Sun.COM 				newp = realloc(*bufp, arg.data_size);
31410491SRishi.Srivatsavai@Sun.COM 				if (newp == NULL) {
31510491SRishi.Srivatsavai@Sun.COM 					retv = -1;
31610491SRishi.Srivatsavai@Sun.COM 				} else {
31710491SRishi.Srivatsavai@Sun.COM 					*bufp = newp;
31810491SRishi.Srivatsavai@Sun.COM 					(void) memcpy(*bufp, arg.rbuf,
31910491SRishi.Srivatsavai@Sun.COM 					    arg.data_size);
32010491SRishi.Srivatsavai@Sun.COM 				}
32110491SRishi.Srivatsavai@Sun.COM 			}
32210491SRishi.Srivatsavai@Sun.COM 			(void) munmap(arg.rbuf, arg.rsize);
32310491SRishi.Srivatsavai@Sun.COM 		}
32410491SRishi.Srivatsavai@Sun.COM 		if (is_list) {
32510491SRishi.Srivatsavai@Sun.COM 			*buflenp = arg.data_size;
32610491SRishi.Srivatsavai@Sun.COM 		} else if (arg.data_size != *buflenp || arg.rbuf != *bufp) {
32710491SRishi.Srivatsavai@Sun.COM 			errno = EINVAL;
32810491SRishi.Srivatsavai@Sun.COM 			retv = -1;
32910491SRishi.Srivatsavai@Sun.COM 		}
33010491SRishi.Srivatsavai@Sun.COM 	}
33110491SRishi.Srivatsavai@Sun.COM 
33210491SRishi.Srivatsavai@Sun.COM 	etmp = errno;
33310491SRishi.Srivatsavai@Sun.COM 	(void) close(did);
33410491SRishi.Srivatsavai@Sun.COM 
33510491SRishi.Srivatsavai@Sun.COM 	/* Revoked door is the same as no door at all */
33610491SRishi.Srivatsavai@Sun.COM 	if (etmp == EBADF)
33710491SRishi.Srivatsavai@Sun.COM 		etmp = ENOENT;
33810491SRishi.Srivatsavai@Sun.COM 
33910491SRishi.Srivatsavai@Sun.COM 	return (retv == 0 ? DLADM_STATUS_OK : dladm_errno2status(etmp));
34010491SRishi.Srivatsavai@Sun.COM }
34110491SRishi.Srivatsavai@Sun.COM 
34210491SRishi.Srivatsavai@Sun.COM /*
34310491SRishi.Srivatsavai@Sun.COM  * Wrapper function for making per-port calls.
34410491SRishi.Srivatsavai@Sun.COM  */
34510491SRishi.Srivatsavai@Sun.COM static dladm_status_t
34610491SRishi.Srivatsavai@Sun.COM port_door_call(dladm_handle_t handle, datalink_id_t linkid,
34710491SRishi.Srivatsavai@Sun.COM     bridge_door_type_t dtype, void *buf, size_t inlen, size_t buflen)
34810491SRishi.Srivatsavai@Sun.COM {
34910491SRishi.Srivatsavai@Sun.COM 	char bridge[MAXLINKNAMELEN];
35010491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
35110491SRishi.Srivatsavai@Sun.COM 
35210491SRishi.Srivatsavai@Sun.COM 	status = dladm_bridge_getlink(handle, linkid, bridge, sizeof (bridge));
35310491SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK)
35410491SRishi.Srivatsavai@Sun.COM 		return (status);
35510491SRishi.Srivatsavai@Sun.COM 	return (bridge_door_call(bridge, dtype, linkid, &buf, inlen, &buflen,
35610491SRishi.Srivatsavai@Sun.COM 	    B_FALSE));
35710491SRishi.Srivatsavai@Sun.COM }
35810491SRishi.Srivatsavai@Sun.COM 
35910491SRishi.Srivatsavai@Sun.COM static dladm_status_t
36010491SRishi.Srivatsavai@Sun.COM bridge_refresh(const char *bridge)
36110491SRishi.Srivatsavai@Sun.COM {
36210491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
36310491SRishi.Srivatsavai@Sun.COM 	int twoints[2];
36410491SRishi.Srivatsavai@Sun.COM 	void *bdptr;
36510491SRishi.Srivatsavai@Sun.COM 	size_t buflen;
36610491SRishi.Srivatsavai@Sun.COM 	char *fmri;
36710491SRishi.Srivatsavai@Sun.COM 	int refresh_count;
36810491SRishi.Srivatsavai@Sun.COM 
36910491SRishi.Srivatsavai@Sun.COM 	buflen = sizeof (twoints);
37010491SRishi.Srivatsavai@Sun.COM 	bdptr = twoints;
37110491SRishi.Srivatsavai@Sun.COM 	status = bridge_door_call(bridge, bdcBridgeGetRefreshCount,
37210491SRishi.Srivatsavai@Sun.COM 	    DATALINK_INVALID_LINKID, &bdptr, 0, &buflen, B_FALSE);
37310491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_NOTFOUND)
37410491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_OK);
37510491SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK)
37610491SRishi.Srivatsavai@Sun.COM 		return (status);
37710491SRishi.Srivatsavai@Sun.COM 	refresh_count = twoints[0];
37810491SRishi.Srivatsavai@Sun.COM 	if ((fmri = alloc_fmri(BRIDGE_SVC_NAME, bridge)) == NULL)
37910491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_NOMEM);
38010491SRishi.Srivatsavai@Sun.COM 	status = smf_refresh_instance(fmri) == 0 ?
38110491SRishi.Srivatsavai@Sun.COM 	    DLADM_STATUS_OK : DLADM_STATUS_FAILED;
38210491SRishi.Srivatsavai@Sun.COM 	free(fmri);
38310491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_OK) {
38410491SRishi.Srivatsavai@Sun.COM 		int i = 0;
38510491SRishi.Srivatsavai@Sun.COM 
38610491SRishi.Srivatsavai@Sun.COM 		/*
38710491SRishi.Srivatsavai@Sun.COM 		 * SMF doesn't give any synchronous behavior or dependency
38810491SRishi.Srivatsavai@Sun.COM 		 * ordering for refresh operations, so we have to invent our
38910491SRishi.Srivatsavai@Sun.COM 		 * own mechanism here.  Get the refresh counter from the
39010491SRishi.Srivatsavai@Sun.COM 		 * daemon, and wait for it to change.  It's not pretty, but
39110491SRishi.Srivatsavai@Sun.COM 		 * it's sufficient.
39210491SRishi.Srivatsavai@Sun.COM 		 */
39310491SRishi.Srivatsavai@Sun.COM 		while (++i <= 10) {
39410491SRishi.Srivatsavai@Sun.COM 			buflen = sizeof (twoints);
39510491SRishi.Srivatsavai@Sun.COM 			bdptr = twoints;
39610491SRishi.Srivatsavai@Sun.COM 			status = bridge_door_call(bridge,
39710491SRishi.Srivatsavai@Sun.COM 			    bdcBridgeGetRefreshCount, DATALINK_INVALID_LINKID,
39810491SRishi.Srivatsavai@Sun.COM 			    &bdptr, 0, &buflen, B_FALSE);
39910491SRishi.Srivatsavai@Sun.COM 			if (status != DLADM_STATUS_OK)
40010491SRishi.Srivatsavai@Sun.COM 				break;
40110491SRishi.Srivatsavai@Sun.COM 			if (twoints[0] != refresh_count)
40210491SRishi.Srivatsavai@Sun.COM 				break;
40310491SRishi.Srivatsavai@Sun.COM 			(void) usleep(100000);
40410491SRishi.Srivatsavai@Sun.COM 		}
40510491SRishi.Srivatsavai@Sun.COM 		fmri = alloc_fmri(TRILL_SVC_NAME, bridge);
40610491SRishi.Srivatsavai@Sun.COM 		if (fmri == NULL)
40710491SRishi.Srivatsavai@Sun.COM 			return (DLADM_STATUS_NOMEM);
40810491SRishi.Srivatsavai@Sun.COM 		status = smf_refresh_instance(fmri) == 0 ||
40910491SRishi.Srivatsavai@Sun.COM 		    scf_error() == SCF_ERROR_NOT_FOUND ?
41010491SRishi.Srivatsavai@Sun.COM 		    DLADM_STATUS_OK : DLADM_STATUS_FAILED;
41110491SRishi.Srivatsavai@Sun.COM 		free(fmri);
41210491SRishi.Srivatsavai@Sun.COM 	}
41310491SRishi.Srivatsavai@Sun.COM 	return (status);
41410491SRishi.Srivatsavai@Sun.COM }
41510491SRishi.Srivatsavai@Sun.COM 
41610491SRishi.Srivatsavai@Sun.COM /*
41710491SRishi.Srivatsavai@Sun.COM  * Look up bridge property values from SCF and return them.
41810491SRishi.Srivatsavai@Sun.COM  */
41910491SRishi.Srivatsavai@Sun.COM dladm_status_t
42010491SRishi.Srivatsavai@Sun.COM dladm_bridge_get_properties(const char *instance_name, UID_STP_CFG_T *cfg,
42110491SRishi.Srivatsavai@Sun.COM     dladm_bridge_prot_t *brprotp)
42210491SRishi.Srivatsavai@Sun.COM {
42310491SRishi.Srivatsavai@Sun.COM 	scf_state_t sstate;
42410491SRishi.Srivatsavai@Sun.COM 	uint64_t value;
42510491SRishi.Srivatsavai@Sun.COM 	boolean_t trill_enabled;
42610491SRishi.Srivatsavai@Sun.COM 
42710491SRishi.Srivatsavai@Sun.COM 	cfg->field_mask = 0;
42810491SRishi.Srivatsavai@Sun.COM 	cfg->bridge_priority = DEF_BR_PRIO;
42910491SRishi.Srivatsavai@Sun.COM 	cfg->max_age = DEF_BR_MAXAGE;
43010491SRishi.Srivatsavai@Sun.COM 	cfg->hello_time = DEF_BR_HELLOT;
43110491SRishi.Srivatsavai@Sun.COM 	cfg->forward_delay = DEF_BR_FWDELAY;
43210491SRishi.Srivatsavai@Sun.COM 	cfg->force_version = DEF_FORCE_VERS;
43310491SRishi.Srivatsavai@Sun.COM 
43410491SRishi.Srivatsavai@Sun.COM 	(void) strlcpy(cfg->vlan_name, instance_name, sizeof (cfg->vlan_name));
43510491SRishi.Srivatsavai@Sun.COM 
43610491SRishi.Srivatsavai@Sun.COM 	*brprotp = DLADM_BRIDGE_PROT_STP;
43710491SRishi.Srivatsavai@Sun.COM 
43810491SRishi.Srivatsavai@Sun.COM 	/* It's ok for this to be missing; it's installed separately */
43910491SRishi.Srivatsavai@Sun.COM 	if (bind_instance(TRILL_SVC_NAME, instance_name, &sstate) == 0) {
44010491SRishi.Srivatsavai@Sun.COM 		trill_enabled = B_FALSE;
44110491SRishi.Srivatsavai@Sun.COM 		if (get_composed_properties(SCF_PG_GENERAL, B_FALSE, &sstate) ==
44210491SRishi.Srivatsavai@Sun.COM 		    0) {
44310491SRishi.Srivatsavai@Sun.COM 			(void) get_boolean(SCF_PROPERTY_ENABLED, &sstate,
44410491SRishi.Srivatsavai@Sun.COM 			    &trill_enabled);
44510491SRishi.Srivatsavai@Sun.COM 			if (trill_enabled)
44610491SRishi.Srivatsavai@Sun.COM 				*brprotp = DLADM_BRIDGE_PROT_TRILL;
44710491SRishi.Srivatsavai@Sun.COM 			drop_composed(&sstate);
44810491SRishi.Srivatsavai@Sun.COM 		}
44910491SRishi.Srivatsavai@Sun.COM 		if (get_composed_properties(SCF_PG_GENERAL_OVR, B_FALSE,
45010491SRishi.Srivatsavai@Sun.COM 		    &sstate) == 0) {
45110491SRishi.Srivatsavai@Sun.COM 			(void) get_boolean(SCF_PROPERTY_ENABLED, &sstate,
45210491SRishi.Srivatsavai@Sun.COM 			    &trill_enabled);
45310491SRishi.Srivatsavai@Sun.COM 			if (trill_enabled)
45410491SRishi.Srivatsavai@Sun.COM 				*brprotp = DLADM_BRIDGE_PROT_TRILL;
45510491SRishi.Srivatsavai@Sun.COM 			drop_composed(&sstate);
45610491SRishi.Srivatsavai@Sun.COM 		}
45710491SRishi.Srivatsavai@Sun.COM 		shut_down_scf(&sstate);
45810491SRishi.Srivatsavai@Sun.COM 	}
45910491SRishi.Srivatsavai@Sun.COM 
46010491SRishi.Srivatsavai@Sun.COM 	cfg->stp_enabled = (*brprotp == DLADM_BRIDGE_PROT_STP) ?
46110491SRishi.Srivatsavai@Sun.COM 	    STP_ENABLED : STP_DISABLED;
46210491SRishi.Srivatsavai@Sun.COM 	cfg->field_mask |= BR_CFG_STATE;
46310491SRishi.Srivatsavai@Sun.COM 
46410491SRishi.Srivatsavai@Sun.COM 	if (bind_instance(BRIDGE_SVC_NAME, instance_name, &sstate) != 0)
46510491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_REPOSITORYINVAL);
46610491SRishi.Srivatsavai@Sun.COM 
46710491SRishi.Srivatsavai@Sun.COM 	if (get_composed_properties("config", B_TRUE, &sstate) != 0) {
46810491SRishi.Srivatsavai@Sun.COM 		shut_down_scf(&sstate);
46910491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_REPOSITORYINVAL);
47010491SRishi.Srivatsavai@Sun.COM 	}
47110491SRishi.Srivatsavai@Sun.COM 
47210491SRishi.Srivatsavai@Sun.COM 	if (get_count("priority", &sstate, &value) == 0) {
47310491SRishi.Srivatsavai@Sun.COM 		cfg->bridge_priority = value;
47410491SRishi.Srivatsavai@Sun.COM 		cfg->field_mask |= BR_CFG_PRIO;
47510491SRishi.Srivatsavai@Sun.COM 	}
47610491SRishi.Srivatsavai@Sun.COM 	if (get_count("max-age", &sstate, &value) == 0) {
47710491SRishi.Srivatsavai@Sun.COM 		cfg->max_age = value / IEEE_TIMER_SCALE;
47810491SRishi.Srivatsavai@Sun.COM 		cfg->field_mask |= BR_CFG_AGE;
47910491SRishi.Srivatsavai@Sun.COM 	}
48010491SRishi.Srivatsavai@Sun.COM 	if (get_count("hello-time", &sstate, &value) == 0) {
48110491SRishi.Srivatsavai@Sun.COM 		cfg->hello_time = value / IEEE_TIMER_SCALE;
48210491SRishi.Srivatsavai@Sun.COM 		cfg->field_mask |= BR_CFG_HELLO;
48310491SRishi.Srivatsavai@Sun.COM 	}
48410491SRishi.Srivatsavai@Sun.COM 	if (get_count("forward-delay", &sstate, &value) == 0) {
48510491SRishi.Srivatsavai@Sun.COM 		cfg->forward_delay = value / IEEE_TIMER_SCALE;
48610491SRishi.Srivatsavai@Sun.COM 		cfg->field_mask |= BR_CFG_DELAY;
48710491SRishi.Srivatsavai@Sun.COM 	}
48810491SRishi.Srivatsavai@Sun.COM 	if (get_count("force-protocol", &sstate, &value) == 0) {
48910491SRishi.Srivatsavai@Sun.COM 		cfg->force_version = value;
49010491SRishi.Srivatsavai@Sun.COM 		cfg->field_mask |= BR_CFG_FORCE_VER;
49110491SRishi.Srivatsavai@Sun.COM 	}
49210491SRishi.Srivatsavai@Sun.COM 
49310491SRishi.Srivatsavai@Sun.COM 	drop_composed(&sstate);
49410491SRishi.Srivatsavai@Sun.COM 	shut_down_scf(&sstate);
49510491SRishi.Srivatsavai@Sun.COM 	return (DLADM_STATUS_OK);
49610491SRishi.Srivatsavai@Sun.COM }
49710491SRishi.Srivatsavai@Sun.COM 
49810491SRishi.Srivatsavai@Sun.COM /*
49910491SRishi.Srivatsavai@Sun.COM  * Retrieve special non-settable and undocumented parameters.
50010491SRishi.Srivatsavai@Sun.COM  */
50110491SRishi.Srivatsavai@Sun.COM dladm_status_t
50210491SRishi.Srivatsavai@Sun.COM dladm_bridge_get_privprop(const char *instance_name, boolean_t *debugp,
50310491SRishi.Srivatsavai@Sun.COM     uint32_t *tablemaxp)
50410491SRishi.Srivatsavai@Sun.COM {
50510491SRishi.Srivatsavai@Sun.COM 	scf_state_t sstate;
50610491SRishi.Srivatsavai@Sun.COM 	uint64_t value;
50710491SRishi.Srivatsavai@Sun.COM 
50810491SRishi.Srivatsavai@Sun.COM 	*debugp = B_FALSE;
50910491SRishi.Srivatsavai@Sun.COM 	*tablemaxp = 10000;
51010491SRishi.Srivatsavai@Sun.COM 
51110491SRishi.Srivatsavai@Sun.COM 	if (bind_instance(BRIDGE_SVC_NAME, instance_name, &sstate) != 0)
51210491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_REPOSITORYINVAL);
51310491SRishi.Srivatsavai@Sun.COM 
51410491SRishi.Srivatsavai@Sun.COM 	if (get_composed_properties("config", B_TRUE, &sstate) != 0) {
51510491SRishi.Srivatsavai@Sun.COM 		shut_down_scf(&sstate);
51610491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_REPOSITORYINVAL);
51710491SRishi.Srivatsavai@Sun.COM 	}
51810491SRishi.Srivatsavai@Sun.COM 
51910491SRishi.Srivatsavai@Sun.COM 	(void) get_boolean("debug", &sstate, debugp);
52010491SRishi.Srivatsavai@Sun.COM 	if (get_count("table-maximum", &sstate, &value) == 0)
52110491SRishi.Srivatsavai@Sun.COM 		*tablemaxp = (uint32_t)value;
52210491SRishi.Srivatsavai@Sun.COM 
52310491SRishi.Srivatsavai@Sun.COM 	drop_composed(&sstate);
52410491SRishi.Srivatsavai@Sun.COM 	shut_down_scf(&sstate);
52510491SRishi.Srivatsavai@Sun.COM 	return (DLADM_STATUS_OK);
52610491SRishi.Srivatsavai@Sun.COM }
52710491SRishi.Srivatsavai@Sun.COM 
52810491SRishi.Srivatsavai@Sun.COM static boolean_t
52910491SRishi.Srivatsavai@Sun.COM set_count_property(scf_handle_t *handle, scf_transaction_t *tran,
53010491SRishi.Srivatsavai@Sun.COM     const char *propname, uint64_t propval)
53110491SRishi.Srivatsavai@Sun.COM {
53210491SRishi.Srivatsavai@Sun.COM 	scf_transaction_entry_t *entry;
53310491SRishi.Srivatsavai@Sun.COM 	scf_value_t *value = NULL;
53410491SRishi.Srivatsavai@Sun.COM 
53510491SRishi.Srivatsavai@Sun.COM 	if ((entry = scf_entry_create(handle)) == NULL)
53610491SRishi.Srivatsavai@Sun.COM 		return (B_FALSE);
53710491SRishi.Srivatsavai@Sun.COM 
53810491SRishi.Srivatsavai@Sun.COM 	if ((value = scf_value_create(handle)) == NULL)
53910491SRishi.Srivatsavai@Sun.COM 		goto out;
54010491SRishi.Srivatsavai@Sun.COM 	if (scf_transaction_property_new(tran, entry, propname,
54110491SRishi.Srivatsavai@Sun.COM 	    SCF_TYPE_COUNT) != 0 &&
54210491SRishi.Srivatsavai@Sun.COM 	    scf_transaction_property_change(tran, entry, propname,
54310491SRishi.Srivatsavai@Sun.COM 	    SCF_TYPE_COUNT) != 0)
54410491SRishi.Srivatsavai@Sun.COM 		goto out;
54510491SRishi.Srivatsavai@Sun.COM 	scf_value_set_count(value, propval);
54610491SRishi.Srivatsavai@Sun.COM 	if (scf_entry_add_value(entry, value) == 0)
54710491SRishi.Srivatsavai@Sun.COM 		return (B_TRUE);
54810491SRishi.Srivatsavai@Sun.COM 
54910491SRishi.Srivatsavai@Sun.COM out:
55010491SRishi.Srivatsavai@Sun.COM 	if (value != NULL)
55110491SRishi.Srivatsavai@Sun.COM 		scf_value_destroy(value);
55210491SRishi.Srivatsavai@Sun.COM 
55310491SRishi.Srivatsavai@Sun.COM 	scf_entry_destroy_children(entry);
55410491SRishi.Srivatsavai@Sun.COM 	scf_entry_destroy(entry);
55510491SRishi.Srivatsavai@Sun.COM 
55610491SRishi.Srivatsavai@Sun.COM 	return (B_FALSE);
55710491SRishi.Srivatsavai@Sun.COM }
55810491SRishi.Srivatsavai@Sun.COM 
55910491SRishi.Srivatsavai@Sun.COM static boolean_t
56010491SRishi.Srivatsavai@Sun.COM set_string_property(scf_handle_t *handle, scf_transaction_t *tran,
56110491SRishi.Srivatsavai@Sun.COM     const char *propname, const char *propval)
56210491SRishi.Srivatsavai@Sun.COM {
56310491SRishi.Srivatsavai@Sun.COM 	scf_transaction_entry_t *entry;
56410491SRishi.Srivatsavai@Sun.COM 	scf_value_t *value = NULL;
56510491SRishi.Srivatsavai@Sun.COM 
56610491SRishi.Srivatsavai@Sun.COM 	if ((entry = scf_entry_create(handle)) == NULL)
56710491SRishi.Srivatsavai@Sun.COM 		return (B_FALSE);
56810491SRishi.Srivatsavai@Sun.COM 
56910491SRishi.Srivatsavai@Sun.COM 	if ((value = scf_value_create(handle)) == NULL)
57010491SRishi.Srivatsavai@Sun.COM 		goto out;
57110491SRishi.Srivatsavai@Sun.COM 	if (scf_transaction_property_new(tran, entry, propname,
57210491SRishi.Srivatsavai@Sun.COM 	    SCF_TYPE_ASTRING) != 0 &&
57310491SRishi.Srivatsavai@Sun.COM 	    scf_transaction_property_change(tran, entry, propname,
57410491SRishi.Srivatsavai@Sun.COM 	    SCF_TYPE_ASTRING) != 0)
57510491SRishi.Srivatsavai@Sun.COM 		goto out;
57610491SRishi.Srivatsavai@Sun.COM 	if (scf_value_set_astring(value, propval) != 0)
57710491SRishi.Srivatsavai@Sun.COM 		goto out;
57810491SRishi.Srivatsavai@Sun.COM 	if (scf_entry_add_value(entry, value) == 0)
57910491SRishi.Srivatsavai@Sun.COM 		return (B_TRUE);
58010491SRishi.Srivatsavai@Sun.COM 
58110491SRishi.Srivatsavai@Sun.COM out:
58210491SRishi.Srivatsavai@Sun.COM 	if (value != NULL)
58310491SRishi.Srivatsavai@Sun.COM 		scf_value_destroy(value);
58410491SRishi.Srivatsavai@Sun.COM 
58510491SRishi.Srivatsavai@Sun.COM 	scf_entry_destroy_children(entry);
58610491SRishi.Srivatsavai@Sun.COM 	scf_entry_destroy(entry);
58710491SRishi.Srivatsavai@Sun.COM 
58810491SRishi.Srivatsavai@Sun.COM 	return (B_FALSE);
58910491SRishi.Srivatsavai@Sun.COM }
59010491SRishi.Srivatsavai@Sun.COM 
59110491SRishi.Srivatsavai@Sun.COM static boolean_t
59210491SRishi.Srivatsavai@Sun.COM set_fmri_property(scf_handle_t *handle, scf_transaction_t *tran,
59310491SRishi.Srivatsavai@Sun.COM     const char *propname, const char *propval)
59410491SRishi.Srivatsavai@Sun.COM {
59510491SRishi.Srivatsavai@Sun.COM 	scf_transaction_entry_t *entry;
59610491SRishi.Srivatsavai@Sun.COM 	scf_value_t *value = NULL;
59710491SRishi.Srivatsavai@Sun.COM 
59810491SRishi.Srivatsavai@Sun.COM 	if ((entry = scf_entry_create(handle)) == NULL)
59910491SRishi.Srivatsavai@Sun.COM 		return (B_FALSE);
60010491SRishi.Srivatsavai@Sun.COM 
60110491SRishi.Srivatsavai@Sun.COM 	if ((value = scf_value_create(handle)) == NULL)
60210491SRishi.Srivatsavai@Sun.COM 		goto out;
60310491SRishi.Srivatsavai@Sun.COM 	if (scf_transaction_property_new(tran, entry, propname,
60410491SRishi.Srivatsavai@Sun.COM 	    SCF_TYPE_FMRI) != 0 &&
60510491SRishi.Srivatsavai@Sun.COM 	    scf_transaction_property_change(tran, entry, propname,
60610491SRishi.Srivatsavai@Sun.COM 	    SCF_TYPE_FMRI) != 0)
60710491SRishi.Srivatsavai@Sun.COM 		goto out;
60810491SRishi.Srivatsavai@Sun.COM 	if (scf_value_set_from_string(value, SCF_TYPE_FMRI, propval) != 0)
60910491SRishi.Srivatsavai@Sun.COM 		goto out;
61010491SRishi.Srivatsavai@Sun.COM 	if (scf_entry_add_value(entry, value) == 0)
61110491SRishi.Srivatsavai@Sun.COM 		return (B_TRUE);
61210491SRishi.Srivatsavai@Sun.COM 
61310491SRishi.Srivatsavai@Sun.COM out:
61410491SRishi.Srivatsavai@Sun.COM 	if (value != NULL)
61510491SRishi.Srivatsavai@Sun.COM 		scf_value_destroy(value);
61610491SRishi.Srivatsavai@Sun.COM 
61710491SRishi.Srivatsavai@Sun.COM 	scf_entry_destroy_children(entry);
61810491SRishi.Srivatsavai@Sun.COM 	scf_entry_destroy(entry);
61910491SRishi.Srivatsavai@Sun.COM 
62010491SRishi.Srivatsavai@Sun.COM 	return (B_FALSE);
62110491SRishi.Srivatsavai@Sun.COM }
62210491SRishi.Srivatsavai@Sun.COM 
62310491SRishi.Srivatsavai@Sun.COM static dladm_status_t
62410491SRishi.Srivatsavai@Sun.COM dladm_bridge_persist_conf(dladm_handle_t handle, const char *link,
62510491SRishi.Srivatsavai@Sun.COM     datalink_id_t linkid)
62610491SRishi.Srivatsavai@Sun.COM {
62710491SRishi.Srivatsavai@Sun.COM 	dladm_conf_t conf = DLADM_INVALID_CONF;
62810491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
62910491SRishi.Srivatsavai@Sun.COM 
63010491SRishi.Srivatsavai@Sun.COM 	status = dladm_create_conf(handle, link, linkid, DATALINK_CLASS_BRIDGE,
63110491SRishi.Srivatsavai@Sun.COM 	    DL_ETHER, &conf);
63210491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_OK) {
63310491SRishi.Srivatsavai@Sun.COM 		/*
63410491SRishi.Srivatsavai@Sun.COM 		 * Create the datalink entry for the bridge.  Note that all of
63510491SRishi.Srivatsavai@Sun.COM 		 * the real configuration information is in SMF.
63610491SRishi.Srivatsavai@Sun.COM 		 */
63710491SRishi.Srivatsavai@Sun.COM 		status = dladm_write_conf(handle, conf);
63810491SRishi.Srivatsavai@Sun.COM 		dladm_destroy_conf(handle, conf);
63910491SRishi.Srivatsavai@Sun.COM 	}
64010491SRishi.Srivatsavai@Sun.COM 	return (status);
64110491SRishi.Srivatsavai@Sun.COM }
64210491SRishi.Srivatsavai@Sun.COM 
64310491SRishi.Srivatsavai@Sun.COM /* Convert bridge protection option string to dladm_bridge_prot_t */
64410491SRishi.Srivatsavai@Sun.COM dladm_status_t
64510491SRishi.Srivatsavai@Sun.COM dladm_bridge_str2prot(const char *str, dladm_bridge_prot_t *brprotp)
64610491SRishi.Srivatsavai@Sun.COM {
64710491SRishi.Srivatsavai@Sun.COM 	if (strcmp(str, "stp") == 0)
64810491SRishi.Srivatsavai@Sun.COM 		*brprotp = DLADM_BRIDGE_PROT_STP;
64910491SRishi.Srivatsavai@Sun.COM 	else if (strcmp(str, "trill") == 0)
65010491SRishi.Srivatsavai@Sun.COM 		*brprotp = DLADM_BRIDGE_PROT_TRILL;
65110491SRishi.Srivatsavai@Sun.COM 	else
65210491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_BADARG);
65310491SRishi.Srivatsavai@Sun.COM 	return (DLADM_STATUS_OK);
65410491SRishi.Srivatsavai@Sun.COM }
65510491SRishi.Srivatsavai@Sun.COM 
65610491SRishi.Srivatsavai@Sun.COM /* Convert bridge protection option from dladm_bridge_prot_t to string */
65710491SRishi.Srivatsavai@Sun.COM const char *
65810491SRishi.Srivatsavai@Sun.COM dladm_bridge_prot2str(dladm_bridge_prot_t brprot)
65910491SRishi.Srivatsavai@Sun.COM {
66010491SRishi.Srivatsavai@Sun.COM 	switch (brprot) {
66110491SRishi.Srivatsavai@Sun.COM 	case DLADM_BRIDGE_PROT_STP:
66210491SRishi.Srivatsavai@Sun.COM 		return ("stp");
66310491SRishi.Srivatsavai@Sun.COM 	case DLADM_BRIDGE_PROT_TRILL:
66410491SRishi.Srivatsavai@Sun.COM 		return ("trill");
66510491SRishi.Srivatsavai@Sun.COM 	default:
66610491SRishi.Srivatsavai@Sun.COM 		return ("unknown");
66710491SRishi.Srivatsavai@Sun.COM 	}
66810491SRishi.Srivatsavai@Sun.COM }
66910491SRishi.Srivatsavai@Sun.COM 
67010491SRishi.Srivatsavai@Sun.COM static dladm_status_t
67110491SRishi.Srivatsavai@Sun.COM enable_instance(const char *service_name, const char *instance)
67210491SRishi.Srivatsavai@Sun.COM {
67310491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
67410491SRishi.Srivatsavai@Sun.COM 	char *fmri = alloc_fmri(service_name, instance);
67510491SRishi.Srivatsavai@Sun.COM 
67610491SRishi.Srivatsavai@Sun.COM 	if (fmri == NULL)
67710491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_NOMEM);
67810491SRishi.Srivatsavai@Sun.COM 	status = smf_enable_instance(fmri, 0) == 0 ?
67910491SRishi.Srivatsavai@Sun.COM 	    DLADM_STATUS_OK : DLADM_STATUS_FAILED;
68010491SRishi.Srivatsavai@Sun.COM 	free(fmri);
68110491SRishi.Srivatsavai@Sun.COM 	return (status);
68210491SRishi.Srivatsavai@Sun.COM }
68310491SRishi.Srivatsavai@Sun.COM 
68410491SRishi.Srivatsavai@Sun.COM /*
68510491SRishi.Srivatsavai@Sun.COM  * Shut down a possibly-running service instance.  If this is a permanent
68610491SRishi.Srivatsavai@Sun.COM  * change, then delete it from the system.
68710491SRishi.Srivatsavai@Sun.COM  */
68810491SRishi.Srivatsavai@Sun.COM static dladm_status_t
68910491SRishi.Srivatsavai@Sun.COM shut_down_instance(const char *service_name, const char *instance,
69010491SRishi.Srivatsavai@Sun.COM     uint32_t flags)
69110491SRishi.Srivatsavai@Sun.COM {
69210491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
69310491SRishi.Srivatsavai@Sun.COM 	char *fmri = alloc_fmri(service_name, instance);
69410491SRishi.Srivatsavai@Sun.COM 	char *state;
69510491SRishi.Srivatsavai@Sun.COM 	scf_state_t sstate;
69610491SRishi.Srivatsavai@Sun.COM 
69710491SRishi.Srivatsavai@Sun.COM 	if (fmri == NULL)
69810491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_NOMEM);
69910491SRishi.Srivatsavai@Sun.COM 
70010491SRishi.Srivatsavai@Sun.COM 	if (smf_disable_instance(fmri,
70110491SRishi.Srivatsavai@Sun.COM 	    flags & DLADM_OPT_PERSIST ? 0 : SMF_TEMPORARY) == 0) {
70210491SRishi.Srivatsavai@Sun.COM 		useconds_t usecs, umax;
70310491SRishi.Srivatsavai@Sun.COM 
70410491SRishi.Srivatsavai@Sun.COM 		/* If we can disable, then wait for it to happen. */
70510491SRishi.Srivatsavai@Sun.COM 		umax = DEFAULT_TIMEOUT;
70610491SRishi.Srivatsavai@Sun.COM 		for (usecs = INIT_WAIT_USECS; umax != 0; umax -= usecs) {
70710491SRishi.Srivatsavai@Sun.COM 			state = smf_get_state(fmri);
70810491SRishi.Srivatsavai@Sun.COM 			if (state != NULL &&
70910491SRishi.Srivatsavai@Sun.COM 			    strcmp(state, SCF_STATE_STRING_DISABLED) == 0)
71010491SRishi.Srivatsavai@Sun.COM 				break;
71110491SRishi.Srivatsavai@Sun.COM 			free(state);
71210491SRishi.Srivatsavai@Sun.COM 			usecs *= 2;
71310491SRishi.Srivatsavai@Sun.COM 			if (usecs > umax)
71410491SRishi.Srivatsavai@Sun.COM 				usecs = umax;
71510491SRishi.Srivatsavai@Sun.COM 			(void) usleep(usecs);
71610491SRishi.Srivatsavai@Sun.COM 		}
71710491SRishi.Srivatsavai@Sun.COM 		if (umax == 0) {
71810491SRishi.Srivatsavai@Sun.COM 			state = smf_get_state(fmri);
71910491SRishi.Srivatsavai@Sun.COM 			if (state != NULL &&
72010491SRishi.Srivatsavai@Sun.COM 			    strcmp(state, SCF_STATE_STRING_DISABLED) == 0)
72110491SRishi.Srivatsavai@Sun.COM 				umax = 1;
72210491SRishi.Srivatsavai@Sun.COM 		}
72310491SRishi.Srivatsavai@Sun.COM 		free(state);
72410491SRishi.Srivatsavai@Sun.COM 		status = umax != 0 ? DLADM_STATUS_OK : DLADM_STATUS_FAILED;
72510491SRishi.Srivatsavai@Sun.COM 	} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
72610491SRishi.Srivatsavai@Sun.COM 		free(fmri);
72710491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_OK);
72810491SRishi.Srivatsavai@Sun.COM 	} else {
72910491SRishi.Srivatsavai@Sun.COM 		status = DLADM_STATUS_FAILED;
73010491SRishi.Srivatsavai@Sun.COM 	}
73110491SRishi.Srivatsavai@Sun.COM 
73210491SRishi.Srivatsavai@Sun.COM 	free(fmri);
73310491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_OK && (flags & DLADM_OPT_PERSIST) &&
73410491SRishi.Srivatsavai@Sun.COM 	    bind_instance(service_name, instance, &sstate) == 0) {
73510491SRishi.Srivatsavai@Sun.COM 		(void) scf_instance_delete(sstate.ss_inst);
73610491SRishi.Srivatsavai@Sun.COM 		shut_down_scf(&sstate);
73710491SRishi.Srivatsavai@Sun.COM 	}
73810491SRishi.Srivatsavai@Sun.COM 
73910491SRishi.Srivatsavai@Sun.COM 	return (status);
74010491SRishi.Srivatsavai@Sun.COM }
74110491SRishi.Srivatsavai@Sun.COM 
74210491SRishi.Srivatsavai@Sun.COM static dladm_status_t
74310491SRishi.Srivatsavai@Sun.COM disable_trill(const char *instance, uint32_t flags)
74410491SRishi.Srivatsavai@Sun.COM {
74510491SRishi.Srivatsavai@Sun.COM 	return (shut_down_instance(TRILL_SVC_NAME, instance, flags));
74610491SRishi.Srivatsavai@Sun.COM }
74710491SRishi.Srivatsavai@Sun.COM 
74810491SRishi.Srivatsavai@Sun.COM /*
74910491SRishi.Srivatsavai@Sun.COM  * To enable TRILL, we must create a new instance of the TRILL service, then
75010491SRishi.Srivatsavai@Sun.COM  * add proper dependencies to it, and finally mark it as enabled.  The
75110491SRishi.Srivatsavai@Sun.COM  * dependencies will keep it from going on-line until the bridge is running.
75210491SRishi.Srivatsavai@Sun.COM  */
75310491SRishi.Srivatsavai@Sun.COM static dladm_status_t
75410491SRishi.Srivatsavai@Sun.COM enable_trill(const char *instance)
75510491SRishi.Srivatsavai@Sun.COM {
75610491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status = DLADM_STATUS_FAILED;
75710491SRishi.Srivatsavai@Sun.COM 	char *fmri = NULL;
75810491SRishi.Srivatsavai@Sun.COM 	scf_state_t sstate;
75910491SRishi.Srivatsavai@Sun.COM 	scf_transaction_t *tran = NULL;
76010491SRishi.Srivatsavai@Sun.COM 	boolean_t new_instance = B_FALSE;
76110491SRishi.Srivatsavai@Sun.COM 	boolean_t new_pg = B_FALSE;
76210491SRishi.Srivatsavai@Sun.COM 	int rv;
76310491SRishi.Srivatsavai@Sun.COM 
76410491SRishi.Srivatsavai@Sun.COM 	/*
76510491SRishi.Srivatsavai@Sun.COM 	 * This check is here in case the user has installed and then removed
76610491SRishi.Srivatsavai@Sun.COM 	 * the package.  SMF should remove the manifest, but currently does
76710491SRishi.Srivatsavai@Sun.COM 	 * not.
76810491SRishi.Srivatsavai@Sun.COM 	 */
76910491SRishi.Srivatsavai@Sun.COM 	if (access("/usr/sbin/trilld", F_OK) != 0)
77010491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_OPTMISSING);
77110491SRishi.Srivatsavai@Sun.COM 
77210491SRishi.Srivatsavai@Sun.COM 	if ((status = exact_instance(TRILL_SVC_NAME, &sstate)) !=
77310491SRishi.Srivatsavai@Sun.COM 	    DLADM_STATUS_OK)
77410491SRishi.Srivatsavai@Sun.COM 		goto out;
77510491SRishi.Srivatsavai@Sun.COM 
77610491SRishi.Srivatsavai@Sun.COM 	status = DLADM_STATUS_FAILED;
77710491SRishi.Srivatsavai@Sun.COM 	if (scf_service_get_instance(sstate.ss_svc, instance, sstate.ss_inst) !=
77810491SRishi.Srivatsavai@Sun.COM 	    0) {
77910491SRishi.Srivatsavai@Sun.COM 		if (scf_service_add_instance(sstate.ss_svc, instance,
78010491SRishi.Srivatsavai@Sun.COM 		    sstate.ss_inst) != 0)
78110491SRishi.Srivatsavai@Sun.COM 			goto out;
78210491SRishi.Srivatsavai@Sun.COM 		new_instance = B_TRUE;
78310491SRishi.Srivatsavai@Sun.COM 	}
78410491SRishi.Srivatsavai@Sun.COM 
78510491SRishi.Srivatsavai@Sun.COM 	if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL)
78610491SRishi.Srivatsavai@Sun.COM 		goto out;
78710491SRishi.Srivatsavai@Sun.COM 
78810491SRishi.Srivatsavai@Sun.COM 	if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL)
78910491SRishi.Srivatsavai@Sun.COM 		goto out;
79010491SRishi.Srivatsavai@Sun.COM 
79110491SRishi.Srivatsavai@Sun.COM 	if (scf_instance_get_pg(sstate.ss_inst, "bridging",
79210491SRishi.Srivatsavai@Sun.COM 	    sstate.ss_pg) == 0) {
79310491SRishi.Srivatsavai@Sun.COM 		status = DLADM_STATUS_OK;
79410491SRishi.Srivatsavai@Sun.COM 		goto out;
79510491SRishi.Srivatsavai@Sun.COM 	}
79610491SRishi.Srivatsavai@Sun.COM 
79710491SRishi.Srivatsavai@Sun.COM 	if ((fmri = alloc_fmri(BRIDGE_SVC_NAME, instance)) == NULL)
79810491SRishi.Srivatsavai@Sun.COM 		goto out;
79910491SRishi.Srivatsavai@Sun.COM 
80010491SRishi.Srivatsavai@Sun.COM 	if (scf_instance_add_pg(sstate.ss_inst, "bridging",
80110491SRishi.Srivatsavai@Sun.COM 	    SCF_GROUP_DEPENDENCY, 0, sstate.ss_pg) != 0)
80210491SRishi.Srivatsavai@Sun.COM 		goto out;
80310491SRishi.Srivatsavai@Sun.COM 
80410491SRishi.Srivatsavai@Sun.COM 	new_pg = B_TRUE;
80510491SRishi.Srivatsavai@Sun.COM 	do {
80610491SRishi.Srivatsavai@Sun.COM 		if (scf_transaction_start(tran, sstate.ss_pg) != 0)
80710491SRishi.Srivatsavai@Sun.COM 			goto out;
80810491SRishi.Srivatsavai@Sun.COM 
80910491SRishi.Srivatsavai@Sun.COM 		if (!set_string_property(sstate.ss_handle, tran,
81010491SRishi.Srivatsavai@Sun.COM 		    SCF_PROPERTY_GROUPING, SCF_DEP_REQUIRE_ALL))
81110491SRishi.Srivatsavai@Sun.COM 			goto out;
81210491SRishi.Srivatsavai@Sun.COM 		if (!set_string_property(sstate.ss_handle, tran,
81310491SRishi.Srivatsavai@Sun.COM 		    SCF_PROPERTY_RESTART_ON, SCF_DEP_RESET_ON_RESTART))
81410491SRishi.Srivatsavai@Sun.COM 			goto out;
81510491SRishi.Srivatsavai@Sun.COM 		if (!set_string_property(sstate.ss_handle, tran,
81610491SRishi.Srivatsavai@Sun.COM 		    SCF_PROPERTY_TYPE, "service"))
81710491SRishi.Srivatsavai@Sun.COM 			goto out;
81810491SRishi.Srivatsavai@Sun.COM 		if (!set_fmri_property(sstate.ss_handle, tran,
81910491SRishi.Srivatsavai@Sun.COM 		    SCF_PROPERTY_ENTITIES, fmri))
82010491SRishi.Srivatsavai@Sun.COM 			goto out;
82110491SRishi.Srivatsavai@Sun.COM 
82210491SRishi.Srivatsavai@Sun.COM 		rv = scf_transaction_commit(tran);
82310491SRishi.Srivatsavai@Sun.COM 		scf_transaction_reset(tran);
82410491SRishi.Srivatsavai@Sun.COM 		if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1)
82510491SRishi.Srivatsavai@Sun.COM 			goto out;
82610491SRishi.Srivatsavai@Sun.COM 	} while (rv == 0);
82710491SRishi.Srivatsavai@Sun.COM 	if (rv != 1)
82810491SRishi.Srivatsavai@Sun.COM 		goto out;
82910491SRishi.Srivatsavai@Sun.COM 
83010491SRishi.Srivatsavai@Sun.COM 	status = DLADM_STATUS_OK;
83110491SRishi.Srivatsavai@Sun.COM 
83210491SRishi.Srivatsavai@Sun.COM out:
83310491SRishi.Srivatsavai@Sun.COM 	free(fmri);
83410491SRishi.Srivatsavai@Sun.COM 	if (tran != NULL) {
83510491SRishi.Srivatsavai@Sun.COM 		scf_transaction_destroy_children(tran);
83610491SRishi.Srivatsavai@Sun.COM 		scf_transaction_destroy(tran);
83710491SRishi.Srivatsavai@Sun.COM 	}
83810491SRishi.Srivatsavai@Sun.COM 
83910491SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK && new_pg)
84010491SRishi.Srivatsavai@Sun.COM 		(void) scf_pg_delete(sstate.ss_pg);
84110491SRishi.Srivatsavai@Sun.COM 
84210491SRishi.Srivatsavai@Sun.COM 	drop_composed(&sstate);
84310491SRishi.Srivatsavai@Sun.COM 
84410491SRishi.Srivatsavai@Sun.COM 	/*
84510491SRishi.Srivatsavai@Sun.COM 	 * If we created an instance and then failed, then remove the instance
84610491SRishi.Srivatsavai@Sun.COM 	 * from the system.
84710491SRishi.Srivatsavai@Sun.COM 	 */
84810491SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK && new_instance)
84910491SRishi.Srivatsavai@Sun.COM 		(void) scf_instance_delete(sstate.ss_inst);
85010491SRishi.Srivatsavai@Sun.COM 
85110491SRishi.Srivatsavai@Sun.COM 	shut_down_scf(&sstate);
85210491SRishi.Srivatsavai@Sun.COM 
85310491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_OK)
85410491SRishi.Srivatsavai@Sun.COM 		status = enable_instance(TRILL_SVC_NAME, instance);
85510491SRishi.Srivatsavai@Sun.COM 
85610491SRishi.Srivatsavai@Sun.COM 	return (status);
85710491SRishi.Srivatsavai@Sun.COM }
85810491SRishi.Srivatsavai@Sun.COM 
85910491SRishi.Srivatsavai@Sun.COM /*
86010491SRishi.Srivatsavai@Sun.COM  * Create a new bridge or modify an existing one.  Update the SMF configuration
86110491SRishi.Srivatsavai@Sun.COM  * and add links.
86210491SRishi.Srivatsavai@Sun.COM  *
86310491SRishi.Srivatsavai@Sun.COM  * Input timer values are in IEEE scaled (* 256) format.
86410491SRishi.Srivatsavai@Sun.COM  */
86510491SRishi.Srivatsavai@Sun.COM dladm_status_t
86610491SRishi.Srivatsavai@Sun.COM dladm_bridge_configure(dladm_handle_t handle, const char *name,
86710491SRishi.Srivatsavai@Sun.COM     const UID_STP_CFG_T *cfg, dladm_bridge_prot_t brprot, uint32_t flags)
86810491SRishi.Srivatsavai@Sun.COM {
86910491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
87010491SRishi.Srivatsavai@Sun.COM 	scf_state_t sstate;
87110491SRishi.Srivatsavai@Sun.COM 	scf_transaction_t *tran = NULL;
87210491SRishi.Srivatsavai@Sun.COM 	boolean_t new_instance = B_FALSE;
87310491SRishi.Srivatsavai@Sun.COM 	boolean_t new_pg = B_FALSE;
87410491SRishi.Srivatsavai@Sun.COM 	datalink_id_t linkid = DATALINK_INVALID_LINKID;
87510491SRishi.Srivatsavai@Sun.COM 	char linkname[MAXLINKNAMELEN];
87610491SRishi.Srivatsavai@Sun.COM 	int rv;
87710491SRishi.Srivatsavai@Sun.COM 
87810491SRishi.Srivatsavai@Sun.COM 	if (!dladm_valid_bridgename(name))
87910491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_FAILED);
88010491SRishi.Srivatsavai@Sun.COM 
88110491SRishi.Srivatsavai@Sun.COM 	if (flags & DLADM_OPT_CREATE) {
88210491SRishi.Srivatsavai@Sun.COM 		/*
88310491SRishi.Srivatsavai@Sun.COM 		 * This check is here in case the user has installed and then
88410491SRishi.Srivatsavai@Sun.COM 		 * removed the package.  SMF should remove the manifest, but
88510491SRishi.Srivatsavai@Sun.COM 		 * currently does not.
88610491SRishi.Srivatsavai@Sun.COM 		 */
88710491SRishi.Srivatsavai@Sun.COM 		if (access("/usr/lib/bridged", F_OK) != 0)
88810491SRishi.Srivatsavai@Sun.COM 			return (DLADM_STATUS_OPTMISSING);
88910491SRishi.Srivatsavai@Sun.COM 
89010491SRishi.Srivatsavai@Sun.COM 		(void) snprintf(linkname, sizeof (linkname), "%s0", name);
89110491SRishi.Srivatsavai@Sun.COM 		status = dladm_create_datalink_id(handle, linkname,
89210491SRishi.Srivatsavai@Sun.COM 		    DATALINK_CLASS_BRIDGE, DL_ETHER,
89310491SRishi.Srivatsavai@Sun.COM 		    flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST), &linkid);
89410491SRishi.Srivatsavai@Sun.COM 		if (status != DLADM_STATUS_OK)
89510491SRishi.Srivatsavai@Sun.COM 			return (status);
89610491SRishi.Srivatsavai@Sun.COM 
89710491SRishi.Srivatsavai@Sun.COM 		if ((flags & DLADM_OPT_PERSIST) &&
89810491SRishi.Srivatsavai@Sun.COM 		    (status = dladm_bridge_persist_conf(handle, linkname,
89910491SRishi.Srivatsavai@Sun.COM 		    linkid) != DLADM_STATUS_OK))
90010491SRishi.Srivatsavai@Sun.COM 			goto dladm_fail;
90110491SRishi.Srivatsavai@Sun.COM 	}
90210491SRishi.Srivatsavai@Sun.COM 
90310491SRishi.Srivatsavai@Sun.COM 	if (brprot == DLADM_BRIDGE_PROT_TRILL)
90410491SRishi.Srivatsavai@Sun.COM 		status = enable_trill(name);
90510491SRishi.Srivatsavai@Sun.COM 	else
90610491SRishi.Srivatsavai@Sun.COM 		status = disable_trill(name, flags);
90710491SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK)
90810491SRishi.Srivatsavai@Sun.COM 		goto dladm_fail;
90910491SRishi.Srivatsavai@Sun.COM 
91010491SRishi.Srivatsavai@Sun.COM 	if ((status = exact_instance(BRIDGE_SVC_NAME, &sstate)) !=
91110491SRishi.Srivatsavai@Sun.COM 	    DLADM_STATUS_OK)
91210491SRishi.Srivatsavai@Sun.COM 		goto out;
91310491SRishi.Srivatsavai@Sun.COM 
91410491SRishi.Srivatsavai@Sun.COM 	/* set up for a series of scf calls */
91510491SRishi.Srivatsavai@Sun.COM 	status = DLADM_STATUS_FAILED;
91610491SRishi.Srivatsavai@Sun.COM 
91710491SRishi.Srivatsavai@Sun.COM 	if (scf_service_get_instance(sstate.ss_svc, name, sstate.ss_inst) ==
91810491SRishi.Srivatsavai@Sun.COM 	    0) {
91910491SRishi.Srivatsavai@Sun.COM 		if (flags & DLADM_OPT_CREATE) {
92010491SRishi.Srivatsavai@Sun.COM 			status = DLADM_STATUS_EXIST;
92110491SRishi.Srivatsavai@Sun.COM 			goto out;
92210491SRishi.Srivatsavai@Sun.COM 		}
92310491SRishi.Srivatsavai@Sun.COM 	} else {
92410491SRishi.Srivatsavai@Sun.COM 		if (!(flags & DLADM_OPT_CREATE)) {
92510491SRishi.Srivatsavai@Sun.COM 			status = DLADM_STATUS_NOTFOUND;
92610491SRishi.Srivatsavai@Sun.COM 			goto out;
92710491SRishi.Srivatsavai@Sun.COM 		}
92810491SRishi.Srivatsavai@Sun.COM 		if (scf_service_add_instance(sstate.ss_svc, name,
92910491SRishi.Srivatsavai@Sun.COM 		    sstate.ss_inst) != 0)
93010491SRishi.Srivatsavai@Sun.COM 			goto out;
93110491SRishi.Srivatsavai@Sun.COM 		new_instance = B_TRUE;
93210491SRishi.Srivatsavai@Sun.COM 	}
93310491SRishi.Srivatsavai@Sun.COM 
93410491SRishi.Srivatsavai@Sun.COM 	if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL)
93510491SRishi.Srivatsavai@Sun.COM 		goto out;
93610491SRishi.Srivatsavai@Sun.COM 
93710491SRishi.Srivatsavai@Sun.COM 	if (cfg->field_mask & BR_CFG_ALL) {
93810491SRishi.Srivatsavai@Sun.COM 		if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL)
93910491SRishi.Srivatsavai@Sun.COM 			goto out;
94010491SRishi.Srivatsavai@Sun.COM 		if (scf_instance_add_pg(sstate.ss_inst, "config",
94110491SRishi.Srivatsavai@Sun.COM 		    SCF_GROUP_APPLICATION, 0, sstate.ss_pg) == 0) {
94210491SRishi.Srivatsavai@Sun.COM 			new_pg = B_TRUE;
94310491SRishi.Srivatsavai@Sun.COM 		} else if (scf_instance_get_pg(sstate.ss_inst, "config",
94410491SRishi.Srivatsavai@Sun.COM 		    sstate.ss_pg) != 0) {
94510491SRishi.Srivatsavai@Sun.COM 			goto out;
94610491SRishi.Srivatsavai@Sun.COM 		}
94710491SRishi.Srivatsavai@Sun.COM 		do {
94810491SRishi.Srivatsavai@Sun.COM 			if (scf_transaction_start(tran, sstate.ss_pg) != 0)
94910491SRishi.Srivatsavai@Sun.COM 				goto out;
95010491SRishi.Srivatsavai@Sun.COM 
95110491SRishi.Srivatsavai@Sun.COM 			if ((cfg->field_mask & BR_CFG_PRIO) &&
95210491SRishi.Srivatsavai@Sun.COM 			    !set_count_property(sstate.ss_handle, tran,
95310491SRishi.Srivatsavai@Sun.COM 			    "priority", cfg->bridge_priority))
95410491SRishi.Srivatsavai@Sun.COM 				goto out;
95510491SRishi.Srivatsavai@Sun.COM 			if ((cfg->field_mask & BR_CFG_AGE) &&
95610491SRishi.Srivatsavai@Sun.COM 			    !set_count_property(sstate.ss_handle, tran,
95710491SRishi.Srivatsavai@Sun.COM 			    "max-age", cfg->max_age * IEEE_TIMER_SCALE))
95810491SRishi.Srivatsavai@Sun.COM 				goto out;
95910491SRishi.Srivatsavai@Sun.COM 			if ((cfg->field_mask & BR_CFG_HELLO) &&
96010491SRishi.Srivatsavai@Sun.COM 			    !set_count_property(sstate.ss_handle, tran,
96110491SRishi.Srivatsavai@Sun.COM 			    "hello-time", cfg->hello_time * IEEE_TIMER_SCALE))
96210491SRishi.Srivatsavai@Sun.COM 				goto out;
96310491SRishi.Srivatsavai@Sun.COM 			if ((cfg->field_mask & BR_CFG_DELAY) &&
96410491SRishi.Srivatsavai@Sun.COM 			    !set_count_property(sstate.ss_handle, tran,
96510491SRishi.Srivatsavai@Sun.COM 			    "forward-delay",
96610491SRishi.Srivatsavai@Sun.COM 			    cfg->forward_delay * IEEE_TIMER_SCALE))
96710491SRishi.Srivatsavai@Sun.COM 				goto out;
96810491SRishi.Srivatsavai@Sun.COM 			if ((cfg->field_mask & BR_CFG_FORCE_VER) &&
96910491SRishi.Srivatsavai@Sun.COM 			    !set_count_property(sstate.ss_handle, tran,
97010491SRishi.Srivatsavai@Sun.COM 			    "force-protocol", cfg->force_version))
97110491SRishi.Srivatsavai@Sun.COM 				goto out;
97210491SRishi.Srivatsavai@Sun.COM 
97310491SRishi.Srivatsavai@Sun.COM 			rv = scf_transaction_commit(tran);
97410491SRishi.Srivatsavai@Sun.COM 			scf_transaction_reset(tran);
97510491SRishi.Srivatsavai@Sun.COM 			if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1)
97610491SRishi.Srivatsavai@Sun.COM 				goto out;
97710491SRishi.Srivatsavai@Sun.COM 		} while (rv == 0);
97810491SRishi.Srivatsavai@Sun.COM 		if (rv != 1)
97910491SRishi.Srivatsavai@Sun.COM 			goto out;
98010491SRishi.Srivatsavai@Sun.COM 	}
98110491SRishi.Srivatsavai@Sun.COM 
98210491SRishi.Srivatsavai@Sun.COM 	/*
98310491SRishi.Srivatsavai@Sun.COM 	 * If we're modifying an existing and running bridge, then tell the
98410491SRishi.Srivatsavai@Sun.COM 	 * daemon to update the requested values.
98510491SRishi.Srivatsavai@Sun.COM 	 */
98610491SRishi.Srivatsavai@Sun.COM 	if ((flags & DLADM_OPT_ACTIVE) && !(flags & DLADM_OPT_CREATE))
98710491SRishi.Srivatsavai@Sun.COM 		status = bridge_refresh(name);
98810491SRishi.Srivatsavai@Sun.COM 	else
98910491SRishi.Srivatsavai@Sun.COM 		status = DLADM_STATUS_OK;
99010491SRishi.Srivatsavai@Sun.COM 
99110491SRishi.Srivatsavai@Sun.COM out:
99210491SRishi.Srivatsavai@Sun.COM 	if (tran != NULL) {
99310491SRishi.Srivatsavai@Sun.COM 		scf_transaction_destroy_children(tran);
99410491SRishi.Srivatsavai@Sun.COM 		scf_transaction_destroy(tran);
99510491SRishi.Srivatsavai@Sun.COM 	}
99610491SRishi.Srivatsavai@Sun.COM 
99710491SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK && new_pg)
99810491SRishi.Srivatsavai@Sun.COM 		(void) scf_pg_delete(sstate.ss_pg);
99910491SRishi.Srivatsavai@Sun.COM 
100010491SRishi.Srivatsavai@Sun.COM 	drop_composed(&sstate);
100110491SRishi.Srivatsavai@Sun.COM 
100210491SRishi.Srivatsavai@Sun.COM 	/*
100310491SRishi.Srivatsavai@Sun.COM 	 * If we created an instance and then failed, then remove the instance
100410491SRishi.Srivatsavai@Sun.COM 	 * from the system.
100510491SRishi.Srivatsavai@Sun.COM 	 */
100610491SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK && new_instance)
100710491SRishi.Srivatsavai@Sun.COM 		(void) scf_instance_delete(sstate.ss_inst);
100810491SRishi.Srivatsavai@Sun.COM 
100910491SRishi.Srivatsavai@Sun.COM 	shut_down_scf(&sstate);
101010491SRishi.Srivatsavai@Sun.COM 
101110491SRishi.Srivatsavai@Sun.COM 	/*
101210491SRishi.Srivatsavai@Sun.COM 	 * Remove the bridge linkid if we've allocated one in this function but
101310491SRishi.Srivatsavai@Sun.COM 	 * we've failed to set up the SMF properties.
101410491SRishi.Srivatsavai@Sun.COM 	 */
101510491SRishi.Srivatsavai@Sun.COM dladm_fail:
101610491SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK && linkid != DATALINK_INVALID_LINKID) {
101710491SRishi.Srivatsavai@Sun.COM 		(void) dladm_remove_conf(handle, linkid);
101810491SRishi.Srivatsavai@Sun.COM 		(void) dladm_destroy_datalink_id(handle, linkid, flags);
101910491SRishi.Srivatsavai@Sun.COM 	}
102010491SRishi.Srivatsavai@Sun.COM 
102110491SRishi.Srivatsavai@Sun.COM 	return (status);
102210491SRishi.Srivatsavai@Sun.COM }
102310491SRishi.Srivatsavai@Sun.COM 
102410491SRishi.Srivatsavai@Sun.COM /*
102510491SRishi.Srivatsavai@Sun.COM  * Enable a newly-created bridge in SMF by creating "general/enabled" and
102610491SRishi.Srivatsavai@Sun.COM  * deleting any "general_ovr/enabled" (used for temporary services).
102710491SRishi.Srivatsavai@Sun.COM  */
102810491SRishi.Srivatsavai@Sun.COM dladm_status_t
102910491SRishi.Srivatsavai@Sun.COM dladm_bridge_enable(const char *name)
103010491SRishi.Srivatsavai@Sun.COM {
103110491SRishi.Srivatsavai@Sun.COM 	return (enable_instance(BRIDGE_SVC_NAME, name));
103210491SRishi.Srivatsavai@Sun.COM }
103310491SRishi.Srivatsavai@Sun.COM 
103410491SRishi.Srivatsavai@Sun.COM /*
103510491SRishi.Srivatsavai@Sun.COM  * Set a link as a member of a bridge, or remove bridge membership.  If the
103610491SRishi.Srivatsavai@Sun.COM  * DLADM_OPT_CREATE flag is set, then we assume that the daemon isn't running.
103710491SRishi.Srivatsavai@Sun.COM  * In all other cases, we must tell the daemon to add or delete the link in
103810491SRishi.Srivatsavai@Sun.COM  * order to stay in sync.
103910491SRishi.Srivatsavai@Sun.COM  */
104010491SRishi.Srivatsavai@Sun.COM dladm_status_t
104110491SRishi.Srivatsavai@Sun.COM dladm_bridge_setlink(dladm_handle_t handle, datalink_id_t linkid,
104210491SRishi.Srivatsavai@Sun.COM     const char *bridge)
104310491SRishi.Srivatsavai@Sun.COM {
104410491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
104510491SRishi.Srivatsavai@Sun.COM 	dladm_conf_t conf;
104610491SRishi.Srivatsavai@Sun.COM 	char oldbridge[MAXLINKNAMELEN];
104710491SRishi.Srivatsavai@Sun.COM 	boolean_t has_oldbridge;
104810491SRishi.Srivatsavai@Sun.COM 	boolean_t changed = B_FALSE;
104910491SRishi.Srivatsavai@Sun.COM 
105010491SRishi.Srivatsavai@Sun.COM 	if (*bridge != '\0' && !dladm_valid_bridgename(bridge))
105110491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_FAILED);
105210491SRishi.Srivatsavai@Sun.COM 
105310491SRishi.Srivatsavai@Sun.COM 	if ((status = dladm_read_conf(handle, linkid, &conf)) !=
105410491SRishi.Srivatsavai@Sun.COM 	    DLADM_STATUS_OK)
105510491SRishi.Srivatsavai@Sun.COM 		return (status);
105610491SRishi.Srivatsavai@Sun.COM 
105710491SRishi.Srivatsavai@Sun.COM 	has_oldbridge = B_FALSE;
105810491SRishi.Srivatsavai@Sun.COM 	status = dladm_get_conf_field(handle, conf, FBRIDGE, oldbridge,
105910491SRishi.Srivatsavai@Sun.COM 	    sizeof (oldbridge));
106010491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_OK) {
106110491SRishi.Srivatsavai@Sun.COM 		/*
106210491SRishi.Srivatsavai@Sun.COM 		 * Don't allow a link to be reassigned directly from one bridge
106310491SRishi.Srivatsavai@Sun.COM 		 * to another.  It must be removed first.
106410491SRishi.Srivatsavai@Sun.COM 		 */
106510491SRishi.Srivatsavai@Sun.COM 		if (*oldbridge != '\0' && *bridge != '\0') {
106610491SRishi.Srivatsavai@Sun.COM 			status = DLADM_STATUS_EXIST;
106710491SRishi.Srivatsavai@Sun.COM 			goto out;
106810491SRishi.Srivatsavai@Sun.COM 		}
106910491SRishi.Srivatsavai@Sun.COM 		has_oldbridge = B_TRUE;
107010491SRishi.Srivatsavai@Sun.COM 	} else if (status != DLADM_STATUS_NOTFOUND) {
107110491SRishi.Srivatsavai@Sun.COM 		goto out;
107210491SRishi.Srivatsavai@Sun.COM 	}
107310491SRishi.Srivatsavai@Sun.COM 
107410491SRishi.Srivatsavai@Sun.COM 	if (*bridge != '\0') {
107510491SRishi.Srivatsavai@Sun.COM 		status = dladm_set_conf_field(handle, conf, FBRIDGE,
107610491SRishi.Srivatsavai@Sun.COM 		    DLADM_TYPE_STR, bridge);
107710491SRishi.Srivatsavai@Sun.COM 		changed = B_TRUE;
107810491SRishi.Srivatsavai@Sun.COM 	} else if (has_oldbridge) {
107910491SRishi.Srivatsavai@Sun.COM 		status = dladm_unset_conf_field(handle, conf, FBRIDGE);
108010491SRishi.Srivatsavai@Sun.COM 		changed = B_TRUE;
108110491SRishi.Srivatsavai@Sun.COM 	} else {
108210491SRishi.Srivatsavai@Sun.COM 		status = DLADM_STATUS_OK;
108310491SRishi.Srivatsavai@Sun.COM 		goto out;
108410491SRishi.Srivatsavai@Sun.COM 	}
108510491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_OK)
108610491SRishi.Srivatsavai@Sun.COM 		status = dladm_write_conf(handle, conf);
108710491SRishi.Srivatsavai@Sun.COM 
108810491SRishi.Srivatsavai@Sun.COM out:
108910491SRishi.Srivatsavai@Sun.COM 	dladm_destroy_conf(handle, conf);
109010491SRishi.Srivatsavai@Sun.COM 	if (changed && status == DLADM_STATUS_OK) {
109110491SRishi.Srivatsavai@Sun.COM 		if (bridge[0] == '\0')
109210491SRishi.Srivatsavai@Sun.COM 			bridge = oldbridge;
109310491SRishi.Srivatsavai@Sun.COM 		status = bridge_refresh(bridge);
109410491SRishi.Srivatsavai@Sun.COM 	}
109510491SRishi.Srivatsavai@Sun.COM 	return (status);
109610491SRishi.Srivatsavai@Sun.COM }
109710491SRishi.Srivatsavai@Sun.COM 
109810491SRishi.Srivatsavai@Sun.COM /*
109910491SRishi.Srivatsavai@Sun.COM  * Get the name of the bridge of which the given linkid is a member.
110010491SRishi.Srivatsavai@Sun.COM  */
110110491SRishi.Srivatsavai@Sun.COM dladm_status_t
110210491SRishi.Srivatsavai@Sun.COM dladm_bridge_getlink(dladm_handle_t handle, datalink_id_t linkid, char *bridge,
110310491SRishi.Srivatsavai@Sun.COM     size_t bridgelen)
110410491SRishi.Srivatsavai@Sun.COM {
110510491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
110610491SRishi.Srivatsavai@Sun.COM 	dladm_conf_t conf;
110710491SRishi.Srivatsavai@Sun.COM 
110810491SRishi.Srivatsavai@Sun.COM 	if ((status = dladm_read_conf(handle, linkid, &conf)) !=
110910491SRishi.Srivatsavai@Sun.COM 	    DLADM_STATUS_OK)
111010491SRishi.Srivatsavai@Sun.COM 		return (status);
111110491SRishi.Srivatsavai@Sun.COM 
111210491SRishi.Srivatsavai@Sun.COM 	*bridge = '\0';
111310491SRishi.Srivatsavai@Sun.COM 	status = dladm_get_conf_field(handle, conf, FBRIDGE, bridge, bridgelen);
111410491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_OK && *bridge == '\0')
111510491SRishi.Srivatsavai@Sun.COM 		status = DLADM_STATUS_NOTFOUND;
111610491SRishi.Srivatsavai@Sun.COM 
111710491SRishi.Srivatsavai@Sun.COM 	dladm_destroy_conf(handle, conf);
111810491SRishi.Srivatsavai@Sun.COM 	return (status);
111910491SRishi.Srivatsavai@Sun.COM }
112010491SRishi.Srivatsavai@Sun.COM 
112110491SRishi.Srivatsavai@Sun.COM dladm_status_t
112210491SRishi.Srivatsavai@Sun.COM dladm_bridge_refresh(dladm_handle_t handle, datalink_id_t linkid)
112310491SRishi.Srivatsavai@Sun.COM {
112410491SRishi.Srivatsavai@Sun.COM 	char bridge[MAXLINKNAMELEN];
112510491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
112610491SRishi.Srivatsavai@Sun.COM 
112710491SRishi.Srivatsavai@Sun.COM 	status = dladm_bridge_getlink(handle, linkid, bridge, sizeof (bridge));
112810491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_NOTFOUND)
112910491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_OK);
113010491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_OK)
113110491SRishi.Srivatsavai@Sun.COM 		status = bridge_refresh(bridge);
113210491SRishi.Srivatsavai@Sun.COM 	return (status);
113310491SRishi.Srivatsavai@Sun.COM }
113410491SRishi.Srivatsavai@Sun.COM 
113510491SRishi.Srivatsavai@Sun.COM typedef struct bridge_held_arg_s {
113610491SRishi.Srivatsavai@Sun.COM 	const char	*bha_bridge;
113710491SRishi.Srivatsavai@Sun.COM 	boolean_t	bha_isheld;
113810491SRishi.Srivatsavai@Sun.COM } bridge_held_arg_t;
113910491SRishi.Srivatsavai@Sun.COM 
114010491SRishi.Srivatsavai@Sun.COM static int
114110491SRishi.Srivatsavai@Sun.COM i_dladm_bridge_is_held(dladm_handle_t handle, datalink_id_t linkid, void *arg)
114210491SRishi.Srivatsavai@Sun.COM {
114310491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status = DLADM_STATUS_FAILED;
114410491SRishi.Srivatsavai@Sun.COM 	dladm_conf_t conf;
114510491SRishi.Srivatsavai@Sun.COM 	char bridge[MAXLINKNAMELEN];
114610491SRishi.Srivatsavai@Sun.COM 	bridge_held_arg_t	*bha = arg;
114710491SRishi.Srivatsavai@Sun.COM 
114810491SRishi.Srivatsavai@Sun.COM 	if ((status = dladm_read_conf(handle, linkid, &conf)) !=
114910491SRishi.Srivatsavai@Sun.COM 	    DLADM_STATUS_OK)
115010491SRishi.Srivatsavai@Sun.COM 		return (DLADM_WALK_CONTINUE);
115110491SRishi.Srivatsavai@Sun.COM 	status = dladm_get_conf_field(handle, conf, FBRIDGE, bridge,
115210491SRishi.Srivatsavai@Sun.COM 	    sizeof (bridge));
115310491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_OK && strcmp(bha->bha_bridge, bridge) == 0) {
115410491SRishi.Srivatsavai@Sun.COM 		bha->bha_isheld = B_TRUE;
115510491SRishi.Srivatsavai@Sun.COM 		dladm_destroy_conf(handle, conf);
115610491SRishi.Srivatsavai@Sun.COM 		return (DLADM_WALK_TERMINATE);
115710491SRishi.Srivatsavai@Sun.COM 	} else {
115810491SRishi.Srivatsavai@Sun.COM 		dladm_destroy_conf(handle, conf);
115910491SRishi.Srivatsavai@Sun.COM 		return (DLADM_WALK_CONTINUE);
116010491SRishi.Srivatsavai@Sun.COM 	}
116110491SRishi.Srivatsavai@Sun.COM }
116210491SRishi.Srivatsavai@Sun.COM 
116310491SRishi.Srivatsavai@Sun.COM /*
116410491SRishi.Srivatsavai@Sun.COM  * Delete a previously created bridge.
116510491SRishi.Srivatsavai@Sun.COM  */
116610491SRishi.Srivatsavai@Sun.COM dladm_status_t
116710491SRishi.Srivatsavai@Sun.COM dladm_bridge_delete(dladm_handle_t handle, const char *bridge, uint32_t flags)
116810491SRishi.Srivatsavai@Sun.COM {
116910491SRishi.Srivatsavai@Sun.COM 	datalink_id_t linkid;
117010491SRishi.Srivatsavai@Sun.COM 	datalink_class_t class;
117110491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
117210491SRishi.Srivatsavai@Sun.COM 	char linkname[MAXLINKNAMELEN];
117310491SRishi.Srivatsavai@Sun.COM 
117410491SRishi.Srivatsavai@Sun.COM 	if (!dladm_valid_bridgename(bridge))
117510491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_LINKINVAL);
117610491SRishi.Srivatsavai@Sun.COM 
117710491SRishi.Srivatsavai@Sun.COM 	/* Get the datalink ID for this bridge */
117810491SRishi.Srivatsavai@Sun.COM 	(void) snprintf(linkname, sizeof (linkname), "%s0", bridge);
117910491SRishi.Srivatsavai@Sun.COM 	if (dladm_name2info(handle, linkname, &linkid, NULL, NULL, NULL) !=
118010491SRishi.Srivatsavai@Sun.COM 	    DLADM_STATUS_OK)
118110491SRishi.Srivatsavai@Sun.COM 		linkid = DATALINK_INVALID_LINKID;
118210491SRishi.Srivatsavai@Sun.COM 	else if (dladm_datalink_id2info(handle, linkid, NULL, &class, NULL,
118310491SRishi.Srivatsavai@Sun.COM 	    NULL, 0) != DLADM_STATUS_OK)
118410491SRishi.Srivatsavai@Sun.COM 		linkid = DATALINK_INVALID_LINKID;
118510491SRishi.Srivatsavai@Sun.COM 	else if (class != DATALINK_CLASS_BRIDGE)
118610491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_BADARG);
118710491SRishi.Srivatsavai@Sun.COM 
118810491SRishi.Srivatsavai@Sun.COM 	if ((flags & DLADM_OPT_ACTIVE) && linkid == DATALINK_INVALID_LINKID)
118910491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_BADARG);
119010491SRishi.Srivatsavai@Sun.COM 
119110491SRishi.Srivatsavai@Sun.COM 	if (flags & DLADM_OPT_PERSIST) {
119210491SRishi.Srivatsavai@Sun.COM 		bridge_held_arg_t arg;
119310491SRishi.Srivatsavai@Sun.COM 
119410491SRishi.Srivatsavai@Sun.COM 		arg.bha_bridge = bridge;
119510491SRishi.Srivatsavai@Sun.COM 		arg.bha_isheld = B_FALSE;
119610491SRishi.Srivatsavai@Sun.COM 
119710491SRishi.Srivatsavai@Sun.COM 		/*
119810491SRishi.Srivatsavai@Sun.COM 		 * See whether there are any persistent links using this
119910491SRishi.Srivatsavai@Sun.COM 		 * bridge.  If so, we fail the operation.
120010491SRishi.Srivatsavai@Sun.COM 		 */
120110491SRishi.Srivatsavai@Sun.COM 		(void) dladm_walk_datalink_id(i_dladm_bridge_is_held, handle,
120210491SRishi.Srivatsavai@Sun.COM 		    &arg, DATALINK_CLASS_PHYS | DATALINK_CLASS_AGGR |
120310491SRishi.Srivatsavai@Sun.COM 		    DATALINK_CLASS_ETHERSTUB | DATALINK_CLASS_SIMNET,
120410491SRishi.Srivatsavai@Sun.COM 		    DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
120510491SRishi.Srivatsavai@Sun.COM 		if (arg.bha_isheld)
120610491SRishi.Srivatsavai@Sun.COM 			return (DLADM_STATUS_LINKBUSY);
120710491SRishi.Srivatsavai@Sun.COM 	}
120810491SRishi.Srivatsavai@Sun.COM 
120910491SRishi.Srivatsavai@Sun.COM 	if ((status = disable_trill(bridge, flags)) != DLADM_STATUS_OK)
121010491SRishi.Srivatsavai@Sun.COM 		goto out;
121110491SRishi.Srivatsavai@Sun.COM 
121210491SRishi.Srivatsavai@Sun.COM 	/* Disable or remove the SMF instance */
121310491SRishi.Srivatsavai@Sun.COM 	status = shut_down_instance(BRIDGE_SVC_NAME, bridge, flags);
121410491SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK)
121510491SRishi.Srivatsavai@Sun.COM 		goto out;
121610491SRishi.Srivatsavai@Sun.COM 
121710491SRishi.Srivatsavai@Sun.COM 	if (flags & DLADM_OPT_ACTIVE) {
121810491SRishi.Srivatsavai@Sun.COM 		/*
121910491SRishi.Srivatsavai@Sun.COM 		 * Delete ACTIVE linkprop now that daemon is gone.
122010491SRishi.Srivatsavai@Sun.COM 		 */
122110491SRishi.Srivatsavai@Sun.COM 		(void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0,
122210491SRishi.Srivatsavai@Sun.COM 		    DLADM_OPT_ACTIVE);
122310491SRishi.Srivatsavai@Sun.COM 		(void) dladm_destroy_datalink_id(handle, linkid,
122410491SRishi.Srivatsavai@Sun.COM 		    DLADM_OPT_ACTIVE);
122510491SRishi.Srivatsavai@Sun.COM 	}
122610491SRishi.Srivatsavai@Sun.COM 
122710491SRishi.Srivatsavai@Sun.COM 	if (flags & DLADM_OPT_PERSIST) {
122810491SRishi.Srivatsavai@Sun.COM 		(void) dladm_remove_conf(handle, linkid);
122910491SRishi.Srivatsavai@Sun.COM 		(void) dladm_destroy_datalink_id(handle, linkid,
123010491SRishi.Srivatsavai@Sun.COM 		    DLADM_OPT_PERSIST);
123110491SRishi.Srivatsavai@Sun.COM 	}
123210491SRishi.Srivatsavai@Sun.COM 
123310491SRishi.Srivatsavai@Sun.COM out:
123410491SRishi.Srivatsavai@Sun.COM 
123510491SRishi.Srivatsavai@Sun.COM 	return (status);
123610491SRishi.Srivatsavai@Sun.COM }
123710491SRishi.Srivatsavai@Sun.COM 
123810491SRishi.Srivatsavai@Sun.COM /* Check if given name is valid for bridges */
123910491SRishi.Srivatsavai@Sun.COM boolean_t
124010491SRishi.Srivatsavai@Sun.COM dladm_valid_bridgename(const char *bridge)
124110491SRishi.Srivatsavai@Sun.COM {
124210491SRishi.Srivatsavai@Sun.COM 	size_t		len = strnlen(bridge, MAXLINKNAMELEN);
124310491SRishi.Srivatsavai@Sun.COM 	const char	*cp;
124410491SRishi.Srivatsavai@Sun.COM 
124510491SRishi.Srivatsavai@Sun.COM 	if (len == MAXLINKNAMELEN)
124610491SRishi.Srivatsavai@Sun.COM 		return (B_FALSE);
124710491SRishi.Srivatsavai@Sun.COM 
124810491SRishi.Srivatsavai@Sun.COM 	/*
124910491SRishi.Srivatsavai@Sun.COM 	 * The bridge name cannot start or end with a digit.
125010491SRishi.Srivatsavai@Sun.COM 	 */
125110491SRishi.Srivatsavai@Sun.COM 	if (isdigit(bridge[0]) || isdigit(bridge[len - 1]))
125210491SRishi.Srivatsavai@Sun.COM 		return (B_FALSE);
125310491SRishi.Srivatsavai@Sun.COM 
125410491SRishi.Srivatsavai@Sun.COM 	/*
125510491SRishi.Srivatsavai@Sun.COM 	 * The legal characters within a bridge name are:
125610491SRishi.Srivatsavai@Sun.COM 	 * alphanumeric (a-z,  A-Z,  0-9), and the underscore ('_').
125710491SRishi.Srivatsavai@Sun.COM 	 */
125810491SRishi.Srivatsavai@Sun.COM 	for (cp = bridge; *cp != '\0'; cp++) {
125910491SRishi.Srivatsavai@Sun.COM 		if (!isalnum(*cp) && *cp != '_')
126010491SRishi.Srivatsavai@Sun.COM 			return (B_FALSE);
126110491SRishi.Srivatsavai@Sun.COM 	}
126210491SRishi.Srivatsavai@Sun.COM 
126310491SRishi.Srivatsavai@Sun.COM 	return (B_TRUE);
126410491SRishi.Srivatsavai@Sun.COM }
126510491SRishi.Srivatsavai@Sun.COM 
126610491SRishi.Srivatsavai@Sun.COM /*
126710491SRishi.Srivatsavai@Sun.COM  * Convert a bridge-related observability node name back into the name of the
126810491SRishi.Srivatsavai@Sun.COM  * bridge.  Returns B_FALSE without making changes if the input name is not in
126910491SRishi.Srivatsavai@Sun.COM  * a legal format.
127010491SRishi.Srivatsavai@Sun.COM  */
127110491SRishi.Srivatsavai@Sun.COM boolean_t
127210491SRishi.Srivatsavai@Sun.COM dladm_observe_to_bridge(char *link)
127310491SRishi.Srivatsavai@Sun.COM {
127410491SRishi.Srivatsavai@Sun.COM 	int llen;
127510491SRishi.Srivatsavai@Sun.COM 
127610491SRishi.Srivatsavai@Sun.COM 	llen = strnlen(link, MAXLINKNAMELEN);
127710491SRishi.Srivatsavai@Sun.COM 	if (llen < 2 || link[llen - 1] != '0' || isdigit(link[llen - 2]))
127810491SRishi.Srivatsavai@Sun.COM 		return (B_FALSE);
127910491SRishi.Srivatsavai@Sun.COM 	link[llen - 1] = '\0';
128010491SRishi.Srivatsavai@Sun.COM 	return (B_TRUE);
128110491SRishi.Srivatsavai@Sun.COM }
128210491SRishi.Srivatsavai@Sun.COM 
128310491SRishi.Srivatsavai@Sun.COM /*
128410491SRishi.Srivatsavai@Sun.COM  * Get bridge property values from the running daemon and return them in a
128510491SRishi.Srivatsavai@Sun.COM  * common structure.
128610491SRishi.Srivatsavai@Sun.COM  */
128710491SRishi.Srivatsavai@Sun.COM dladm_status_t
128810491SRishi.Srivatsavai@Sun.COM dladm_bridge_run_properties(const char *instname, UID_STP_CFG_T *smcfg,
128910491SRishi.Srivatsavai@Sun.COM     dladm_bridge_prot_t *brprotp)
129010491SRishi.Srivatsavai@Sun.COM {
129110491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
129210491SRishi.Srivatsavai@Sun.COM 	bridge_door_cfg_t bdcf;
129310491SRishi.Srivatsavai@Sun.COM 	bridge_door_cfg_t *bdcfp = &bdcf;
129410491SRishi.Srivatsavai@Sun.COM 	size_t buflen = sizeof (bdcf);
129510491SRishi.Srivatsavai@Sun.COM 
129610491SRishi.Srivatsavai@Sun.COM 	status = bridge_door_call(instname, bdcBridgeGetConfig,
129710491SRishi.Srivatsavai@Sun.COM 	    DATALINK_INVALID_LINKID, (void **)&bdcfp, 0, &buflen, B_FALSE);
129810491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_OK) {
129910491SRishi.Srivatsavai@Sun.COM 		*smcfg = bdcfp->bdcf_cfg;
130010491SRishi.Srivatsavai@Sun.COM 		*brprotp = bdcfp->bdcf_prot;
130110491SRishi.Srivatsavai@Sun.COM 	} else {
130210491SRishi.Srivatsavai@Sun.COM 		smcfg->field_mask = 0;
130310491SRishi.Srivatsavai@Sun.COM 		*brprotp = DLADM_BRIDGE_PROT_STP;
130410491SRishi.Srivatsavai@Sun.COM 	}
130510491SRishi.Srivatsavai@Sun.COM 	return (status);
130610491SRishi.Srivatsavai@Sun.COM }
130710491SRishi.Srivatsavai@Sun.COM 
130810491SRishi.Srivatsavai@Sun.COM /*
130910491SRishi.Srivatsavai@Sun.COM  * Get bridge state from the running daemon and return in structure borrowed
131010491SRishi.Srivatsavai@Sun.COM  * from librstp.
131110491SRishi.Srivatsavai@Sun.COM  */
131210491SRishi.Srivatsavai@Sun.COM dladm_status_t
131310491SRishi.Srivatsavai@Sun.COM dladm_bridge_state(const char *instname, UID_STP_STATE_T *statep)
131410491SRishi.Srivatsavai@Sun.COM {
131510491SRishi.Srivatsavai@Sun.COM 	size_t buflen = sizeof (*statep);
131610491SRishi.Srivatsavai@Sun.COM 
131710491SRishi.Srivatsavai@Sun.COM 	return (bridge_door_call(instname, bdcBridgeGetState,
131810491SRishi.Srivatsavai@Sun.COM 	    DATALINK_INVALID_LINKID, (void **)&statep, 0, &buflen, B_FALSE));
131910491SRishi.Srivatsavai@Sun.COM }
132010491SRishi.Srivatsavai@Sun.COM 
132110491SRishi.Srivatsavai@Sun.COM /* Returns list of ports (datalink_id_t values) assigned to a bridge instance */
132210491SRishi.Srivatsavai@Sun.COM datalink_id_t *
132310491SRishi.Srivatsavai@Sun.COM dladm_bridge_get_portlist(const char *instname, uint_t *nports)
132410491SRishi.Srivatsavai@Sun.COM {
132510491SRishi.Srivatsavai@Sun.COM 	size_t buflen = sizeof (int) + MAXPORTS * sizeof (datalink_id_t);
132610491SRishi.Srivatsavai@Sun.COM 	int *rbuf;
132710491SRishi.Srivatsavai@Sun.COM 
132810491SRishi.Srivatsavai@Sun.COM 	if ((rbuf = malloc(buflen)) == NULL)
132910491SRishi.Srivatsavai@Sun.COM 		return (NULL);
133010491SRishi.Srivatsavai@Sun.COM 	if (bridge_door_call(instname, bdcBridgeGetPorts,
133110491SRishi.Srivatsavai@Sun.COM 	    DATALINK_INVALID_LINKID, (void **)&rbuf, 0, &buflen, B_TRUE) !=
133210491SRishi.Srivatsavai@Sun.COM 	    DLADM_STATUS_OK) {
133310491SRishi.Srivatsavai@Sun.COM 		free(rbuf);
133410491SRishi.Srivatsavai@Sun.COM 		return (NULL);
133510491SRishi.Srivatsavai@Sun.COM 	} else {
133610491SRishi.Srivatsavai@Sun.COM 		/*
133710491SRishi.Srivatsavai@Sun.COM 		 * Returns an array of datalink_id_t values for all the ports
133810491SRishi.Srivatsavai@Sun.COM 		 * part of the bridge instance. First entry in the array is the
133910491SRishi.Srivatsavai@Sun.COM 		 * number of ports.
134010491SRishi.Srivatsavai@Sun.COM 		 */
134110491SRishi.Srivatsavai@Sun.COM 		*nports = *rbuf;
134210491SRishi.Srivatsavai@Sun.COM 		return ((datalink_id_t *)(rbuf + 1));
134310491SRishi.Srivatsavai@Sun.COM 	}
134410491SRishi.Srivatsavai@Sun.COM }
134510491SRishi.Srivatsavai@Sun.COM 
134610491SRishi.Srivatsavai@Sun.COM void
134710491SRishi.Srivatsavai@Sun.COM dladm_bridge_free_portlist(datalink_id_t *dlp)
134810491SRishi.Srivatsavai@Sun.COM {
134910491SRishi.Srivatsavai@Sun.COM 	free((int *)dlp - 1);
135010491SRishi.Srivatsavai@Sun.COM }
135110491SRishi.Srivatsavai@Sun.COM 
135210491SRishi.Srivatsavai@Sun.COM /* Retrieve Bridge port configuration values */
135310491SRishi.Srivatsavai@Sun.COM dladm_status_t
135410491SRishi.Srivatsavai@Sun.COM dladm_bridge_get_port_cfg(dladm_handle_t handle, datalink_id_t linkid,
135510491SRishi.Srivatsavai@Sun.COM     int field, int *valuep)
135610491SRishi.Srivatsavai@Sun.COM {
135710491SRishi.Srivatsavai@Sun.COM 	UID_STP_PORT_CFG_T portcfg;
135810491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
135910491SRishi.Srivatsavai@Sun.COM 
136010491SRishi.Srivatsavai@Sun.COM 	status = port_door_call(handle, linkid, bdcPortGetConfig, &portcfg,
136110491SRishi.Srivatsavai@Sun.COM 	    0, sizeof (portcfg));
136210491SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK)
136310491SRishi.Srivatsavai@Sun.COM 		return (status);
136410491SRishi.Srivatsavai@Sun.COM 
136510491SRishi.Srivatsavai@Sun.COM 	switch (field) {
136610491SRishi.Srivatsavai@Sun.COM 	case PT_CFG_COST:
136710491SRishi.Srivatsavai@Sun.COM 		*valuep = portcfg.admin_port_path_cost;
136810491SRishi.Srivatsavai@Sun.COM 		break;
136910491SRishi.Srivatsavai@Sun.COM 	case PT_CFG_PRIO:
137010491SRishi.Srivatsavai@Sun.COM 		*valuep = portcfg.port_priority;
137110491SRishi.Srivatsavai@Sun.COM 		break;
137210491SRishi.Srivatsavai@Sun.COM 	case PT_CFG_P2P:
137310491SRishi.Srivatsavai@Sun.COM 		*valuep = portcfg.admin_point2point;
137410491SRishi.Srivatsavai@Sun.COM 		break;
137510491SRishi.Srivatsavai@Sun.COM 	case PT_CFG_EDGE:
137610491SRishi.Srivatsavai@Sun.COM 		*valuep = portcfg.admin_edge;
137710491SRishi.Srivatsavai@Sun.COM 		break;
137810491SRishi.Srivatsavai@Sun.COM 	case PT_CFG_NON_STP:
137910491SRishi.Srivatsavai@Sun.COM 		*valuep = !portcfg.admin_non_stp;
138010491SRishi.Srivatsavai@Sun.COM 		break;
138110491SRishi.Srivatsavai@Sun.COM 	case PT_CFG_MCHECK:
138210491SRishi.Srivatsavai@Sun.COM 		*valuep = (portcfg.field_mask & PT_CFG_MCHECK) ? 1 : 0;
138310491SRishi.Srivatsavai@Sun.COM 		break;
138410491SRishi.Srivatsavai@Sun.COM 	}
138510491SRishi.Srivatsavai@Sun.COM 	return (status);
138610491SRishi.Srivatsavai@Sun.COM }
138710491SRishi.Srivatsavai@Sun.COM 
138810491SRishi.Srivatsavai@Sun.COM /* Retreive Bridge port status (disabled, bad SDU etc.) */
138910491SRishi.Srivatsavai@Sun.COM dladm_status_t
139010491SRishi.Srivatsavai@Sun.COM dladm_bridge_link_state(dladm_handle_t handle, datalink_id_t linkid,
139110491SRishi.Srivatsavai@Sun.COM     UID_STP_PORT_STATE_T *spsp)
139210491SRishi.Srivatsavai@Sun.COM {
139310491SRishi.Srivatsavai@Sun.COM 	return (port_door_call(handle, linkid, bdcPortGetState, spsp, 0,
139410491SRishi.Srivatsavai@Sun.COM 	    sizeof (*spsp)));
139510491SRishi.Srivatsavai@Sun.COM }
139610491SRishi.Srivatsavai@Sun.COM 
139710491SRishi.Srivatsavai@Sun.COM /* Retrieve Bridge forwarding status of the given link */
139810491SRishi.Srivatsavai@Sun.COM dladm_status_t
139910491SRishi.Srivatsavai@Sun.COM dladm_bridge_get_forwarding(dladm_handle_t handle, datalink_id_t linkid,
140010491SRishi.Srivatsavai@Sun.COM     uint_t *valuep)
140110491SRishi.Srivatsavai@Sun.COM {
140210491SRishi.Srivatsavai@Sun.COM 	int twoints[2];
140310491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
140410491SRishi.Srivatsavai@Sun.COM 
140510491SRishi.Srivatsavai@Sun.COM 	status = port_door_call(handle, linkid, bdcPortGetForwarding, twoints,
140610491SRishi.Srivatsavai@Sun.COM 	    0, sizeof (twoints));
140710491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_OK)
140810491SRishi.Srivatsavai@Sun.COM 		*valuep = twoints[0];
140910491SRishi.Srivatsavai@Sun.COM 	return (status);
141010491SRishi.Srivatsavai@Sun.COM }
141110491SRishi.Srivatsavai@Sun.COM 
141210491SRishi.Srivatsavai@Sun.COM /* Retrieve Bridge forwarding table entries */
141310491SRishi.Srivatsavai@Sun.COM bridge_listfwd_t *
141410491SRishi.Srivatsavai@Sun.COM dladm_bridge_get_fwdtable(dladm_handle_t handle, const char *bridge,
141510491SRishi.Srivatsavai@Sun.COM     uint_t *nfwd)
141610491SRishi.Srivatsavai@Sun.COM {
141710491SRishi.Srivatsavai@Sun.COM 	bridge_listfwd_t *blf = NULL, *newblf, blfread;
141810491SRishi.Srivatsavai@Sun.COM 	uint_t nblf = 0, maxblf = 0;
141910491SRishi.Srivatsavai@Sun.COM 	static uint8_t zero_addr[ETHERADDRL];
142010491SRishi.Srivatsavai@Sun.COM 	int rc;
142110491SRishi.Srivatsavai@Sun.COM 
142210491SRishi.Srivatsavai@Sun.COM 	(void) memset(&blfread, 0, sizeof (blfread));
142310491SRishi.Srivatsavai@Sun.COM 	(void) snprintf(blfread.blf_name, sizeof (blfread.blf_name),
142410491SRishi.Srivatsavai@Sun.COM 	    "%s0", bridge);
142510491SRishi.Srivatsavai@Sun.COM 	for (;;) {
142610491SRishi.Srivatsavai@Sun.COM 		if (nblf >= maxblf) {
142710491SRishi.Srivatsavai@Sun.COM 			maxblf = maxblf == 0 ? 64 : (maxblf << 1);
142810491SRishi.Srivatsavai@Sun.COM 			newblf = realloc(blf, maxblf * sizeof (*blf));
142910491SRishi.Srivatsavai@Sun.COM 			if (newblf == NULL) {
143010491SRishi.Srivatsavai@Sun.COM 				free(blf);
143110491SRishi.Srivatsavai@Sun.COM 				blf = NULL;
143210491SRishi.Srivatsavai@Sun.COM 				break;
143310491SRishi.Srivatsavai@Sun.COM 			}
143410491SRishi.Srivatsavai@Sun.COM 			blf = newblf;
143510491SRishi.Srivatsavai@Sun.COM 		}
143610491SRishi.Srivatsavai@Sun.COM 		rc = ioctl(dladm_dld_fd(handle), BRIDGE_IOC_LISTFWD, &blfread);
143710491SRishi.Srivatsavai@Sun.COM 		if (rc != 0) {
143810491SRishi.Srivatsavai@Sun.COM 			free(blf);
143910491SRishi.Srivatsavai@Sun.COM 			blf = NULL;
144010491SRishi.Srivatsavai@Sun.COM 			break;
144110491SRishi.Srivatsavai@Sun.COM 		}
144210491SRishi.Srivatsavai@Sun.COM 		if (memcmp(blfread.blf_dest, zero_addr, ETHERADDRL) == 0)
144310491SRishi.Srivatsavai@Sun.COM 			break;
144410491SRishi.Srivatsavai@Sun.COM 		blf[nblf++] = blfread;
144510491SRishi.Srivatsavai@Sun.COM 	}
144610491SRishi.Srivatsavai@Sun.COM 	if (blf != NULL)
144710491SRishi.Srivatsavai@Sun.COM 		*nfwd = nblf;
144810491SRishi.Srivatsavai@Sun.COM 	return (blf);
144910491SRishi.Srivatsavai@Sun.COM }
145010491SRishi.Srivatsavai@Sun.COM 
145110491SRishi.Srivatsavai@Sun.COM void
145210491SRishi.Srivatsavai@Sun.COM dladm_bridge_free_fwdtable(bridge_listfwd_t *blf)
145310491SRishi.Srivatsavai@Sun.COM {
145410491SRishi.Srivatsavai@Sun.COM 	free(blf);
145510491SRishi.Srivatsavai@Sun.COM }
145610491SRishi.Srivatsavai@Sun.COM 
145710491SRishi.Srivatsavai@Sun.COM /* Retrieve list of TRILL nicknames from the TRILL module */
145810491SRishi.Srivatsavai@Sun.COM trill_listnick_t *
145910491SRishi.Srivatsavai@Sun.COM dladm_bridge_get_trillnick(const char *bridge, uint_t *nnick)
146010491SRishi.Srivatsavai@Sun.COM {
146110491SRishi.Srivatsavai@Sun.COM 	int fd;
146210491SRishi.Srivatsavai@Sun.COM 	char brcopy[MAXLINKNAMELEN];
146310491SRishi.Srivatsavai@Sun.COM 	trill_listnick_t *tln = NULL, *newtln, tlnread;
146410491SRishi.Srivatsavai@Sun.COM 	uint_t ntln = 0, maxtln = 0;
146510491SRishi.Srivatsavai@Sun.COM 
146610491SRishi.Srivatsavai@Sun.COM 	if ((fd = socket(PF_TRILL, SOCK_DGRAM, 0)) == -1)
146710491SRishi.Srivatsavai@Sun.COM 		return (NULL);
146810491SRishi.Srivatsavai@Sun.COM 	(void) strlcpy(brcopy, bridge, sizeof (brcopy));
146910491SRishi.Srivatsavai@Sun.COM 	if (ioctl(fd, TRILL_GETBRIDGE, &brcopy) < 0) {
147010491SRishi.Srivatsavai@Sun.COM 		(void) close(fd);
147110491SRishi.Srivatsavai@Sun.COM 		return (NULL);
147210491SRishi.Srivatsavai@Sun.COM 	}
147310491SRishi.Srivatsavai@Sun.COM 	(void) memset(&tlnread, 0, sizeof (tlnread));
147410491SRishi.Srivatsavai@Sun.COM 	for (;;) {
147510491SRishi.Srivatsavai@Sun.COM 		if (ntln >= maxtln) {
147610491SRishi.Srivatsavai@Sun.COM 			maxtln = maxtln == 0 ? 64 : (maxtln << 1);
147710491SRishi.Srivatsavai@Sun.COM 			newtln = realloc(tln, maxtln * sizeof (*tln));
147810491SRishi.Srivatsavai@Sun.COM 			if (newtln == NULL) {
147910491SRishi.Srivatsavai@Sun.COM 				free(tln);
148010491SRishi.Srivatsavai@Sun.COM 				tln = NULL;
148110491SRishi.Srivatsavai@Sun.COM 				break;
148210491SRishi.Srivatsavai@Sun.COM 			}
148310491SRishi.Srivatsavai@Sun.COM 			tln = newtln;
148410491SRishi.Srivatsavai@Sun.COM 		}
148510491SRishi.Srivatsavai@Sun.COM 		if (ioctl(fd, TRILL_LISTNICK, &tlnread) == -1) {
148610491SRishi.Srivatsavai@Sun.COM 			free(tln);
148710491SRishi.Srivatsavai@Sun.COM 			tln = NULL;
148810491SRishi.Srivatsavai@Sun.COM 			break;
148910491SRishi.Srivatsavai@Sun.COM 		}
149010491SRishi.Srivatsavai@Sun.COM 		if (tlnread.tln_nick == 0)
149110491SRishi.Srivatsavai@Sun.COM 			break;
149210491SRishi.Srivatsavai@Sun.COM 		tln[ntln++] = tlnread;
149310491SRishi.Srivatsavai@Sun.COM 	}
149410491SRishi.Srivatsavai@Sun.COM 	(void) close(fd);
149510491SRishi.Srivatsavai@Sun.COM 	if (tln != NULL)
149610491SRishi.Srivatsavai@Sun.COM 		*nnick = ntln;
149710491SRishi.Srivatsavai@Sun.COM 	return (tln);
149810491SRishi.Srivatsavai@Sun.COM }
149910491SRishi.Srivatsavai@Sun.COM 
150010491SRishi.Srivatsavai@Sun.COM void
150110491SRishi.Srivatsavai@Sun.COM dladm_bridge_free_trillnick(trill_listnick_t *tln)
150210491SRishi.Srivatsavai@Sun.COM {
150310491SRishi.Srivatsavai@Sun.COM 	free(tln);
150410491SRishi.Srivatsavai@Sun.COM }
150510491SRishi.Srivatsavai@Sun.COM 
150610491SRishi.Srivatsavai@Sun.COM /* Retrieve any stored TRILL nickname from TRILL SMF service */
150710491SRishi.Srivatsavai@Sun.COM uint16_t
150810491SRishi.Srivatsavai@Sun.COM dladm_bridge_get_nick(const char *bridge)
150910491SRishi.Srivatsavai@Sun.COM {
151010491SRishi.Srivatsavai@Sun.COM 	scf_state_t sstate;
151110491SRishi.Srivatsavai@Sun.COM 	uint64_t value;
151210491SRishi.Srivatsavai@Sun.COM 	uint16_t nickname = RBRIDGE_NICKNAME_NONE;
151310491SRishi.Srivatsavai@Sun.COM 
151410491SRishi.Srivatsavai@Sun.COM 	if (bind_instance(TRILL_SVC_NAME, bridge, &sstate) != 0)
151510491SRishi.Srivatsavai@Sun.COM 		return (nickname);
151610491SRishi.Srivatsavai@Sun.COM 
151710491SRishi.Srivatsavai@Sun.COM 	if (get_composed_properties("config", B_TRUE, &sstate) == 0 &&
151810491SRishi.Srivatsavai@Sun.COM 	    get_count("nickname", &sstate, &value) == 0)
151910491SRishi.Srivatsavai@Sun.COM 		nickname = value;
152010491SRishi.Srivatsavai@Sun.COM 	shut_down_scf(&sstate);
152110491SRishi.Srivatsavai@Sun.COM 	return (nickname);
152210491SRishi.Srivatsavai@Sun.COM }
152310491SRishi.Srivatsavai@Sun.COM 
152410491SRishi.Srivatsavai@Sun.COM /* Stores TRILL nickname in SMF configuraiton for the TRILL service */
152510491SRishi.Srivatsavai@Sun.COM void
152610491SRishi.Srivatsavai@Sun.COM dladm_bridge_set_nick(const char *bridge, uint16_t nick)
152710491SRishi.Srivatsavai@Sun.COM {
152810491SRishi.Srivatsavai@Sun.COM 	scf_state_t sstate;
152910491SRishi.Srivatsavai@Sun.COM 	scf_transaction_t *tran = NULL;
153010491SRishi.Srivatsavai@Sun.COM 	boolean_t new_pg = B_FALSE;
153110491SRishi.Srivatsavai@Sun.COM 	int rv = 0;
153210491SRishi.Srivatsavai@Sun.COM 	char *fmri;
153310491SRishi.Srivatsavai@Sun.COM 
153410491SRishi.Srivatsavai@Sun.COM 	if (exact_instance(TRILL_SVC_NAME, &sstate) != DLADM_STATUS_OK)
153510491SRishi.Srivatsavai@Sun.COM 		return;
153610491SRishi.Srivatsavai@Sun.COM 
153710491SRishi.Srivatsavai@Sun.COM 	if (scf_service_get_instance(sstate.ss_svc, bridge, sstate.ss_inst) !=
153810491SRishi.Srivatsavai@Sun.COM 	    0)
153910491SRishi.Srivatsavai@Sun.COM 		goto out;
154010491SRishi.Srivatsavai@Sun.COM 	if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL)
154110491SRishi.Srivatsavai@Sun.COM 		goto out;
154210491SRishi.Srivatsavai@Sun.COM 	if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL)
154310491SRishi.Srivatsavai@Sun.COM 		goto out;
154410491SRishi.Srivatsavai@Sun.COM 	if (scf_instance_add_pg(sstate.ss_inst, "config",
154510491SRishi.Srivatsavai@Sun.COM 	    SCF_GROUP_APPLICATION, 0, sstate.ss_pg) == 0) {
154610491SRishi.Srivatsavai@Sun.COM 		new_pg = B_TRUE;
154710491SRishi.Srivatsavai@Sun.COM 	} else if (scf_instance_get_pg(sstate.ss_inst, "config",
154810491SRishi.Srivatsavai@Sun.COM 	    sstate.ss_pg) != 0) {
154910491SRishi.Srivatsavai@Sun.COM 		goto out;
155010491SRishi.Srivatsavai@Sun.COM 	}
155110491SRishi.Srivatsavai@Sun.COM 	do {
155210491SRishi.Srivatsavai@Sun.COM 		if (scf_transaction_start(tran, sstate.ss_pg) != 0)
155310491SRishi.Srivatsavai@Sun.COM 			goto out;
155410491SRishi.Srivatsavai@Sun.COM 		if (!set_count_property(sstate.ss_handle, tran, "nickname",
155510491SRishi.Srivatsavai@Sun.COM 		    nick))
155610491SRishi.Srivatsavai@Sun.COM 			goto out;
155710491SRishi.Srivatsavai@Sun.COM 		rv = scf_transaction_commit(tran);
155810491SRishi.Srivatsavai@Sun.COM 		scf_transaction_reset(tran);
155910491SRishi.Srivatsavai@Sun.COM 		if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1)
156010491SRishi.Srivatsavai@Sun.COM 			goto out;
156110491SRishi.Srivatsavai@Sun.COM 	} while (rv == 0);
156210491SRishi.Srivatsavai@Sun.COM 
156310491SRishi.Srivatsavai@Sun.COM out:
156410491SRishi.Srivatsavai@Sun.COM 	if (tran != NULL) {
156510491SRishi.Srivatsavai@Sun.COM 		scf_transaction_destroy_children(tran);
156610491SRishi.Srivatsavai@Sun.COM 		scf_transaction_destroy(tran);
156710491SRishi.Srivatsavai@Sun.COM 	}
156810491SRishi.Srivatsavai@Sun.COM 
156910491SRishi.Srivatsavai@Sun.COM 	if (rv != 1 && new_pg)
157010491SRishi.Srivatsavai@Sun.COM 		(void) scf_pg_delete(sstate.ss_pg);
157110491SRishi.Srivatsavai@Sun.COM 
157210491SRishi.Srivatsavai@Sun.COM 	drop_composed(&sstate);
157310491SRishi.Srivatsavai@Sun.COM 	shut_down_scf(&sstate);
157410491SRishi.Srivatsavai@Sun.COM 	if (rv == 1 && (fmri = alloc_fmri(TRILL_SVC_NAME, bridge)) != NULL) {
157510491SRishi.Srivatsavai@Sun.COM 		(void) smf_refresh_instance(fmri);
157610491SRishi.Srivatsavai@Sun.COM 		free(fmri);
157710491SRishi.Srivatsavai@Sun.COM 	}
157810491SRishi.Srivatsavai@Sun.COM }
1579