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