1*10491SRishi.Srivatsavai@Sun.COM /*
2*10491SRishi.Srivatsavai@Sun.COM  * CDDL HEADER START
3*10491SRishi.Srivatsavai@Sun.COM  *
4*10491SRishi.Srivatsavai@Sun.COM  * The contents of this file are subject to the terms of the
5*10491SRishi.Srivatsavai@Sun.COM  * Common Development and Distribution License (the "License").
6*10491SRishi.Srivatsavai@Sun.COM  * You may not use this file except in compliance with the License.
7*10491SRishi.Srivatsavai@Sun.COM  *
8*10491SRishi.Srivatsavai@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*10491SRishi.Srivatsavai@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*10491SRishi.Srivatsavai@Sun.COM  * See the License for the specific language governing permissions
11*10491SRishi.Srivatsavai@Sun.COM  * and limitations under the License.
12*10491SRishi.Srivatsavai@Sun.COM  *
13*10491SRishi.Srivatsavai@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*10491SRishi.Srivatsavai@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*10491SRishi.Srivatsavai@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*10491SRishi.Srivatsavai@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*10491SRishi.Srivatsavai@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*10491SRishi.Srivatsavai@Sun.COM  *
19*10491SRishi.Srivatsavai@Sun.COM  * CDDL HEADER END
20*10491SRishi.Srivatsavai@Sun.COM  */
21*10491SRishi.Srivatsavai@Sun.COM /*
22*10491SRishi.Srivatsavai@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23*10491SRishi.Srivatsavai@Sun.COM  * Use is subject to license terms.
24*10491SRishi.Srivatsavai@Sun.COM  */
25*10491SRishi.Srivatsavai@Sun.COM 
26*10491SRishi.Srivatsavai@Sun.COM #include <stdio.h>
27*10491SRishi.Srivatsavai@Sun.COM #include <sys/types.h>
28*10491SRishi.Srivatsavai@Sun.COM #include <string.h>
29*10491SRishi.Srivatsavai@Sun.COM #include <fcntl.h>
30*10491SRishi.Srivatsavai@Sun.COM #include <unistd.h>
31*10491SRishi.Srivatsavai@Sun.COM #include <stropts.h>
32*10491SRishi.Srivatsavai@Sun.COM #include <ctype.h>
33*10491SRishi.Srivatsavai@Sun.COM #include <errno.h>
34*10491SRishi.Srivatsavai@Sun.COM #include <stdlib.h>
35*10491SRishi.Srivatsavai@Sun.COM #include <door.h>
36*10491SRishi.Srivatsavai@Sun.COM #include <sys/mman.h>
37*10491SRishi.Srivatsavai@Sun.COM #include <libscf.h>
38*10491SRishi.Srivatsavai@Sun.COM #include <libscf_priv.h>
39*10491SRishi.Srivatsavai@Sun.COM #include <libdllink.h>
40*10491SRishi.Srivatsavai@Sun.COM #include <libdlbridge.h>
41*10491SRishi.Srivatsavai@Sun.COM #include <libdladm_impl.h>
42*10491SRishi.Srivatsavai@Sun.COM #include <stp_in.h>
43*10491SRishi.Srivatsavai@Sun.COM #include <net/bridge.h>
44*10491SRishi.Srivatsavai@Sun.COM #include <net/trill.h>
45*10491SRishi.Srivatsavai@Sun.COM #include <sys/socket.h>
46*10491SRishi.Srivatsavai@Sun.COM 
47*10491SRishi.Srivatsavai@Sun.COM /*
48*10491SRishi.Srivatsavai@Sun.COM  * Bridge Administration Library.
49*10491SRishi.Srivatsavai@Sun.COM  *
50*10491SRishi.Srivatsavai@Sun.COM  * This library is used by administration tools such as dladm(1M) to configure
51*10491SRishi.Srivatsavai@Sun.COM  * bridges, and by the bridge daemon to retrieve configuration information.
52*10491SRishi.Srivatsavai@Sun.COM  */
53*10491SRishi.Srivatsavai@Sun.COM 
54*10491SRishi.Srivatsavai@Sun.COM #define	BRIDGE_SVC_NAME	"network/bridge"
55*10491SRishi.Srivatsavai@Sun.COM #define	TRILL_SVC_NAME	"network/routing/trill"
56*10491SRishi.Srivatsavai@Sun.COM 
57*10491SRishi.Srivatsavai@Sun.COM #define	DEFAULT_TIMEOUT	60000000
58*10491SRishi.Srivatsavai@Sun.COM #define	INIT_WAIT_USECS	50000
59*10491SRishi.Srivatsavai@Sun.COM #define	MAXPORTS	256
60*10491SRishi.Srivatsavai@Sun.COM 
61*10491SRishi.Srivatsavai@Sun.COM typedef struct scf_state {
62*10491SRishi.Srivatsavai@Sun.COM 	scf_handle_t *ss_handle;
63*10491SRishi.Srivatsavai@Sun.COM 	scf_instance_t *ss_inst;
64*10491SRishi.Srivatsavai@Sun.COM 	scf_service_t *ss_svc;
65*10491SRishi.Srivatsavai@Sun.COM 	scf_snapshot_t *ss_snap;
66*10491SRishi.Srivatsavai@Sun.COM 	scf_propertygroup_t *ss_pg;
67*10491SRishi.Srivatsavai@Sun.COM 	scf_property_t *ss_prop;
68*10491SRishi.Srivatsavai@Sun.COM } scf_state_t;
69*10491SRishi.Srivatsavai@Sun.COM 
70*10491SRishi.Srivatsavai@Sun.COM static void
71*10491SRishi.Srivatsavai@Sun.COM shut_down_scf(scf_state_t *sstate)
72*10491SRishi.Srivatsavai@Sun.COM {
73*10491SRishi.Srivatsavai@Sun.COM 	scf_instance_destroy(sstate->ss_inst);
74*10491SRishi.Srivatsavai@Sun.COM 	(void) scf_handle_unbind(sstate->ss_handle);
75*10491SRishi.Srivatsavai@Sun.COM 	scf_handle_destroy(sstate->ss_handle);
76*10491SRishi.Srivatsavai@Sun.COM }
77*10491SRishi.Srivatsavai@Sun.COM 
78*10491SRishi.Srivatsavai@Sun.COM static char *
79*10491SRishi.Srivatsavai@Sun.COM alloc_fmri(const char *service, const char *instance_name)
80*10491SRishi.Srivatsavai@Sun.COM {
81*10491SRishi.Srivatsavai@Sun.COM 	ssize_t max_fmri;
82*10491SRishi.Srivatsavai@Sun.COM 	char *fmri;
83*10491SRishi.Srivatsavai@Sun.COM 
84*10491SRishi.Srivatsavai@Sun.COM 	/* If the limit is unknown, then use an arbitrary value */
85*10491SRishi.Srivatsavai@Sun.COM 	if ((max_fmri = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) == -1)
86*10491SRishi.Srivatsavai@Sun.COM 		max_fmri = 1024;
87*10491SRishi.Srivatsavai@Sun.COM 	if ((fmri = malloc(max_fmri)) != NULL) {
88*10491SRishi.Srivatsavai@Sun.COM 		(void) snprintf(fmri, max_fmri, "svc:/%s:%s", service,
89*10491SRishi.Srivatsavai@Sun.COM 		    instance_name);
90*10491SRishi.Srivatsavai@Sun.COM 	}
91*10491SRishi.Srivatsavai@Sun.COM 	return (fmri);
92*10491SRishi.Srivatsavai@Sun.COM }
93*10491SRishi.Srivatsavai@Sun.COM 
94*10491SRishi.Srivatsavai@Sun.COM /*
95*10491SRishi.Srivatsavai@Sun.COM  * Start up SCF and bind the requested instance alone.
96*10491SRishi.Srivatsavai@Sun.COM  */
97*10491SRishi.Srivatsavai@Sun.COM static int
98*10491SRishi.Srivatsavai@Sun.COM bind_instance(const char *service, const char *instance_name,
99*10491SRishi.Srivatsavai@Sun.COM     scf_state_t *sstate)
100*10491SRishi.Srivatsavai@Sun.COM {
101*10491SRishi.Srivatsavai@Sun.COM 	char *fmri = NULL;
102*10491SRishi.Srivatsavai@Sun.COM 
103*10491SRishi.Srivatsavai@Sun.COM 	(void) memset(sstate, 0, sizeof (*sstate));
104*10491SRishi.Srivatsavai@Sun.COM 
105*10491SRishi.Srivatsavai@Sun.COM 	if ((sstate->ss_handle = scf_handle_create(SCF_VERSION)) == NULL)
106*10491SRishi.Srivatsavai@Sun.COM 		return (-1);
107*10491SRishi.Srivatsavai@Sun.COM 
108*10491SRishi.Srivatsavai@Sun.COM 	if (scf_handle_bind(sstate->ss_handle) != 0)
109*10491SRishi.Srivatsavai@Sun.COM 		goto failure;
110*10491SRishi.Srivatsavai@Sun.COM 	sstate->ss_inst = scf_instance_create(sstate->ss_handle);
111*10491SRishi.Srivatsavai@Sun.COM 	if (sstate->ss_inst == NULL)
112*10491SRishi.Srivatsavai@Sun.COM 		goto failure;
113*10491SRishi.Srivatsavai@Sun.COM 
114*10491SRishi.Srivatsavai@Sun.COM 	fmri = alloc_fmri(service, instance_name);
115*10491SRishi.Srivatsavai@Sun.COM 
116*10491SRishi.Srivatsavai@Sun.COM 	if (scf_handle_decode_fmri(sstate->ss_handle, fmri, NULL, NULL,
117*10491SRishi.Srivatsavai@Sun.COM 	    sstate->ss_inst, NULL, NULL,
118*10491SRishi.Srivatsavai@Sun.COM 	    SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0)
119*10491SRishi.Srivatsavai@Sun.COM 		goto failure;
120*10491SRishi.Srivatsavai@Sun.COM 	free(fmri);
121*10491SRishi.Srivatsavai@Sun.COM 	return (0);
122*10491SRishi.Srivatsavai@Sun.COM 
123*10491SRishi.Srivatsavai@Sun.COM failure:
124*10491SRishi.Srivatsavai@Sun.COM 	free(fmri);
125*10491SRishi.Srivatsavai@Sun.COM 	shut_down_scf(sstate);
126*10491SRishi.Srivatsavai@Sun.COM 	return (-1);
127*10491SRishi.Srivatsavai@Sun.COM }
128*10491SRishi.Srivatsavai@Sun.COM 
129*10491SRishi.Srivatsavai@Sun.COM /*
130*10491SRishi.Srivatsavai@Sun.COM  * Start up SCF and an exact FMRI.  This is used for creating new instances and
131*10491SRishi.Srivatsavai@Sun.COM  * enable/disable actions.
132*10491SRishi.Srivatsavai@Sun.COM  */
133*10491SRishi.Srivatsavai@Sun.COM static dladm_status_t
134*10491SRishi.Srivatsavai@Sun.COM exact_instance(const char *fmri, scf_state_t *sstate)
135*10491SRishi.Srivatsavai@Sun.COM {
136*10491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
137*10491SRishi.Srivatsavai@Sun.COM 
138*10491SRishi.Srivatsavai@Sun.COM 	(void) memset(sstate, 0, sizeof (*sstate));
139*10491SRishi.Srivatsavai@Sun.COM 
140*10491SRishi.Srivatsavai@Sun.COM 	if ((sstate->ss_handle = scf_handle_create(SCF_VERSION)) == NULL)
141*10491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_NOMEM);
142*10491SRishi.Srivatsavai@Sun.COM 
143*10491SRishi.Srivatsavai@Sun.COM 	status = DLADM_STATUS_FAILED;
144*10491SRishi.Srivatsavai@Sun.COM 	if (scf_handle_bind(sstate->ss_handle) != 0)
145*10491SRishi.Srivatsavai@Sun.COM 		goto failure;
146*10491SRishi.Srivatsavai@Sun.COM 	sstate->ss_svc = scf_service_create(sstate->ss_handle);
147*10491SRishi.Srivatsavai@Sun.COM 	if (sstate->ss_svc == NULL)
148*10491SRishi.Srivatsavai@Sun.COM 		goto failure;
149*10491SRishi.Srivatsavai@Sun.COM 	if (scf_handle_decode_fmri(sstate->ss_handle, fmri, NULL,
150*10491SRishi.Srivatsavai@Sun.COM 	    sstate->ss_svc, NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) {
151*10491SRishi.Srivatsavai@Sun.COM 		if (scf_error() == SCF_ERROR_NOT_FOUND)
152*10491SRishi.Srivatsavai@Sun.COM 			status = DLADM_STATUS_OPTMISSING;
153*10491SRishi.Srivatsavai@Sun.COM 		goto failure;
154*10491SRishi.Srivatsavai@Sun.COM 	}
155*10491SRishi.Srivatsavai@Sun.COM 	sstate->ss_inst = scf_instance_create(sstate->ss_handle);
156*10491SRishi.Srivatsavai@Sun.COM 	if (sstate->ss_inst == NULL)
157*10491SRishi.Srivatsavai@Sun.COM 		goto failure;
158*10491SRishi.Srivatsavai@Sun.COM 	return (DLADM_STATUS_OK);
159*10491SRishi.Srivatsavai@Sun.COM 
160*10491SRishi.Srivatsavai@Sun.COM failure:
161*10491SRishi.Srivatsavai@Sun.COM 	shut_down_scf(sstate);
162*10491SRishi.Srivatsavai@Sun.COM 	return (status);
163*10491SRishi.Srivatsavai@Sun.COM }
164*10491SRishi.Srivatsavai@Sun.COM 
165*10491SRishi.Srivatsavai@Sun.COM static void
166*10491SRishi.Srivatsavai@Sun.COM drop_composed(scf_state_t *sstate)
167*10491SRishi.Srivatsavai@Sun.COM {
168*10491SRishi.Srivatsavai@Sun.COM 	scf_property_destroy(sstate->ss_prop);
169*10491SRishi.Srivatsavai@Sun.COM 	scf_pg_destroy(sstate->ss_pg);
170*10491SRishi.Srivatsavai@Sun.COM 	scf_snapshot_destroy(sstate->ss_snap);
171*10491SRishi.Srivatsavai@Sun.COM }
172*10491SRishi.Srivatsavai@Sun.COM 
173*10491SRishi.Srivatsavai@Sun.COM /*
174*10491SRishi.Srivatsavai@Sun.COM  * This function sets up a composed view of the configuration information for
175*10491SRishi.Srivatsavai@Sun.COM  * the specified instance.  When this is done, the get_property() function
176*10491SRishi.Srivatsavai@Sun.COM  * should be able to return individual parameters.
177*10491SRishi.Srivatsavai@Sun.COM  */
178*10491SRishi.Srivatsavai@Sun.COM static int
179*10491SRishi.Srivatsavai@Sun.COM get_composed_properties(const char *lpg, boolean_t snap, scf_state_t *sstate)
180*10491SRishi.Srivatsavai@Sun.COM {
181*10491SRishi.Srivatsavai@Sun.COM 	sstate->ss_snap = NULL;
182*10491SRishi.Srivatsavai@Sun.COM 	sstate->ss_pg = NULL;
183*10491SRishi.Srivatsavai@Sun.COM 	sstate->ss_prop = NULL;
184*10491SRishi.Srivatsavai@Sun.COM 
185*10491SRishi.Srivatsavai@Sun.COM 	if (snap) {
186*10491SRishi.Srivatsavai@Sun.COM 		sstate->ss_snap = scf_snapshot_create(sstate->ss_handle);
187*10491SRishi.Srivatsavai@Sun.COM 		if (sstate->ss_snap == NULL)
188*10491SRishi.Srivatsavai@Sun.COM 			goto failure;
189*10491SRishi.Srivatsavai@Sun.COM 		if (scf_instance_get_snapshot(sstate->ss_inst, "running",
190*10491SRishi.Srivatsavai@Sun.COM 		    sstate->ss_snap) != 0)
191*10491SRishi.Srivatsavai@Sun.COM 			goto failure;
192*10491SRishi.Srivatsavai@Sun.COM 	}
193*10491SRishi.Srivatsavai@Sun.COM 	if ((sstate->ss_pg = scf_pg_create(sstate->ss_handle)) == NULL)
194*10491SRishi.Srivatsavai@Sun.COM 		goto failure;
195*10491SRishi.Srivatsavai@Sun.COM 	if (scf_instance_get_pg_composed(sstate->ss_inst, sstate->ss_snap, lpg,
196*10491SRishi.Srivatsavai@Sun.COM 	    sstate->ss_pg) != 0)
197*10491SRishi.Srivatsavai@Sun.COM 		goto failure;
198*10491SRishi.Srivatsavai@Sun.COM 	if ((sstate->ss_prop = scf_property_create(sstate->ss_handle)) ==
199*10491SRishi.Srivatsavai@Sun.COM 	    NULL)
200*10491SRishi.Srivatsavai@Sun.COM 		goto failure;
201*10491SRishi.Srivatsavai@Sun.COM 	return (0);
202*10491SRishi.Srivatsavai@Sun.COM 
203*10491SRishi.Srivatsavai@Sun.COM failure:
204*10491SRishi.Srivatsavai@Sun.COM 	drop_composed(sstate);
205*10491SRishi.Srivatsavai@Sun.COM 	return (-1);
206*10491SRishi.Srivatsavai@Sun.COM }
207*10491SRishi.Srivatsavai@Sun.COM 
208*10491SRishi.Srivatsavai@Sun.COM static int
209*10491SRishi.Srivatsavai@Sun.COM get_count(const char *lprop, scf_state_t *sstate, uint64_t *answer)
210*10491SRishi.Srivatsavai@Sun.COM {
211*10491SRishi.Srivatsavai@Sun.COM 	scf_value_t *val;
212*10491SRishi.Srivatsavai@Sun.COM 	int retv;
213*10491SRishi.Srivatsavai@Sun.COM 
214*10491SRishi.Srivatsavai@Sun.COM 	if (scf_pg_get_property(sstate->ss_pg, lprop, sstate->ss_prop) != 0)
215*10491SRishi.Srivatsavai@Sun.COM 		return (-1);
216*10491SRishi.Srivatsavai@Sun.COM 	if ((val = scf_value_create(sstate->ss_handle)) == NULL)
217*10491SRishi.Srivatsavai@Sun.COM 		return (-1);
218*10491SRishi.Srivatsavai@Sun.COM 
219*10491SRishi.Srivatsavai@Sun.COM 	if (scf_property_get_value(sstate->ss_prop, val) == 0 &&
220*10491SRishi.Srivatsavai@Sun.COM 	    scf_value_get_count(val, answer) == 0)
221*10491SRishi.Srivatsavai@Sun.COM 		retv = 0;
222*10491SRishi.Srivatsavai@Sun.COM 	else
223*10491SRishi.Srivatsavai@Sun.COM 		retv = -1;
224*10491SRishi.Srivatsavai@Sun.COM 	scf_value_destroy(val);
225*10491SRishi.Srivatsavai@Sun.COM 	return (retv);
226*10491SRishi.Srivatsavai@Sun.COM }
227*10491SRishi.Srivatsavai@Sun.COM 
228*10491SRishi.Srivatsavai@Sun.COM static int
229*10491SRishi.Srivatsavai@Sun.COM get_boolean(const char *lprop, scf_state_t *sstate, boolean_t *answer)
230*10491SRishi.Srivatsavai@Sun.COM {
231*10491SRishi.Srivatsavai@Sun.COM 	scf_value_t *val;
232*10491SRishi.Srivatsavai@Sun.COM 	int retv;
233*10491SRishi.Srivatsavai@Sun.COM 	uint8_t bval;
234*10491SRishi.Srivatsavai@Sun.COM 
235*10491SRishi.Srivatsavai@Sun.COM 	if (scf_pg_get_property(sstate->ss_pg, lprop, sstate->ss_prop) != 0)
236*10491SRishi.Srivatsavai@Sun.COM 		return (-1);
237*10491SRishi.Srivatsavai@Sun.COM 	if ((val = scf_value_create(sstate->ss_handle)) == NULL)
238*10491SRishi.Srivatsavai@Sun.COM 		return (-1);
239*10491SRishi.Srivatsavai@Sun.COM 
240*10491SRishi.Srivatsavai@Sun.COM 	if (scf_property_get_value(sstate->ss_prop, val) == 0 &&
241*10491SRishi.Srivatsavai@Sun.COM 	    scf_value_get_boolean(val, &bval) == 0) {
242*10491SRishi.Srivatsavai@Sun.COM 		retv = 0;
243*10491SRishi.Srivatsavai@Sun.COM 		*answer = bval != 0;
244*10491SRishi.Srivatsavai@Sun.COM 	} else {
245*10491SRishi.Srivatsavai@Sun.COM 		retv = -1;
246*10491SRishi.Srivatsavai@Sun.COM 	}
247*10491SRishi.Srivatsavai@Sun.COM 	scf_value_destroy(val);
248*10491SRishi.Srivatsavai@Sun.COM 	return (retv);
249*10491SRishi.Srivatsavai@Sun.COM }
250*10491SRishi.Srivatsavai@Sun.COM 
251*10491SRishi.Srivatsavai@Sun.COM static dladm_status_t
252*10491SRishi.Srivatsavai@Sun.COM bridge_door_call(const char *instname, bridge_door_type_t dtype,
253*10491SRishi.Srivatsavai@Sun.COM     datalink_id_t linkid, void **bufp, size_t inlen, size_t *buflenp,
254*10491SRishi.Srivatsavai@Sun.COM     boolean_t is_list)
255*10491SRishi.Srivatsavai@Sun.COM {
256*10491SRishi.Srivatsavai@Sun.COM 	char doorname[MAXPATHLEN];
257*10491SRishi.Srivatsavai@Sun.COM 	int did, retv, etmp;
258*10491SRishi.Srivatsavai@Sun.COM 	bridge_door_cmd_t *bdc;
259*10491SRishi.Srivatsavai@Sun.COM 	door_arg_t arg;
260*10491SRishi.Srivatsavai@Sun.COM 
261*10491SRishi.Srivatsavai@Sun.COM 	(void) snprintf(doorname, sizeof (doorname), "%s/%s", DOOR_DIRNAME,
262*10491SRishi.Srivatsavai@Sun.COM 	    instname);
263*10491SRishi.Srivatsavai@Sun.COM 
264*10491SRishi.Srivatsavai@Sun.COM 	/* Knock on the door */
265*10491SRishi.Srivatsavai@Sun.COM 	did = open(doorname, O_RDONLY | O_NOFOLLOW | O_NONBLOCK);
266*10491SRishi.Srivatsavai@Sun.COM 	if (did == -1)
267*10491SRishi.Srivatsavai@Sun.COM 		return (dladm_errno2status(errno));
268*10491SRishi.Srivatsavai@Sun.COM 
269*10491SRishi.Srivatsavai@Sun.COM 	if ((bdc = malloc(sizeof (*bdc) + inlen)) == NULL) {
270*10491SRishi.Srivatsavai@Sun.COM 		(void) close(did);
271*10491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_NOMEM);
272*10491SRishi.Srivatsavai@Sun.COM 	}
273*10491SRishi.Srivatsavai@Sun.COM 	bdc->bdc_type = dtype;
274*10491SRishi.Srivatsavai@Sun.COM 	bdc->bdc_linkid = linkid;
275*10491SRishi.Srivatsavai@Sun.COM 	if (inlen != 0)
276*10491SRishi.Srivatsavai@Sun.COM 		(void) memcpy(bdc + 1, *bufp, inlen);
277*10491SRishi.Srivatsavai@Sun.COM 
278*10491SRishi.Srivatsavai@Sun.COM 	(void) memset(&arg, 0, sizeof (arg));
279*10491SRishi.Srivatsavai@Sun.COM 	arg.data_ptr = (char *)bdc;
280*10491SRishi.Srivatsavai@Sun.COM 	arg.data_size = sizeof (*bdc) + inlen;
281*10491SRishi.Srivatsavai@Sun.COM 	arg.rbuf = *bufp;
282*10491SRishi.Srivatsavai@Sun.COM 	arg.rsize = *buflenp;
283*10491SRishi.Srivatsavai@Sun.COM 
284*10491SRishi.Srivatsavai@Sun.COM 	/* The door_call function doesn't restart, so take care of that */
285*10491SRishi.Srivatsavai@Sun.COM 	do {
286*10491SRishi.Srivatsavai@Sun.COM 		errno = 0;
287*10491SRishi.Srivatsavai@Sun.COM 		if ((retv = door_call(did, &arg)) == 0)
288*10491SRishi.Srivatsavai@Sun.COM 			break;
289*10491SRishi.Srivatsavai@Sun.COM 	} while (errno == EINTR);
290*10491SRishi.Srivatsavai@Sun.COM 
291*10491SRishi.Srivatsavai@Sun.COM 	/* If we get an unexpected response, then return an error */
292*10491SRishi.Srivatsavai@Sun.COM 	if (retv == 0) {
293*10491SRishi.Srivatsavai@Sun.COM 		/* The daemon returns a single int for errors */
294*10491SRishi.Srivatsavai@Sun.COM 		/* LINTED: pointer alignment */
295*10491SRishi.Srivatsavai@Sun.COM 		if (arg.data_size == sizeof (int) && *(int *)arg.rbuf != 0) {
296*10491SRishi.Srivatsavai@Sun.COM 			retv = -1;
297*10491SRishi.Srivatsavai@Sun.COM 			/* LINTED: pointer alignment */
298*10491SRishi.Srivatsavai@Sun.COM 			errno = *(int *)arg.rbuf;
299*10491SRishi.Srivatsavai@Sun.COM 		}
300*10491SRishi.Srivatsavai@Sun.COM 		/* Terminated daemon returns with zero data */
301*10491SRishi.Srivatsavai@Sun.COM 		if (arg.data_size == 0) {
302*10491SRishi.Srivatsavai@Sun.COM 			retv = -1;
303*10491SRishi.Srivatsavai@Sun.COM 			errno = EBADF;
304*10491SRishi.Srivatsavai@Sun.COM 		}
305*10491SRishi.Srivatsavai@Sun.COM 	}
306*10491SRishi.Srivatsavai@Sun.COM 
307*10491SRishi.Srivatsavai@Sun.COM 	if (retv == 0) {
308*10491SRishi.Srivatsavai@Sun.COM 		if (arg.rbuf != *bufp) {
309*10491SRishi.Srivatsavai@Sun.COM 			if (is_list) {
310*10491SRishi.Srivatsavai@Sun.COM 				void *newp;
311*10491SRishi.Srivatsavai@Sun.COM 
312*10491SRishi.Srivatsavai@Sun.COM 				newp = realloc(*bufp, arg.data_size);
313*10491SRishi.Srivatsavai@Sun.COM 				if (newp == NULL) {
314*10491SRishi.Srivatsavai@Sun.COM 					retv = -1;
315*10491SRishi.Srivatsavai@Sun.COM 				} else {
316*10491SRishi.Srivatsavai@Sun.COM 					*bufp = newp;
317*10491SRishi.Srivatsavai@Sun.COM 					(void) memcpy(*bufp, arg.rbuf,
318*10491SRishi.Srivatsavai@Sun.COM 					    arg.data_size);
319*10491SRishi.Srivatsavai@Sun.COM 				}
320*10491SRishi.Srivatsavai@Sun.COM 			}
321*10491SRishi.Srivatsavai@Sun.COM 			(void) munmap(arg.rbuf, arg.rsize);
322*10491SRishi.Srivatsavai@Sun.COM 		}
323*10491SRishi.Srivatsavai@Sun.COM 		if (is_list) {
324*10491SRishi.Srivatsavai@Sun.COM 			*buflenp = arg.data_size;
325*10491SRishi.Srivatsavai@Sun.COM 		} else if (arg.data_size != *buflenp || arg.rbuf != *bufp) {
326*10491SRishi.Srivatsavai@Sun.COM 			errno = EINVAL;
327*10491SRishi.Srivatsavai@Sun.COM 			retv = -1;
328*10491SRishi.Srivatsavai@Sun.COM 		}
329*10491SRishi.Srivatsavai@Sun.COM 	}
330*10491SRishi.Srivatsavai@Sun.COM 
331*10491SRishi.Srivatsavai@Sun.COM 	etmp = errno;
332*10491SRishi.Srivatsavai@Sun.COM 	(void) close(did);
333*10491SRishi.Srivatsavai@Sun.COM 
334*10491SRishi.Srivatsavai@Sun.COM 	/* Revoked door is the same as no door at all */
335*10491SRishi.Srivatsavai@Sun.COM 	if (etmp == EBADF)
336*10491SRishi.Srivatsavai@Sun.COM 		etmp = ENOENT;
337*10491SRishi.Srivatsavai@Sun.COM 
338*10491SRishi.Srivatsavai@Sun.COM 	return (retv == 0 ? DLADM_STATUS_OK : dladm_errno2status(etmp));
339*10491SRishi.Srivatsavai@Sun.COM }
340*10491SRishi.Srivatsavai@Sun.COM 
341*10491SRishi.Srivatsavai@Sun.COM /*
342*10491SRishi.Srivatsavai@Sun.COM  * Wrapper function for making per-port calls.
343*10491SRishi.Srivatsavai@Sun.COM  */
344*10491SRishi.Srivatsavai@Sun.COM static dladm_status_t
345*10491SRishi.Srivatsavai@Sun.COM port_door_call(dladm_handle_t handle, datalink_id_t linkid,
346*10491SRishi.Srivatsavai@Sun.COM     bridge_door_type_t dtype, void *buf, size_t inlen, size_t buflen)
347*10491SRishi.Srivatsavai@Sun.COM {
348*10491SRishi.Srivatsavai@Sun.COM 	char bridge[MAXLINKNAMELEN];
349*10491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
350*10491SRishi.Srivatsavai@Sun.COM 
351*10491SRishi.Srivatsavai@Sun.COM 	status = dladm_bridge_getlink(handle, linkid, bridge, sizeof (bridge));
352*10491SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK)
353*10491SRishi.Srivatsavai@Sun.COM 		return (status);
354*10491SRishi.Srivatsavai@Sun.COM 	return (bridge_door_call(bridge, dtype, linkid, &buf, inlen, &buflen,
355*10491SRishi.Srivatsavai@Sun.COM 	    B_FALSE));
356*10491SRishi.Srivatsavai@Sun.COM }
357*10491SRishi.Srivatsavai@Sun.COM 
358*10491SRishi.Srivatsavai@Sun.COM static dladm_status_t
359*10491SRishi.Srivatsavai@Sun.COM bridge_refresh(const char *bridge)
360*10491SRishi.Srivatsavai@Sun.COM {
361*10491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
362*10491SRishi.Srivatsavai@Sun.COM 	int twoints[2];
363*10491SRishi.Srivatsavai@Sun.COM 	void *bdptr;
364*10491SRishi.Srivatsavai@Sun.COM 	size_t buflen;
365*10491SRishi.Srivatsavai@Sun.COM 	char *fmri;
366*10491SRishi.Srivatsavai@Sun.COM 	int refresh_count;
367*10491SRishi.Srivatsavai@Sun.COM 
368*10491SRishi.Srivatsavai@Sun.COM 	buflen = sizeof (twoints);
369*10491SRishi.Srivatsavai@Sun.COM 	bdptr = twoints;
370*10491SRishi.Srivatsavai@Sun.COM 	status = bridge_door_call(bridge, bdcBridgeGetRefreshCount,
371*10491SRishi.Srivatsavai@Sun.COM 	    DATALINK_INVALID_LINKID, &bdptr, 0, &buflen, B_FALSE);
372*10491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_NOTFOUND)
373*10491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_OK);
374*10491SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK)
375*10491SRishi.Srivatsavai@Sun.COM 		return (status);
376*10491SRishi.Srivatsavai@Sun.COM 	refresh_count = twoints[0];
377*10491SRishi.Srivatsavai@Sun.COM 	if ((fmri = alloc_fmri(BRIDGE_SVC_NAME, bridge)) == NULL)
378*10491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_NOMEM);
379*10491SRishi.Srivatsavai@Sun.COM 	status = smf_refresh_instance(fmri) == 0 ?
380*10491SRishi.Srivatsavai@Sun.COM 	    DLADM_STATUS_OK : DLADM_STATUS_FAILED;
381*10491SRishi.Srivatsavai@Sun.COM 	free(fmri);
382*10491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_OK) {
383*10491SRishi.Srivatsavai@Sun.COM 		int i = 0;
384*10491SRishi.Srivatsavai@Sun.COM 
385*10491SRishi.Srivatsavai@Sun.COM 		/*
386*10491SRishi.Srivatsavai@Sun.COM 		 * SMF doesn't give any synchronous behavior or dependency
387*10491SRishi.Srivatsavai@Sun.COM 		 * ordering for refresh operations, so we have to invent our
388*10491SRishi.Srivatsavai@Sun.COM 		 * own mechanism here.  Get the refresh counter from the
389*10491SRishi.Srivatsavai@Sun.COM 		 * daemon, and wait for it to change.  It's not pretty, but
390*10491SRishi.Srivatsavai@Sun.COM 		 * it's sufficient.
391*10491SRishi.Srivatsavai@Sun.COM 		 */
392*10491SRishi.Srivatsavai@Sun.COM 		while (++i <= 10) {
393*10491SRishi.Srivatsavai@Sun.COM 			buflen = sizeof (twoints);
394*10491SRishi.Srivatsavai@Sun.COM 			bdptr = twoints;
395*10491SRishi.Srivatsavai@Sun.COM 			status = bridge_door_call(bridge,
396*10491SRishi.Srivatsavai@Sun.COM 			    bdcBridgeGetRefreshCount, DATALINK_INVALID_LINKID,
397*10491SRishi.Srivatsavai@Sun.COM 			    &bdptr, 0, &buflen, B_FALSE);
398*10491SRishi.Srivatsavai@Sun.COM 			if (status != DLADM_STATUS_OK)
399*10491SRishi.Srivatsavai@Sun.COM 				break;
400*10491SRishi.Srivatsavai@Sun.COM 			if (twoints[0] != refresh_count)
401*10491SRishi.Srivatsavai@Sun.COM 				break;
402*10491SRishi.Srivatsavai@Sun.COM 			(void) usleep(100000);
403*10491SRishi.Srivatsavai@Sun.COM 		}
404*10491SRishi.Srivatsavai@Sun.COM 		fmri = alloc_fmri(TRILL_SVC_NAME, bridge);
405*10491SRishi.Srivatsavai@Sun.COM 		if (fmri == NULL)
406*10491SRishi.Srivatsavai@Sun.COM 			return (DLADM_STATUS_NOMEM);
407*10491SRishi.Srivatsavai@Sun.COM 		status = smf_refresh_instance(fmri) == 0 ||
408*10491SRishi.Srivatsavai@Sun.COM 		    scf_error() == SCF_ERROR_NOT_FOUND ?
409*10491SRishi.Srivatsavai@Sun.COM 		    DLADM_STATUS_OK : DLADM_STATUS_FAILED;
410*10491SRishi.Srivatsavai@Sun.COM 		free(fmri);
411*10491SRishi.Srivatsavai@Sun.COM 	}
412*10491SRishi.Srivatsavai@Sun.COM 	return (status);
413*10491SRishi.Srivatsavai@Sun.COM }
414*10491SRishi.Srivatsavai@Sun.COM 
415*10491SRishi.Srivatsavai@Sun.COM /*
416*10491SRishi.Srivatsavai@Sun.COM  * Look up bridge property values from SCF and return them.
417*10491SRishi.Srivatsavai@Sun.COM  */
418*10491SRishi.Srivatsavai@Sun.COM dladm_status_t
419*10491SRishi.Srivatsavai@Sun.COM dladm_bridge_get_properties(const char *instance_name, UID_STP_CFG_T *cfg,
420*10491SRishi.Srivatsavai@Sun.COM     dladm_bridge_prot_t *brprotp)
421*10491SRishi.Srivatsavai@Sun.COM {
422*10491SRishi.Srivatsavai@Sun.COM 	scf_state_t sstate;
423*10491SRishi.Srivatsavai@Sun.COM 	uint64_t value;
424*10491SRishi.Srivatsavai@Sun.COM 	boolean_t trill_enabled;
425*10491SRishi.Srivatsavai@Sun.COM 
426*10491SRishi.Srivatsavai@Sun.COM 	cfg->field_mask = 0;
427*10491SRishi.Srivatsavai@Sun.COM 	cfg->bridge_priority = DEF_BR_PRIO;
428*10491SRishi.Srivatsavai@Sun.COM 	cfg->max_age = DEF_BR_MAXAGE;
429*10491SRishi.Srivatsavai@Sun.COM 	cfg->hello_time = DEF_BR_HELLOT;
430*10491SRishi.Srivatsavai@Sun.COM 	cfg->forward_delay = DEF_BR_FWDELAY;
431*10491SRishi.Srivatsavai@Sun.COM 	cfg->force_version = DEF_FORCE_VERS;
432*10491SRishi.Srivatsavai@Sun.COM 
433*10491SRishi.Srivatsavai@Sun.COM 	(void) strlcpy(cfg->vlan_name, instance_name, sizeof (cfg->vlan_name));
434*10491SRishi.Srivatsavai@Sun.COM 
435*10491SRishi.Srivatsavai@Sun.COM 	*brprotp = DLADM_BRIDGE_PROT_STP;
436*10491SRishi.Srivatsavai@Sun.COM 
437*10491SRishi.Srivatsavai@Sun.COM 	/* It's ok for this to be missing; it's installed separately */
438*10491SRishi.Srivatsavai@Sun.COM 	if (bind_instance(TRILL_SVC_NAME, instance_name, &sstate) == 0) {
439*10491SRishi.Srivatsavai@Sun.COM 		trill_enabled = B_FALSE;
440*10491SRishi.Srivatsavai@Sun.COM 		if (get_composed_properties(SCF_PG_GENERAL, B_FALSE, &sstate) ==
441*10491SRishi.Srivatsavai@Sun.COM 		    0) {
442*10491SRishi.Srivatsavai@Sun.COM 			(void) get_boolean(SCF_PROPERTY_ENABLED, &sstate,
443*10491SRishi.Srivatsavai@Sun.COM 			    &trill_enabled);
444*10491SRishi.Srivatsavai@Sun.COM 			if (trill_enabled)
445*10491SRishi.Srivatsavai@Sun.COM 				*brprotp = DLADM_BRIDGE_PROT_TRILL;
446*10491SRishi.Srivatsavai@Sun.COM 			drop_composed(&sstate);
447*10491SRishi.Srivatsavai@Sun.COM 		}
448*10491SRishi.Srivatsavai@Sun.COM 		if (get_composed_properties(SCF_PG_GENERAL_OVR, B_FALSE,
449*10491SRishi.Srivatsavai@Sun.COM 		    &sstate) == 0) {
450*10491SRishi.Srivatsavai@Sun.COM 			(void) get_boolean(SCF_PROPERTY_ENABLED, &sstate,
451*10491SRishi.Srivatsavai@Sun.COM 			    &trill_enabled);
452*10491SRishi.Srivatsavai@Sun.COM 			if (trill_enabled)
453*10491SRishi.Srivatsavai@Sun.COM 				*brprotp = DLADM_BRIDGE_PROT_TRILL;
454*10491SRishi.Srivatsavai@Sun.COM 			drop_composed(&sstate);
455*10491SRishi.Srivatsavai@Sun.COM 		}
456*10491SRishi.Srivatsavai@Sun.COM 		shut_down_scf(&sstate);
457*10491SRishi.Srivatsavai@Sun.COM 	}
458*10491SRishi.Srivatsavai@Sun.COM 
459*10491SRishi.Srivatsavai@Sun.COM 	cfg->stp_enabled = (*brprotp == DLADM_BRIDGE_PROT_STP) ?
460*10491SRishi.Srivatsavai@Sun.COM 	    STP_ENABLED : STP_DISABLED;
461*10491SRishi.Srivatsavai@Sun.COM 	cfg->field_mask |= BR_CFG_STATE;
462*10491SRishi.Srivatsavai@Sun.COM 
463*10491SRishi.Srivatsavai@Sun.COM 	if (bind_instance(BRIDGE_SVC_NAME, instance_name, &sstate) != 0)
464*10491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_REPOSITORYINVAL);
465*10491SRishi.Srivatsavai@Sun.COM 
466*10491SRishi.Srivatsavai@Sun.COM 	if (get_composed_properties("config", B_TRUE, &sstate) != 0) {
467*10491SRishi.Srivatsavai@Sun.COM 		shut_down_scf(&sstate);
468*10491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_REPOSITORYINVAL);
469*10491SRishi.Srivatsavai@Sun.COM 	}
470*10491SRishi.Srivatsavai@Sun.COM 
471*10491SRishi.Srivatsavai@Sun.COM 	if (get_count("priority", &sstate, &value) == 0) {
472*10491SRishi.Srivatsavai@Sun.COM 		cfg->bridge_priority = value;
473*10491SRishi.Srivatsavai@Sun.COM 		cfg->field_mask |= BR_CFG_PRIO;
474*10491SRishi.Srivatsavai@Sun.COM 	}
475*10491SRishi.Srivatsavai@Sun.COM 	if (get_count("max-age", &sstate, &value) == 0) {
476*10491SRishi.Srivatsavai@Sun.COM 		cfg->max_age = value / IEEE_TIMER_SCALE;
477*10491SRishi.Srivatsavai@Sun.COM 		cfg->field_mask |= BR_CFG_AGE;
478*10491SRishi.Srivatsavai@Sun.COM 	}
479*10491SRishi.Srivatsavai@Sun.COM 	if (get_count("hello-time", &sstate, &value) == 0) {
480*10491SRishi.Srivatsavai@Sun.COM 		cfg->hello_time = value / IEEE_TIMER_SCALE;
481*10491SRishi.Srivatsavai@Sun.COM 		cfg->field_mask |= BR_CFG_HELLO;
482*10491SRishi.Srivatsavai@Sun.COM 	}
483*10491SRishi.Srivatsavai@Sun.COM 	if (get_count("forward-delay", &sstate, &value) == 0) {
484*10491SRishi.Srivatsavai@Sun.COM 		cfg->forward_delay = value / IEEE_TIMER_SCALE;
485*10491SRishi.Srivatsavai@Sun.COM 		cfg->field_mask |= BR_CFG_DELAY;
486*10491SRishi.Srivatsavai@Sun.COM 	}
487*10491SRishi.Srivatsavai@Sun.COM 	if (get_count("force-protocol", &sstate, &value) == 0) {
488*10491SRishi.Srivatsavai@Sun.COM 		cfg->force_version = value;
489*10491SRishi.Srivatsavai@Sun.COM 		cfg->field_mask |= BR_CFG_FORCE_VER;
490*10491SRishi.Srivatsavai@Sun.COM 	}
491*10491SRishi.Srivatsavai@Sun.COM 
492*10491SRishi.Srivatsavai@Sun.COM 	drop_composed(&sstate);
493*10491SRishi.Srivatsavai@Sun.COM 	shut_down_scf(&sstate);
494*10491SRishi.Srivatsavai@Sun.COM 	return (DLADM_STATUS_OK);
495*10491SRishi.Srivatsavai@Sun.COM }
496*10491SRishi.Srivatsavai@Sun.COM 
497*10491SRishi.Srivatsavai@Sun.COM /*
498*10491SRishi.Srivatsavai@Sun.COM  * Retrieve special non-settable and undocumented parameters.
499*10491SRishi.Srivatsavai@Sun.COM  */
500*10491SRishi.Srivatsavai@Sun.COM dladm_status_t
501*10491SRishi.Srivatsavai@Sun.COM dladm_bridge_get_privprop(const char *instance_name, boolean_t *debugp,
502*10491SRishi.Srivatsavai@Sun.COM     uint32_t *tablemaxp)
503*10491SRishi.Srivatsavai@Sun.COM {
504*10491SRishi.Srivatsavai@Sun.COM 	scf_state_t sstate;
505*10491SRishi.Srivatsavai@Sun.COM 	uint64_t value;
506*10491SRishi.Srivatsavai@Sun.COM 
507*10491SRishi.Srivatsavai@Sun.COM 	*debugp = B_FALSE;
508*10491SRishi.Srivatsavai@Sun.COM 	*tablemaxp = 10000;
509*10491SRishi.Srivatsavai@Sun.COM 
510*10491SRishi.Srivatsavai@Sun.COM 	if (bind_instance(BRIDGE_SVC_NAME, instance_name, &sstate) != 0)
511*10491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_REPOSITORYINVAL);
512*10491SRishi.Srivatsavai@Sun.COM 
513*10491SRishi.Srivatsavai@Sun.COM 	if (get_composed_properties("config", B_TRUE, &sstate) != 0) {
514*10491SRishi.Srivatsavai@Sun.COM 		shut_down_scf(&sstate);
515*10491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_REPOSITORYINVAL);
516*10491SRishi.Srivatsavai@Sun.COM 	}
517*10491SRishi.Srivatsavai@Sun.COM 
518*10491SRishi.Srivatsavai@Sun.COM 	(void) get_boolean("debug", &sstate, debugp);
519*10491SRishi.Srivatsavai@Sun.COM 	if (get_count("table-maximum", &sstate, &value) == 0)
520*10491SRishi.Srivatsavai@Sun.COM 		*tablemaxp = (uint32_t)value;
521*10491SRishi.Srivatsavai@Sun.COM 
522*10491SRishi.Srivatsavai@Sun.COM 	drop_composed(&sstate);
523*10491SRishi.Srivatsavai@Sun.COM 	shut_down_scf(&sstate);
524*10491SRishi.Srivatsavai@Sun.COM 	return (DLADM_STATUS_OK);
525*10491SRishi.Srivatsavai@Sun.COM }
526*10491SRishi.Srivatsavai@Sun.COM 
527*10491SRishi.Srivatsavai@Sun.COM static boolean_t
528*10491SRishi.Srivatsavai@Sun.COM set_count_property(scf_handle_t *handle, scf_transaction_t *tran,
529*10491SRishi.Srivatsavai@Sun.COM     const char *propname, uint64_t propval)
530*10491SRishi.Srivatsavai@Sun.COM {
531*10491SRishi.Srivatsavai@Sun.COM 	scf_transaction_entry_t *entry;
532*10491SRishi.Srivatsavai@Sun.COM 	scf_value_t *value = NULL;
533*10491SRishi.Srivatsavai@Sun.COM 
534*10491SRishi.Srivatsavai@Sun.COM 	if ((entry = scf_entry_create(handle)) == NULL)
535*10491SRishi.Srivatsavai@Sun.COM 		return (B_FALSE);
536*10491SRishi.Srivatsavai@Sun.COM 
537*10491SRishi.Srivatsavai@Sun.COM 	if ((value = scf_value_create(handle)) == NULL)
538*10491SRishi.Srivatsavai@Sun.COM 		goto out;
539*10491SRishi.Srivatsavai@Sun.COM 	if (scf_transaction_property_new(tran, entry, propname,
540*10491SRishi.Srivatsavai@Sun.COM 	    SCF_TYPE_COUNT) != 0 &&
541*10491SRishi.Srivatsavai@Sun.COM 	    scf_transaction_property_change(tran, entry, propname,
542*10491SRishi.Srivatsavai@Sun.COM 	    SCF_TYPE_COUNT) != 0)
543*10491SRishi.Srivatsavai@Sun.COM 		goto out;
544*10491SRishi.Srivatsavai@Sun.COM 	scf_value_set_count(value, propval);
545*10491SRishi.Srivatsavai@Sun.COM 	if (scf_entry_add_value(entry, value) == 0)
546*10491SRishi.Srivatsavai@Sun.COM 		return (B_TRUE);
547*10491SRishi.Srivatsavai@Sun.COM 
548*10491SRishi.Srivatsavai@Sun.COM out:
549*10491SRishi.Srivatsavai@Sun.COM 	if (value != NULL)
550*10491SRishi.Srivatsavai@Sun.COM 		scf_value_destroy(value);
551*10491SRishi.Srivatsavai@Sun.COM 
552*10491SRishi.Srivatsavai@Sun.COM 	scf_entry_destroy_children(entry);
553*10491SRishi.Srivatsavai@Sun.COM 	scf_entry_destroy(entry);
554*10491SRishi.Srivatsavai@Sun.COM 
555*10491SRishi.Srivatsavai@Sun.COM 	return (B_FALSE);
556*10491SRishi.Srivatsavai@Sun.COM }
557*10491SRishi.Srivatsavai@Sun.COM 
558*10491SRishi.Srivatsavai@Sun.COM static boolean_t
559*10491SRishi.Srivatsavai@Sun.COM set_string_property(scf_handle_t *handle, scf_transaction_t *tran,
560*10491SRishi.Srivatsavai@Sun.COM     const char *propname, const char *propval)
561*10491SRishi.Srivatsavai@Sun.COM {
562*10491SRishi.Srivatsavai@Sun.COM 	scf_transaction_entry_t *entry;
563*10491SRishi.Srivatsavai@Sun.COM 	scf_value_t *value = NULL;
564*10491SRishi.Srivatsavai@Sun.COM 
565*10491SRishi.Srivatsavai@Sun.COM 	if ((entry = scf_entry_create(handle)) == NULL)
566*10491SRishi.Srivatsavai@Sun.COM 		return (B_FALSE);
567*10491SRishi.Srivatsavai@Sun.COM 
568*10491SRishi.Srivatsavai@Sun.COM 	if ((value = scf_value_create(handle)) == NULL)
569*10491SRishi.Srivatsavai@Sun.COM 		goto out;
570*10491SRishi.Srivatsavai@Sun.COM 	if (scf_transaction_property_new(tran, entry, propname,
571*10491SRishi.Srivatsavai@Sun.COM 	    SCF_TYPE_ASTRING) != 0 &&
572*10491SRishi.Srivatsavai@Sun.COM 	    scf_transaction_property_change(tran, entry, propname,
573*10491SRishi.Srivatsavai@Sun.COM 	    SCF_TYPE_ASTRING) != 0)
574*10491SRishi.Srivatsavai@Sun.COM 		goto out;
575*10491SRishi.Srivatsavai@Sun.COM 	if (scf_value_set_astring(value, propval) != 0)
576*10491SRishi.Srivatsavai@Sun.COM 		goto out;
577*10491SRishi.Srivatsavai@Sun.COM 	if (scf_entry_add_value(entry, value) == 0)
578*10491SRishi.Srivatsavai@Sun.COM 		return (B_TRUE);
579*10491SRishi.Srivatsavai@Sun.COM 
580*10491SRishi.Srivatsavai@Sun.COM out:
581*10491SRishi.Srivatsavai@Sun.COM 	if (value != NULL)
582*10491SRishi.Srivatsavai@Sun.COM 		scf_value_destroy(value);
583*10491SRishi.Srivatsavai@Sun.COM 
584*10491SRishi.Srivatsavai@Sun.COM 	scf_entry_destroy_children(entry);
585*10491SRishi.Srivatsavai@Sun.COM 	scf_entry_destroy(entry);
586*10491SRishi.Srivatsavai@Sun.COM 
587*10491SRishi.Srivatsavai@Sun.COM 	return (B_FALSE);
588*10491SRishi.Srivatsavai@Sun.COM }
589*10491SRishi.Srivatsavai@Sun.COM 
590*10491SRishi.Srivatsavai@Sun.COM static boolean_t
591*10491SRishi.Srivatsavai@Sun.COM set_fmri_property(scf_handle_t *handle, scf_transaction_t *tran,
592*10491SRishi.Srivatsavai@Sun.COM     const char *propname, const char *propval)
593*10491SRishi.Srivatsavai@Sun.COM {
594*10491SRishi.Srivatsavai@Sun.COM 	scf_transaction_entry_t *entry;
595*10491SRishi.Srivatsavai@Sun.COM 	scf_value_t *value = NULL;
596*10491SRishi.Srivatsavai@Sun.COM 
597*10491SRishi.Srivatsavai@Sun.COM 	if ((entry = scf_entry_create(handle)) == NULL)
598*10491SRishi.Srivatsavai@Sun.COM 		return (B_FALSE);
599*10491SRishi.Srivatsavai@Sun.COM 
600*10491SRishi.Srivatsavai@Sun.COM 	if ((value = scf_value_create(handle)) == NULL)
601*10491SRishi.Srivatsavai@Sun.COM 		goto out;
602*10491SRishi.Srivatsavai@Sun.COM 	if (scf_transaction_property_new(tran, entry, propname,
603*10491SRishi.Srivatsavai@Sun.COM 	    SCF_TYPE_FMRI) != 0 &&
604*10491SRishi.Srivatsavai@Sun.COM 	    scf_transaction_property_change(tran, entry, propname,
605*10491SRishi.Srivatsavai@Sun.COM 	    SCF_TYPE_FMRI) != 0)
606*10491SRishi.Srivatsavai@Sun.COM 		goto out;
607*10491SRishi.Srivatsavai@Sun.COM 	if (scf_value_set_from_string(value, SCF_TYPE_FMRI, propval) != 0)
608*10491SRishi.Srivatsavai@Sun.COM 		goto out;
609*10491SRishi.Srivatsavai@Sun.COM 	if (scf_entry_add_value(entry, value) == 0)
610*10491SRishi.Srivatsavai@Sun.COM 		return (B_TRUE);
611*10491SRishi.Srivatsavai@Sun.COM 
612*10491SRishi.Srivatsavai@Sun.COM out:
613*10491SRishi.Srivatsavai@Sun.COM 	if (value != NULL)
614*10491SRishi.Srivatsavai@Sun.COM 		scf_value_destroy(value);
615*10491SRishi.Srivatsavai@Sun.COM 
616*10491SRishi.Srivatsavai@Sun.COM 	scf_entry_destroy_children(entry);
617*10491SRishi.Srivatsavai@Sun.COM 	scf_entry_destroy(entry);
618*10491SRishi.Srivatsavai@Sun.COM 
619*10491SRishi.Srivatsavai@Sun.COM 	return (B_FALSE);
620*10491SRishi.Srivatsavai@Sun.COM }
621*10491SRishi.Srivatsavai@Sun.COM 
622*10491SRishi.Srivatsavai@Sun.COM static dladm_status_t
623*10491SRishi.Srivatsavai@Sun.COM dladm_bridge_persist_conf(dladm_handle_t handle, const char *link,
624*10491SRishi.Srivatsavai@Sun.COM     datalink_id_t linkid)
625*10491SRishi.Srivatsavai@Sun.COM {
626*10491SRishi.Srivatsavai@Sun.COM 	dladm_conf_t conf = DLADM_INVALID_CONF;
627*10491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
628*10491SRishi.Srivatsavai@Sun.COM 
629*10491SRishi.Srivatsavai@Sun.COM 	status = dladm_create_conf(handle, link, linkid, DATALINK_CLASS_BRIDGE,
630*10491SRishi.Srivatsavai@Sun.COM 	    DL_ETHER, &conf);
631*10491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_OK) {
632*10491SRishi.Srivatsavai@Sun.COM 		/*
633*10491SRishi.Srivatsavai@Sun.COM 		 * Create the datalink entry for the bridge.  Note that all of
634*10491SRishi.Srivatsavai@Sun.COM 		 * the real configuration information is in SMF.
635*10491SRishi.Srivatsavai@Sun.COM 		 */
636*10491SRishi.Srivatsavai@Sun.COM 		status = dladm_write_conf(handle, conf);
637*10491SRishi.Srivatsavai@Sun.COM 		dladm_destroy_conf(handle, conf);
638*10491SRishi.Srivatsavai@Sun.COM 	}
639*10491SRishi.Srivatsavai@Sun.COM 	return (status);
640*10491SRishi.Srivatsavai@Sun.COM }
641*10491SRishi.Srivatsavai@Sun.COM 
642*10491SRishi.Srivatsavai@Sun.COM /* Convert bridge protection option string to dladm_bridge_prot_t */
643*10491SRishi.Srivatsavai@Sun.COM dladm_status_t
644*10491SRishi.Srivatsavai@Sun.COM dladm_bridge_str2prot(const char *str, dladm_bridge_prot_t *brprotp)
645*10491SRishi.Srivatsavai@Sun.COM {
646*10491SRishi.Srivatsavai@Sun.COM 	if (strcmp(str, "stp") == 0)
647*10491SRishi.Srivatsavai@Sun.COM 		*brprotp = DLADM_BRIDGE_PROT_STP;
648*10491SRishi.Srivatsavai@Sun.COM 	else if (strcmp(str, "trill") == 0)
649*10491SRishi.Srivatsavai@Sun.COM 		*brprotp = DLADM_BRIDGE_PROT_TRILL;
650*10491SRishi.Srivatsavai@Sun.COM 	else
651*10491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_BADARG);
652*10491SRishi.Srivatsavai@Sun.COM 	return (DLADM_STATUS_OK);
653*10491SRishi.Srivatsavai@Sun.COM }
654*10491SRishi.Srivatsavai@Sun.COM 
655*10491SRishi.Srivatsavai@Sun.COM /* Convert bridge protection option from dladm_bridge_prot_t to string */
656*10491SRishi.Srivatsavai@Sun.COM const char *
657*10491SRishi.Srivatsavai@Sun.COM dladm_bridge_prot2str(dladm_bridge_prot_t brprot)
658*10491SRishi.Srivatsavai@Sun.COM {
659*10491SRishi.Srivatsavai@Sun.COM 	switch (brprot) {
660*10491SRishi.Srivatsavai@Sun.COM 	case DLADM_BRIDGE_PROT_STP:
661*10491SRishi.Srivatsavai@Sun.COM 		return ("stp");
662*10491SRishi.Srivatsavai@Sun.COM 	case DLADM_BRIDGE_PROT_TRILL:
663*10491SRishi.Srivatsavai@Sun.COM 		return ("trill");
664*10491SRishi.Srivatsavai@Sun.COM 	default:
665*10491SRishi.Srivatsavai@Sun.COM 		return ("unknown");
666*10491SRishi.Srivatsavai@Sun.COM 	}
667*10491SRishi.Srivatsavai@Sun.COM }
668*10491SRishi.Srivatsavai@Sun.COM 
669*10491SRishi.Srivatsavai@Sun.COM static dladm_status_t
670*10491SRishi.Srivatsavai@Sun.COM enable_instance(const char *service_name, const char *instance)
671*10491SRishi.Srivatsavai@Sun.COM {
672*10491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
673*10491SRishi.Srivatsavai@Sun.COM 	char *fmri = alloc_fmri(service_name, instance);
674*10491SRishi.Srivatsavai@Sun.COM 
675*10491SRishi.Srivatsavai@Sun.COM 	if (fmri == NULL)
676*10491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_NOMEM);
677*10491SRishi.Srivatsavai@Sun.COM 	status = smf_enable_instance(fmri, 0) == 0 ?
678*10491SRishi.Srivatsavai@Sun.COM 	    DLADM_STATUS_OK : DLADM_STATUS_FAILED;
679*10491SRishi.Srivatsavai@Sun.COM 	free(fmri);
680*10491SRishi.Srivatsavai@Sun.COM 	return (status);
681*10491SRishi.Srivatsavai@Sun.COM }
682*10491SRishi.Srivatsavai@Sun.COM 
683*10491SRishi.Srivatsavai@Sun.COM /*
684*10491SRishi.Srivatsavai@Sun.COM  * Shut down a possibly-running service instance.  If this is a permanent
685*10491SRishi.Srivatsavai@Sun.COM  * change, then delete it from the system.
686*10491SRishi.Srivatsavai@Sun.COM  */
687*10491SRishi.Srivatsavai@Sun.COM static dladm_status_t
688*10491SRishi.Srivatsavai@Sun.COM shut_down_instance(const char *service_name, const char *instance,
689*10491SRishi.Srivatsavai@Sun.COM     uint32_t flags)
690*10491SRishi.Srivatsavai@Sun.COM {
691*10491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
692*10491SRishi.Srivatsavai@Sun.COM 	char *fmri = alloc_fmri(service_name, instance);
693*10491SRishi.Srivatsavai@Sun.COM 	char *state;
694*10491SRishi.Srivatsavai@Sun.COM 	scf_state_t sstate;
695*10491SRishi.Srivatsavai@Sun.COM 
696*10491SRishi.Srivatsavai@Sun.COM 	if (fmri == NULL)
697*10491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_NOMEM);
698*10491SRishi.Srivatsavai@Sun.COM 
699*10491SRishi.Srivatsavai@Sun.COM 	if (smf_disable_instance(fmri,
700*10491SRishi.Srivatsavai@Sun.COM 	    flags & DLADM_OPT_PERSIST ? 0 : SMF_TEMPORARY) == 0) {
701*10491SRishi.Srivatsavai@Sun.COM 		useconds_t usecs, umax;
702*10491SRishi.Srivatsavai@Sun.COM 
703*10491SRishi.Srivatsavai@Sun.COM 		/* If we can disable, then wait for it to happen. */
704*10491SRishi.Srivatsavai@Sun.COM 		umax = DEFAULT_TIMEOUT;
705*10491SRishi.Srivatsavai@Sun.COM 		for (usecs = INIT_WAIT_USECS; umax != 0; umax -= usecs) {
706*10491SRishi.Srivatsavai@Sun.COM 			state = smf_get_state(fmri);
707*10491SRishi.Srivatsavai@Sun.COM 			if (state != NULL &&
708*10491SRishi.Srivatsavai@Sun.COM 			    strcmp(state, SCF_STATE_STRING_DISABLED) == 0)
709*10491SRishi.Srivatsavai@Sun.COM 				break;
710*10491SRishi.Srivatsavai@Sun.COM 			free(state);
711*10491SRishi.Srivatsavai@Sun.COM 			usecs *= 2;
712*10491SRishi.Srivatsavai@Sun.COM 			if (usecs > umax)
713*10491SRishi.Srivatsavai@Sun.COM 				usecs = umax;
714*10491SRishi.Srivatsavai@Sun.COM 			(void) usleep(usecs);
715*10491SRishi.Srivatsavai@Sun.COM 		}
716*10491SRishi.Srivatsavai@Sun.COM 		if (umax == 0) {
717*10491SRishi.Srivatsavai@Sun.COM 			state = smf_get_state(fmri);
718*10491SRishi.Srivatsavai@Sun.COM 			if (state != NULL &&
719*10491SRishi.Srivatsavai@Sun.COM 			    strcmp(state, SCF_STATE_STRING_DISABLED) == 0)
720*10491SRishi.Srivatsavai@Sun.COM 				umax = 1;
721*10491SRishi.Srivatsavai@Sun.COM 		}
722*10491SRishi.Srivatsavai@Sun.COM 		free(state);
723*10491SRishi.Srivatsavai@Sun.COM 		status = umax != 0 ? DLADM_STATUS_OK : DLADM_STATUS_FAILED;
724*10491SRishi.Srivatsavai@Sun.COM 	} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
725*10491SRishi.Srivatsavai@Sun.COM 		free(fmri);
726*10491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_OK);
727*10491SRishi.Srivatsavai@Sun.COM 	} else {
728*10491SRishi.Srivatsavai@Sun.COM 		status = DLADM_STATUS_FAILED;
729*10491SRishi.Srivatsavai@Sun.COM 	}
730*10491SRishi.Srivatsavai@Sun.COM 
731*10491SRishi.Srivatsavai@Sun.COM 	free(fmri);
732*10491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_OK && (flags & DLADM_OPT_PERSIST) &&
733*10491SRishi.Srivatsavai@Sun.COM 	    bind_instance(service_name, instance, &sstate) == 0) {
734*10491SRishi.Srivatsavai@Sun.COM 		(void) scf_instance_delete(sstate.ss_inst);
735*10491SRishi.Srivatsavai@Sun.COM 		shut_down_scf(&sstate);
736*10491SRishi.Srivatsavai@Sun.COM 	}
737*10491SRishi.Srivatsavai@Sun.COM 
738*10491SRishi.Srivatsavai@Sun.COM 	return (status);
739*10491SRishi.Srivatsavai@Sun.COM }
740*10491SRishi.Srivatsavai@Sun.COM 
741*10491SRishi.Srivatsavai@Sun.COM static dladm_status_t
742*10491SRishi.Srivatsavai@Sun.COM disable_trill(const char *instance, uint32_t flags)
743*10491SRishi.Srivatsavai@Sun.COM {
744*10491SRishi.Srivatsavai@Sun.COM 	return (shut_down_instance(TRILL_SVC_NAME, instance, flags));
745*10491SRishi.Srivatsavai@Sun.COM }
746*10491SRishi.Srivatsavai@Sun.COM 
747*10491SRishi.Srivatsavai@Sun.COM /*
748*10491SRishi.Srivatsavai@Sun.COM  * To enable TRILL, we must create a new instance of the TRILL service, then
749*10491SRishi.Srivatsavai@Sun.COM  * add proper dependencies to it, and finally mark it as enabled.  The
750*10491SRishi.Srivatsavai@Sun.COM  * dependencies will keep it from going on-line until the bridge is running.
751*10491SRishi.Srivatsavai@Sun.COM  */
752*10491SRishi.Srivatsavai@Sun.COM static dladm_status_t
753*10491SRishi.Srivatsavai@Sun.COM enable_trill(const char *instance)
754*10491SRishi.Srivatsavai@Sun.COM {
755*10491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status = DLADM_STATUS_FAILED;
756*10491SRishi.Srivatsavai@Sun.COM 	char *fmri = NULL;
757*10491SRishi.Srivatsavai@Sun.COM 	scf_state_t sstate;
758*10491SRishi.Srivatsavai@Sun.COM 	scf_transaction_t *tran = NULL;
759*10491SRishi.Srivatsavai@Sun.COM 	boolean_t new_instance = B_FALSE;
760*10491SRishi.Srivatsavai@Sun.COM 	boolean_t new_pg = B_FALSE;
761*10491SRishi.Srivatsavai@Sun.COM 	int rv;
762*10491SRishi.Srivatsavai@Sun.COM 
763*10491SRishi.Srivatsavai@Sun.COM 	/*
764*10491SRishi.Srivatsavai@Sun.COM 	 * This check is here in case the user has installed and then removed
765*10491SRishi.Srivatsavai@Sun.COM 	 * the package.  SMF should remove the manifest, but currently does
766*10491SRishi.Srivatsavai@Sun.COM 	 * not.
767*10491SRishi.Srivatsavai@Sun.COM 	 */
768*10491SRishi.Srivatsavai@Sun.COM 	if (access("/usr/sbin/trilld", F_OK) != 0)
769*10491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_OPTMISSING);
770*10491SRishi.Srivatsavai@Sun.COM 
771*10491SRishi.Srivatsavai@Sun.COM 	if ((status = exact_instance(TRILL_SVC_NAME, &sstate)) !=
772*10491SRishi.Srivatsavai@Sun.COM 	    DLADM_STATUS_OK)
773*10491SRishi.Srivatsavai@Sun.COM 		goto out;
774*10491SRishi.Srivatsavai@Sun.COM 
775*10491SRishi.Srivatsavai@Sun.COM 	status = DLADM_STATUS_FAILED;
776*10491SRishi.Srivatsavai@Sun.COM 	if (scf_service_get_instance(sstate.ss_svc, instance, sstate.ss_inst) !=
777*10491SRishi.Srivatsavai@Sun.COM 	    0) {
778*10491SRishi.Srivatsavai@Sun.COM 		if (scf_service_add_instance(sstate.ss_svc, instance,
779*10491SRishi.Srivatsavai@Sun.COM 		    sstate.ss_inst) != 0)
780*10491SRishi.Srivatsavai@Sun.COM 			goto out;
781*10491SRishi.Srivatsavai@Sun.COM 		new_instance = B_TRUE;
782*10491SRishi.Srivatsavai@Sun.COM 	}
783*10491SRishi.Srivatsavai@Sun.COM 
784*10491SRishi.Srivatsavai@Sun.COM 	if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL)
785*10491SRishi.Srivatsavai@Sun.COM 		goto out;
786*10491SRishi.Srivatsavai@Sun.COM 
787*10491SRishi.Srivatsavai@Sun.COM 	if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL)
788*10491SRishi.Srivatsavai@Sun.COM 		goto out;
789*10491SRishi.Srivatsavai@Sun.COM 
790*10491SRishi.Srivatsavai@Sun.COM 	if (scf_instance_get_pg(sstate.ss_inst, "bridging",
791*10491SRishi.Srivatsavai@Sun.COM 	    sstate.ss_pg) == 0) {
792*10491SRishi.Srivatsavai@Sun.COM 		status = DLADM_STATUS_OK;
793*10491SRishi.Srivatsavai@Sun.COM 		goto out;
794*10491SRishi.Srivatsavai@Sun.COM 	}
795*10491SRishi.Srivatsavai@Sun.COM 
796*10491SRishi.Srivatsavai@Sun.COM 	if ((fmri = alloc_fmri(BRIDGE_SVC_NAME, instance)) == NULL)
797*10491SRishi.Srivatsavai@Sun.COM 		goto out;
798*10491SRishi.Srivatsavai@Sun.COM 
799*10491SRishi.Srivatsavai@Sun.COM 	if (scf_instance_add_pg(sstate.ss_inst, "bridging",
800*10491SRishi.Srivatsavai@Sun.COM 	    SCF_GROUP_DEPENDENCY, 0, sstate.ss_pg) != 0)
801*10491SRishi.Srivatsavai@Sun.COM 		goto out;
802*10491SRishi.Srivatsavai@Sun.COM 
803*10491SRishi.Srivatsavai@Sun.COM 	new_pg = B_TRUE;
804*10491SRishi.Srivatsavai@Sun.COM 	do {
805*10491SRishi.Srivatsavai@Sun.COM 		if (scf_transaction_start(tran, sstate.ss_pg) != 0)
806*10491SRishi.Srivatsavai@Sun.COM 			goto out;
807*10491SRishi.Srivatsavai@Sun.COM 
808*10491SRishi.Srivatsavai@Sun.COM 		if (!set_string_property(sstate.ss_handle, tran,
809*10491SRishi.Srivatsavai@Sun.COM 		    SCF_PROPERTY_GROUPING, SCF_DEP_REQUIRE_ALL))
810*10491SRishi.Srivatsavai@Sun.COM 			goto out;
811*10491SRishi.Srivatsavai@Sun.COM 		if (!set_string_property(sstate.ss_handle, tran,
812*10491SRishi.Srivatsavai@Sun.COM 		    SCF_PROPERTY_RESTART_ON, SCF_DEP_RESET_ON_RESTART))
813*10491SRishi.Srivatsavai@Sun.COM 			goto out;
814*10491SRishi.Srivatsavai@Sun.COM 		if (!set_string_property(sstate.ss_handle, tran,
815*10491SRishi.Srivatsavai@Sun.COM 		    SCF_PROPERTY_TYPE, "service"))
816*10491SRishi.Srivatsavai@Sun.COM 			goto out;
817*10491SRishi.Srivatsavai@Sun.COM 		if (!set_fmri_property(sstate.ss_handle, tran,
818*10491SRishi.Srivatsavai@Sun.COM 		    SCF_PROPERTY_ENTITIES, fmri))
819*10491SRishi.Srivatsavai@Sun.COM 			goto out;
820*10491SRishi.Srivatsavai@Sun.COM 
821*10491SRishi.Srivatsavai@Sun.COM 		rv = scf_transaction_commit(tran);
822*10491SRishi.Srivatsavai@Sun.COM 		scf_transaction_reset(tran);
823*10491SRishi.Srivatsavai@Sun.COM 		if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1)
824*10491SRishi.Srivatsavai@Sun.COM 			goto out;
825*10491SRishi.Srivatsavai@Sun.COM 	} while (rv == 0);
826*10491SRishi.Srivatsavai@Sun.COM 	if (rv != 1)
827*10491SRishi.Srivatsavai@Sun.COM 		goto out;
828*10491SRishi.Srivatsavai@Sun.COM 
829*10491SRishi.Srivatsavai@Sun.COM 	status = DLADM_STATUS_OK;
830*10491SRishi.Srivatsavai@Sun.COM 
831*10491SRishi.Srivatsavai@Sun.COM out:
832*10491SRishi.Srivatsavai@Sun.COM 	free(fmri);
833*10491SRishi.Srivatsavai@Sun.COM 	if (tran != NULL) {
834*10491SRishi.Srivatsavai@Sun.COM 		scf_transaction_destroy_children(tran);
835*10491SRishi.Srivatsavai@Sun.COM 		scf_transaction_destroy(tran);
836*10491SRishi.Srivatsavai@Sun.COM 	}
837*10491SRishi.Srivatsavai@Sun.COM 
838*10491SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK && new_pg)
839*10491SRishi.Srivatsavai@Sun.COM 		(void) scf_pg_delete(sstate.ss_pg);
840*10491SRishi.Srivatsavai@Sun.COM 
841*10491SRishi.Srivatsavai@Sun.COM 	drop_composed(&sstate);
842*10491SRishi.Srivatsavai@Sun.COM 
843*10491SRishi.Srivatsavai@Sun.COM 	/*
844*10491SRishi.Srivatsavai@Sun.COM 	 * If we created an instance and then failed, then remove the instance
845*10491SRishi.Srivatsavai@Sun.COM 	 * from the system.
846*10491SRishi.Srivatsavai@Sun.COM 	 */
847*10491SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK && new_instance)
848*10491SRishi.Srivatsavai@Sun.COM 		(void) scf_instance_delete(sstate.ss_inst);
849*10491SRishi.Srivatsavai@Sun.COM 
850*10491SRishi.Srivatsavai@Sun.COM 	shut_down_scf(&sstate);
851*10491SRishi.Srivatsavai@Sun.COM 
852*10491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_OK)
853*10491SRishi.Srivatsavai@Sun.COM 		status = enable_instance(TRILL_SVC_NAME, instance);
854*10491SRishi.Srivatsavai@Sun.COM 
855*10491SRishi.Srivatsavai@Sun.COM 	return (status);
856*10491SRishi.Srivatsavai@Sun.COM }
857*10491SRishi.Srivatsavai@Sun.COM 
858*10491SRishi.Srivatsavai@Sun.COM /*
859*10491SRishi.Srivatsavai@Sun.COM  * Create a new bridge or modify an existing one.  Update the SMF configuration
860*10491SRishi.Srivatsavai@Sun.COM  * and add links.
861*10491SRishi.Srivatsavai@Sun.COM  *
862*10491SRishi.Srivatsavai@Sun.COM  * Input timer values are in IEEE scaled (* 256) format.
863*10491SRishi.Srivatsavai@Sun.COM  */
864*10491SRishi.Srivatsavai@Sun.COM dladm_status_t
865*10491SRishi.Srivatsavai@Sun.COM dladm_bridge_configure(dladm_handle_t handle, const char *name,
866*10491SRishi.Srivatsavai@Sun.COM     const UID_STP_CFG_T *cfg, dladm_bridge_prot_t brprot, uint32_t flags)
867*10491SRishi.Srivatsavai@Sun.COM {
868*10491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
869*10491SRishi.Srivatsavai@Sun.COM 	scf_state_t sstate;
870*10491SRishi.Srivatsavai@Sun.COM 	scf_transaction_t *tran = NULL;
871*10491SRishi.Srivatsavai@Sun.COM 	boolean_t new_instance = B_FALSE;
872*10491SRishi.Srivatsavai@Sun.COM 	boolean_t new_pg = B_FALSE;
873*10491SRishi.Srivatsavai@Sun.COM 	datalink_id_t linkid = DATALINK_INVALID_LINKID;
874*10491SRishi.Srivatsavai@Sun.COM 	char linkname[MAXLINKNAMELEN];
875*10491SRishi.Srivatsavai@Sun.COM 	int rv;
876*10491SRishi.Srivatsavai@Sun.COM 
877*10491SRishi.Srivatsavai@Sun.COM 	if (!dladm_valid_bridgename(name))
878*10491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_FAILED);
879*10491SRishi.Srivatsavai@Sun.COM 
880*10491SRishi.Srivatsavai@Sun.COM 	if (flags & DLADM_OPT_CREATE) {
881*10491SRishi.Srivatsavai@Sun.COM 		/*
882*10491SRishi.Srivatsavai@Sun.COM 		 * This check is here in case the user has installed and then
883*10491SRishi.Srivatsavai@Sun.COM 		 * removed the package.  SMF should remove the manifest, but
884*10491SRishi.Srivatsavai@Sun.COM 		 * currently does not.
885*10491SRishi.Srivatsavai@Sun.COM 		 */
886*10491SRishi.Srivatsavai@Sun.COM 		if (access("/usr/lib/bridged", F_OK) != 0)
887*10491SRishi.Srivatsavai@Sun.COM 			return (DLADM_STATUS_OPTMISSING);
888*10491SRishi.Srivatsavai@Sun.COM 
889*10491SRishi.Srivatsavai@Sun.COM 		(void) snprintf(linkname, sizeof (linkname), "%s0", name);
890*10491SRishi.Srivatsavai@Sun.COM 		status = dladm_create_datalink_id(handle, linkname,
891*10491SRishi.Srivatsavai@Sun.COM 		    DATALINK_CLASS_BRIDGE, DL_ETHER,
892*10491SRishi.Srivatsavai@Sun.COM 		    flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST), &linkid);
893*10491SRishi.Srivatsavai@Sun.COM 		if (status != DLADM_STATUS_OK)
894*10491SRishi.Srivatsavai@Sun.COM 			return (status);
895*10491SRishi.Srivatsavai@Sun.COM 
896*10491SRishi.Srivatsavai@Sun.COM 		if ((flags & DLADM_OPT_PERSIST) &&
897*10491SRishi.Srivatsavai@Sun.COM 		    (status = dladm_bridge_persist_conf(handle, linkname,
898*10491SRishi.Srivatsavai@Sun.COM 		    linkid) != DLADM_STATUS_OK))
899*10491SRishi.Srivatsavai@Sun.COM 			goto dladm_fail;
900*10491SRishi.Srivatsavai@Sun.COM 	}
901*10491SRishi.Srivatsavai@Sun.COM 
902*10491SRishi.Srivatsavai@Sun.COM 	if (brprot == DLADM_BRIDGE_PROT_TRILL)
903*10491SRishi.Srivatsavai@Sun.COM 		status = enable_trill(name);
904*10491SRishi.Srivatsavai@Sun.COM 	else
905*10491SRishi.Srivatsavai@Sun.COM 		status = disable_trill(name, flags);
906*10491SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK)
907*10491SRishi.Srivatsavai@Sun.COM 		goto dladm_fail;
908*10491SRishi.Srivatsavai@Sun.COM 
909*10491SRishi.Srivatsavai@Sun.COM 	if ((status = exact_instance(BRIDGE_SVC_NAME, &sstate)) !=
910*10491SRishi.Srivatsavai@Sun.COM 	    DLADM_STATUS_OK)
911*10491SRishi.Srivatsavai@Sun.COM 		goto out;
912*10491SRishi.Srivatsavai@Sun.COM 
913*10491SRishi.Srivatsavai@Sun.COM 	/* set up for a series of scf calls */
914*10491SRishi.Srivatsavai@Sun.COM 	status = DLADM_STATUS_FAILED;
915*10491SRishi.Srivatsavai@Sun.COM 
916*10491SRishi.Srivatsavai@Sun.COM 	if (scf_service_get_instance(sstate.ss_svc, name, sstate.ss_inst) ==
917*10491SRishi.Srivatsavai@Sun.COM 	    0) {
918*10491SRishi.Srivatsavai@Sun.COM 		if (flags & DLADM_OPT_CREATE) {
919*10491SRishi.Srivatsavai@Sun.COM 			status = DLADM_STATUS_EXIST;
920*10491SRishi.Srivatsavai@Sun.COM 			goto out;
921*10491SRishi.Srivatsavai@Sun.COM 		}
922*10491SRishi.Srivatsavai@Sun.COM 	} else {
923*10491SRishi.Srivatsavai@Sun.COM 		if (!(flags & DLADM_OPT_CREATE)) {
924*10491SRishi.Srivatsavai@Sun.COM 			status = DLADM_STATUS_NOTFOUND;
925*10491SRishi.Srivatsavai@Sun.COM 			goto out;
926*10491SRishi.Srivatsavai@Sun.COM 		}
927*10491SRishi.Srivatsavai@Sun.COM 		if (scf_service_add_instance(sstate.ss_svc, name,
928*10491SRishi.Srivatsavai@Sun.COM 		    sstate.ss_inst) != 0)
929*10491SRishi.Srivatsavai@Sun.COM 			goto out;
930*10491SRishi.Srivatsavai@Sun.COM 		new_instance = B_TRUE;
931*10491SRishi.Srivatsavai@Sun.COM 	}
932*10491SRishi.Srivatsavai@Sun.COM 
933*10491SRishi.Srivatsavai@Sun.COM 	if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL)
934*10491SRishi.Srivatsavai@Sun.COM 		goto out;
935*10491SRishi.Srivatsavai@Sun.COM 
936*10491SRishi.Srivatsavai@Sun.COM 	if (cfg->field_mask & BR_CFG_ALL) {
937*10491SRishi.Srivatsavai@Sun.COM 		if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL)
938*10491SRishi.Srivatsavai@Sun.COM 			goto out;
939*10491SRishi.Srivatsavai@Sun.COM 		if (scf_instance_add_pg(sstate.ss_inst, "config",
940*10491SRishi.Srivatsavai@Sun.COM 		    SCF_GROUP_APPLICATION, 0, sstate.ss_pg) == 0) {
941*10491SRishi.Srivatsavai@Sun.COM 			new_pg = B_TRUE;
942*10491SRishi.Srivatsavai@Sun.COM 		} else if (scf_instance_get_pg(sstate.ss_inst, "config",
943*10491SRishi.Srivatsavai@Sun.COM 		    sstate.ss_pg) != 0) {
944*10491SRishi.Srivatsavai@Sun.COM 			goto out;
945*10491SRishi.Srivatsavai@Sun.COM 		}
946*10491SRishi.Srivatsavai@Sun.COM 		do {
947*10491SRishi.Srivatsavai@Sun.COM 			if (scf_transaction_start(tran, sstate.ss_pg) != 0)
948*10491SRishi.Srivatsavai@Sun.COM 				goto out;
949*10491SRishi.Srivatsavai@Sun.COM 
950*10491SRishi.Srivatsavai@Sun.COM 			if ((cfg->field_mask & BR_CFG_PRIO) &&
951*10491SRishi.Srivatsavai@Sun.COM 			    !set_count_property(sstate.ss_handle, tran,
952*10491SRishi.Srivatsavai@Sun.COM 			    "priority", cfg->bridge_priority))
953*10491SRishi.Srivatsavai@Sun.COM 				goto out;
954*10491SRishi.Srivatsavai@Sun.COM 			if ((cfg->field_mask & BR_CFG_AGE) &&
955*10491SRishi.Srivatsavai@Sun.COM 			    !set_count_property(sstate.ss_handle, tran,
956*10491SRishi.Srivatsavai@Sun.COM 			    "max-age", cfg->max_age * IEEE_TIMER_SCALE))
957*10491SRishi.Srivatsavai@Sun.COM 				goto out;
958*10491SRishi.Srivatsavai@Sun.COM 			if ((cfg->field_mask & BR_CFG_HELLO) &&
959*10491SRishi.Srivatsavai@Sun.COM 			    !set_count_property(sstate.ss_handle, tran,
960*10491SRishi.Srivatsavai@Sun.COM 			    "hello-time", cfg->hello_time * IEEE_TIMER_SCALE))
961*10491SRishi.Srivatsavai@Sun.COM 				goto out;
962*10491SRishi.Srivatsavai@Sun.COM 			if ((cfg->field_mask & BR_CFG_DELAY) &&
963*10491SRishi.Srivatsavai@Sun.COM 			    !set_count_property(sstate.ss_handle, tran,
964*10491SRishi.Srivatsavai@Sun.COM 			    "forward-delay",
965*10491SRishi.Srivatsavai@Sun.COM 			    cfg->forward_delay * IEEE_TIMER_SCALE))
966*10491SRishi.Srivatsavai@Sun.COM 				goto out;
967*10491SRishi.Srivatsavai@Sun.COM 			if ((cfg->field_mask & BR_CFG_FORCE_VER) &&
968*10491SRishi.Srivatsavai@Sun.COM 			    !set_count_property(sstate.ss_handle, tran,
969*10491SRishi.Srivatsavai@Sun.COM 			    "force-protocol", cfg->force_version))
970*10491SRishi.Srivatsavai@Sun.COM 				goto out;
971*10491SRishi.Srivatsavai@Sun.COM 
972*10491SRishi.Srivatsavai@Sun.COM 			rv = scf_transaction_commit(tran);
973*10491SRishi.Srivatsavai@Sun.COM 			scf_transaction_reset(tran);
974*10491SRishi.Srivatsavai@Sun.COM 			if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1)
975*10491SRishi.Srivatsavai@Sun.COM 				goto out;
976*10491SRishi.Srivatsavai@Sun.COM 		} while (rv == 0);
977*10491SRishi.Srivatsavai@Sun.COM 		if (rv != 1)
978*10491SRishi.Srivatsavai@Sun.COM 			goto out;
979*10491SRishi.Srivatsavai@Sun.COM 	}
980*10491SRishi.Srivatsavai@Sun.COM 
981*10491SRishi.Srivatsavai@Sun.COM 	/*
982*10491SRishi.Srivatsavai@Sun.COM 	 * If we're modifying an existing and running bridge, then tell the
983*10491SRishi.Srivatsavai@Sun.COM 	 * daemon to update the requested values.
984*10491SRishi.Srivatsavai@Sun.COM 	 */
985*10491SRishi.Srivatsavai@Sun.COM 	if ((flags & DLADM_OPT_ACTIVE) && !(flags & DLADM_OPT_CREATE))
986*10491SRishi.Srivatsavai@Sun.COM 		status = bridge_refresh(name);
987*10491SRishi.Srivatsavai@Sun.COM 	else
988*10491SRishi.Srivatsavai@Sun.COM 		status = DLADM_STATUS_OK;
989*10491SRishi.Srivatsavai@Sun.COM 
990*10491SRishi.Srivatsavai@Sun.COM out:
991*10491SRishi.Srivatsavai@Sun.COM 	if (tran != NULL) {
992*10491SRishi.Srivatsavai@Sun.COM 		scf_transaction_destroy_children(tran);
993*10491SRishi.Srivatsavai@Sun.COM 		scf_transaction_destroy(tran);
994*10491SRishi.Srivatsavai@Sun.COM 	}
995*10491SRishi.Srivatsavai@Sun.COM 
996*10491SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK && new_pg)
997*10491SRishi.Srivatsavai@Sun.COM 		(void) scf_pg_delete(sstate.ss_pg);
998*10491SRishi.Srivatsavai@Sun.COM 
999*10491SRishi.Srivatsavai@Sun.COM 	drop_composed(&sstate);
1000*10491SRishi.Srivatsavai@Sun.COM 
1001*10491SRishi.Srivatsavai@Sun.COM 	/*
1002*10491SRishi.Srivatsavai@Sun.COM 	 * If we created an instance and then failed, then remove the instance
1003*10491SRishi.Srivatsavai@Sun.COM 	 * from the system.
1004*10491SRishi.Srivatsavai@Sun.COM 	 */
1005*10491SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK && new_instance)
1006*10491SRishi.Srivatsavai@Sun.COM 		(void) scf_instance_delete(sstate.ss_inst);
1007*10491SRishi.Srivatsavai@Sun.COM 
1008*10491SRishi.Srivatsavai@Sun.COM 	shut_down_scf(&sstate);
1009*10491SRishi.Srivatsavai@Sun.COM 
1010*10491SRishi.Srivatsavai@Sun.COM 	/*
1011*10491SRishi.Srivatsavai@Sun.COM 	 * Remove the bridge linkid if we've allocated one in this function but
1012*10491SRishi.Srivatsavai@Sun.COM 	 * we've failed to set up the SMF properties.
1013*10491SRishi.Srivatsavai@Sun.COM 	 */
1014*10491SRishi.Srivatsavai@Sun.COM dladm_fail:
1015*10491SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK && linkid != DATALINK_INVALID_LINKID) {
1016*10491SRishi.Srivatsavai@Sun.COM 		(void) dladm_remove_conf(handle, linkid);
1017*10491SRishi.Srivatsavai@Sun.COM 		(void) dladm_destroy_datalink_id(handle, linkid, flags);
1018*10491SRishi.Srivatsavai@Sun.COM 	}
1019*10491SRishi.Srivatsavai@Sun.COM 
1020*10491SRishi.Srivatsavai@Sun.COM 	return (status);
1021*10491SRishi.Srivatsavai@Sun.COM }
1022*10491SRishi.Srivatsavai@Sun.COM 
1023*10491SRishi.Srivatsavai@Sun.COM /*
1024*10491SRishi.Srivatsavai@Sun.COM  * Enable a newly-created bridge in SMF by creating "general/enabled" and
1025*10491SRishi.Srivatsavai@Sun.COM  * deleting any "general_ovr/enabled" (used for temporary services).
1026*10491SRishi.Srivatsavai@Sun.COM  */
1027*10491SRishi.Srivatsavai@Sun.COM dladm_status_t
1028*10491SRishi.Srivatsavai@Sun.COM dladm_bridge_enable(const char *name)
1029*10491SRishi.Srivatsavai@Sun.COM {
1030*10491SRishi.Srivatsavai@Sun.COM 	return (enable_instance(BRIDGE_SVC_NAME, name));
1031*10491SRishi.Srivatsavai@Sun.COM }
1032*10491SRishi.Srivatsavai@Sun.COM 
1033*10491SRishi.Srivatsavai@Sun.COM /*
1034*10491SRishi.Srivatsavai@Sun.COM  * Set a link as a member of a bridge, or remove bridge membership.  If the
1035*10491SRishi.Srivatsavai@Sun.COM  * DLADM_OPT_CREATE flag is set, then we assume that the daemon isn't running.
1036*10491SRishi.Srivatsavai@Sun.COM  * In all other cases, we must tell the daemon to add or delete the link in
1037*10491SRishi.Srivatsavai@Sun.COM  * order to stay in sync.
1038*10491SRishi.Srivatsavai@Sun.COM  */
1039*10491SRishi.Srivatsavai@Sun.COM dladm_status_t
1040*10491SRishi.Srivatsavai@Sun.COM dladm_bridge_setlink(dladm_handle_t handle, datalink_id_t linkid,
1041*10491SRishi.Srivatsavai@Sun.COM     const char *bridge)
1042*10491SRishi.Srivatsavai@Sun.COM {
1043*10491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
1044*10491SRishi.Srivatsavai@Sun.COM 	dladm_conf_t conf;
1045*10491SRishi.Srivatsavai@Sun.COM 	char oldbridge[MAXLINKNAMELEN];
1046*10491SRishi.Srivatsavai@Sun.COM 	boolean_t has_oldbridge;
1047*10491SRishi.Srivatsavai@Sun.COM 	boolean_t changed = B_FALSE;
1048*10491SRishi.Srivatsavai@Sun.COM 
1049*10491SRishi.Srivatsavai@Sun.COM 	if (*bridge != '\0' && !dladm_valid_bridgename(bridge))
1050*10491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_FAILED);
1051*10491SRishi.Srivatsavai@Sun.COM 
1052*10491SRishi.Srivatsavai@Sun.COM 	if ((status = dladm_read_conf(handle, linkid, &conf)) !=
1053*10491SRishi.Srivatsavai@Sun.COM 	    DLADM_STATUS_OK)
1054*10491SRishi.Srivatsavai@Sun.COM 		return (status);
1055*10491SRishi.Srivatsavai@Sun.COM 
1056*10491SRishi.Srivatsavai@Sun.COM 	has_oldbridge = B_FALSE;
1057*10491SRishi.Srivatsavai@Sun.COM 	status = dladm_get_conf_field(handle, conf, FBRIDGE, oldbridge,
1058*10491SRishi.Srivatsavai@Sun.COM 	    sizeof (oldbridge));
1059*10491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_OK) {
1060*10491SRishi.Srivatsavai@Sun.COM 		/*
1061*10491SRishi.Srivatsavai@Sun.COM 		 * Don't allow a link to be reassigned directly from one bridge
1062*10491SRishi.Srivatsavai@Sun.COM 		 * to another.  It must be removed first.
1063*10491SRishi.Srivatsavai@Sun.COM 		 */
1064*10491SRishi.Srivatsavai@Sun.COM 		if (*oldbridge != '\0' && *bridge != '\0') {
1065*10491SRishi.Srivatsavai@Sun.COM 			status = DLADM_STATUS_EXIST;
1066*10491SRishi.Srivatsavai@Sun.COM 			goto out;
1067*10491SRishi.Srivatsavai@Sun.COM 		}
1068*10491SRishi.Srivatsavai@Sun.COM 		has_oldbridge = B_TRUE;
1069*10491SRishi.Srivatsavai@Sun.COM 	} else if (status != DLADM_STATUS_NOTFOUND) {
1070*10491SRishi.Srivatsavai@Sun.COM 		goto out;
1071*10491SRishi.Srivatsavai@Sun.COM 	}
1072*10491SRishi.Srivatsavai@Sun.COM 
1073*10491SRishi.Srivatsavai@Sun.COM 	if (*bridge != '\0') {
1074*10491SRishi.Srivatsavai@Sun.COM 		status = dladm_set_conf_field(handle, conf, FBRIDGE,
1075*10491SRishi.Srivatsavai@Sun.COM 		    DLADM_TYPE_STR, bridge);
1076*10491SRishi.Srivatsavai@Sun.COM 		changed = B_TRUE;
1077*10491SRishi.Srivatsavai@Sun.COM 	} else if (has_oldbridge) {
1078*10491SRishi.Srivatsavai@Sun.COM 		status = dladm_unset_conf_field(handle, conf, FBRIDGE);
1079*10491SRishi.Srivatsavai@Sun.COM 		changed = B_TRUE;
1080*10491SRishi.Srivatsavai@Sun.COM 	} else {
1081*10491SRishi.Srivatsavai@Sun.COM 		status = DLADM_STATUS_OK;
1082*10491SRishi.Srivatsavai@Sun.COM 		goto out;
1083*10491SRishi.Srivatsavai@Sun.COM 	}
1084*10491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_OK)
1085*10491SRishi.Srivatsavai@Sun.COM 		status = dladm_write_conf(handle, conf);
1086*10491SRishi.Srivatsavai@Sun.COM 
1087*10491SRishi.Srivatsavai@Sun.COM out:
1088*10491SRishi.Srivatsavai@Sun.COM 	dladm_destroy_conf(handle, conf);
1089*10491SRishi.Srivatsavai@Sun.COM 	if (changed && status == DLADM_STATUS_OK) {
1090*10491SRishi.Srivatsavai@Sun.COM 		if (bridge[0] == '\0')
1091*10491SRishi.Srivatsavai@Sun.COM 			bridge = oldbridge;
1092*10491SRishi.Srivatsavai@Sun.COM 		status = bridge_refresh(bridge);
1093*10491SRishi.Srivatsavai@Sun.COM 	}
1094*10491SRishi.Srivatsavai@Sun.COM 	return (status);
1095*10491SRishi.Srivatsavai@Sun.COM }
1096*10491SRishi.Srivatsavai@Sun.COM 
1097*10491SRishi.Srivatsavai@Sun.COM /*
1098*10491SRishi.Srivatsavai@Sun.COM  * Get the name of the bridge of which the given linkid is a member.
1099*10491SRishi.Srivatsavai@Sun.COM  */
1100*10491SRishi.Srivatsavai@Sun.COM dladm_status_t
1101*10491SRishi.Srivatsavai@Sun.COM dladm_bridge_getlink(dladm_handle_t handle, datalink_id_t linkid, char *bridge,
1102*10491SRishi.Srivatsavai@Sun.COM     size_t bridgelen)
1103*10491SRishi.Srivatsavai@Sun.COM {
1104*10491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
1105*10491SRishi.Srivatsavai@Sun.COM 	dladm_conf_t conf;
1106*10491SRishi.Srivatsavai@Sun.COM 
1107*10491SRishi.Srivatsavai@Sun.COM 	if ((status = dladm_read_conf(handle, linkid, &conf)) !=
1108*10491SRishi.Srivatsavai@Sun.COM 	    DLADM_STATUS_OK)
1109*10491SRishi.Srivatsavai@Sun.COM 		return (status);
1110*10491SRishi.Srivatsavai@Sun.COM 
1111*10491SRishi.Srivatsavai@Sun.COM 	*bridge = '\0';
1112*10491SRishi.Srivatsavai@Sun.COM 	status = dladm_get_conf_field(handle, conf, FBRIDGE, bridge, bridgelen);
1113*10491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_OK && *bridge == '\0')
1114*10491SRishi.Srivatsavai@Sun.COM 		status = DLADM_STATUS_NOTFOUND;
1115*10491SRishi.Srivatsavai@Sun.COM 
1116*10491SRishi.Srivatsavai@Sun.COM 	dladm_destroy_conf(handle, conf);
1117*10491SRishi.Srivatsavai@Sun.COM 	return (status);
1118*10491SRishi.Srivatsavai@Sun.COM }
1119*10491SRishi.Srivatsavai@Sun.COM 
1120*10491SRishi.Srivatsavai@Sun.COM dladm_status_t
1121*10491SRishi.Srivatsavai@Sun.COM dladm_bridge_refresh(dladm_handle_t handle, datalink_id_t linkid)
1122*10491SRishi.Srivatsavai@Sun.COM {
1123*10491SRishi.Srivatsavai@Sun.COM 	char bridge[MAXLINKNAMELEN];
1124*10491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
1125*10491SRishi.Srivatsavai@Sun.COM 
1126*10491SRishi.Srivatsavai@Sun.COM 	status = dladm_bridge_getlink(handle, linkid, bridge, sizeof (bridge));
1127*10491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_NOTFOUND)
1128*10491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_OK);
1129*10491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_OK)
1130*10491SRishi.Srivatsavai@Sun.COM 		status = bridge_refresh(bridge);
1131*10491SRishi.Srivatsavai@Sun.COM 	return (status);
1132*10491SRishi.Srivatsavai@Sun.COM }
1133*10491SRishi.Srivatsavai@Sun.COM 
1134*10491SRishi.Srivatsavai@Sun.COM typedef struct bridge_held_arg_s {
1135*10491SRishi.Srivatsavai@Sun.COM 	const char	*bha_bridge;
1136*10491SRishi.Srivatsavai@Sun.COM 	boolean_t	bha_isheld;
1137*10491SRishi.Srivatsavai@Sun.COM } bridge_held_arg_t;
1138*10491SRishi.Srivatsavai@Sun.COM 
1139*10491SRishi.Srivatsavai@Sun.COM static int
1140*10491SRishi.Srivatsavai@Sun.COM i_dladm_bridge_is_held(dladm_handle_t handle, datalink_id_t linkid, void *arg)
1141*10491SRishi.Srivatsavai@Sun.COM {
1142*10491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status = DLADM_STATUS_FAILED;
1143*10491SRishi.Srivatsavai@Sun.COM 	dladm_conf_t conf;
1144*10491SRishi.Srivatsavai@Sun.COM 	char bridge[MAXLINKNAMELEN];
1145*10491SRishi.Srivatsavai@Sun.COM 	bridge_held_arg_t	*bha = arg;
1146*10491SRishi.Srivatsavai@Sun.COM 
1147*10491SRishi.Srivatsavai@Sun.COM 	if ((status = dladm_read_conf(handle, linkid, &conf)) !=
1148*10491SRishi.Srivatsavai@Sun.COM 	    DLADM_STATUS_OK)
1149*10491SRishi.Srivatsavai@Sun.COM 		return (DLADM_WALK_CONTINUE);
1150*10491SRishi.Srivatsavai@Sun.COM 	status = dladm_get_conf_field(handle, conf, FBRIDGE, bridge,
1151*10491SRishi.Srivatsavai@Sun.COM 	    sizeof (bridge));
1152*10491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_OK && strcmp(bha->bha_bridge, bridge) == 0) {
1153*10491SRishi.Srivatsavai@Sun.COM 		bha->bha_isheld = B_TRUE;
1154*10491SRishi.Srivatsavai@Sun.COM 		dladm_destroy_conf(handle, conf);
1155*10491SRishi.Srivatsavai@Sun.COM 		return (DLADM_WALK_TERMINATE);
1156*10491SRishi.Srivatsavai@Sun.COM 	} else {
1157*10491SRishi.Srivatsavai@Sun.COM 		dladm_destroy_conf(handle, conf);
1158*10491SRishi.Srivatsavai@Sun.COM 		return (DLADM_WALK_CONTINUE);
1159*10491SRishi.Srivatsavai@Sun.COM 	}
1160*10491SRishi.Srivatsavai@Sun.COM }
1161*10491SRishi.Srivatsavai@Sun.COM 
1162*10491SRishi.Srivatsavai@Sun.COM /*
1163*10491SRishi.Srivatsavai@Sun.COM  * Delete a previously created bridge.
1164*10491SRishi.Srivatsavai@Sun.COM  */
1165*10491SRishi.Srivatsavai@Sun.COM dladm_status_t
1166*10491SRishi.Srivatsavai@Sun.COM dladm_bridge_delete(dladm_handle_t handle, const char *bridge, uint32_t flags)
1167*10491SRishi.Srivatsavai@Sun.COM {
1168*10491SRishi.Srivatsavai@Sun.COM 	datalink_id_t linkid;
1169*10491SRishi.Srivatsavai@Sun.COM 	datalink_class_t class;
1170*10491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
1171*10491SRishi.Srivatsavai@Sun.COM 	char linkname[MAXLINKNAMELEN];
1172*10491SRishi.Srivatsavai@Sun.COM 
1173*10491SRishi.Srivatsavai@Sun.COM 	if (!dladm_valid_bridgename(bridge))
1174*10491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_LINKINVAL);
1175*10491SRishi.Srivatsavai@Sun.COM 
1176*10491SRishi.Srivatsavai@Sun.COM 	/* Get the datalink ID for this bridge */
1177*10491SRishi.Srivatsavai@Sun.COM 	(void) snprintf(linkname, sizeof (linkname), "%s0", bridge);
1178*10491SRishi.Srivatsavai@Sun.COM 	if (dladm_name2info(handle, linkname, &linkid, NULL, NULL, NULL) !=
1179*10491SRishi.Srivatsavai@Sun.COM 	    DLADM_STATUS_OK)
1180*10491SRishi.Srivatsavai@Sun.COM 		linkid = DATALINK_INVALID_LINKID;
1181*10491SRishi.Srivatsavai@Sun.COM 	else if (dladm_datalink_id2info(handle, linkid, NULL, &class, NULL,
1182*10491SRishi.Srivatsavai@Sun.COM 	    NULL, 0) != DLADM_STATUS_OK)
1183*10491SRishi.Srivatsavai@Sun.COM 		linkid = DATALINK_INVALID_LINKID;
1184*10491SRishi.Srivatsavai@Sun.COM 	else if (class != DATALINK_CLASS_BRIDGE)
1185*10491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_BADARG);
1186*10491SRishi.Srivatsavai@Sun.COM 
1187*10491SRishi.Srivatsavai@Sun.COM 	if ((flags & DLADM_OPT_ACTIVE) && linkid == DATALINK_INVALID_LINKID)
1188*10491SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_BADARG);
1189*10491SRishi.Srivatsavai@Sun.COM 
1190*10491SRishi.Srivatsavai@Sun.COM 	if (flags & DLADM_OPT_PERSIST) {
1191*10491SRishi.Srivatsavai@Sun.COM 		bridge_held_arg_t arg;
1192*10491SRishi.Srivatsavai@Sun.COM 
1193*10491SRishi.Srivatsavai@Sun.COM 		arg.bha_bridge = bridge;
1194*10491SRishi.Srivatsavai@Sun.COM 		arg.bha_isheld = B_FALSE;
1195*10491SRishi.Srivatsavai@Sun.COM 
1196*10491SRishi.Srivatsavai@Sun.COM 		/*
1197*10491SRishi.Srivatsavai@Sun.COM 		 * See whether there are any persistent links using this
1198*10491SRishi.Srivatsavai@Sun.COM 		 * bridge.  If so, we fail the operation.
1199*10491SRishi.Srivatsavai@Sun.COM 		 */
1200*10491SRishi.Srivatsavai@Sun.COM 		(void) dladm_walk_datalink_id(i_dladm_bridge_is_held, handle,
1201*10491SRishi.Srivatsavai@Sun.COM 		    &arg, DATALINK_CLASS_PHYS | DATALINK_CLASS_AGGR |
1202*10491SRishi.Srivatsavai@Sun.COM 		    DATALINK_CLASS_ETHERSTUB | DATALINK_CLASS_SIMNET,
1203*10491SRishi.Srivatsavai@Sun.COM 		    DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
1204*10491SRishi.Srivatsavai@Sun.COM 		if (arg.bha_isheld)
1205*10491SRishi.Srivatsavai@Sun.COM 			return (DLADM_STATUS_LINKBUSY);
1206*10491SRishi.Srivatsavai@Sun.COM 	}
1207*10491SRishi.Srivatsavai@Sun.COM 
1208*10491SRishi.Srivatsavai@Sun.COM 	if ((status = disable_trill(bridge, flags)) != DLADM_STATUS_OK)
1209*10491SRishi.Srivatsavai@Sun.COM 		goto out;
1210*10491SRishi.Srivatsavai@Sun.COM 
1211*10491SRishi.Srivatsavai@Sun.COM 	/* Disable or remove the SMF instance */
1212*10491SRishi.Srivatsavai@Sun.COM 	status = shut_down_instance(BRIDGE_SVC_NAME, bridge, flags);
1213*10491SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK)
1214*10491SRishi.Srivatsavai@Sun.COM 		goto out;
1215*10491SRishi.Srivatsavai@Sun.COM 
1216*10491SRishi.Srivatsavai@Sun.COM 	if (flags & DLADM_OPT_ACTIVE) {
1217*10491SRishi.Srivatsavai@Sun.COM 		/*
1218*10491SRishi.Srivatsavai@Sun.COM 		 * Delete ACTIVE linkprop now that daemon is gone.
1219*10491SRishi.Srivatsavai@Sun.COM 		 */
1220*10491SRishi.Srivatsavai@Sun.COM 		(void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0,
1221*10491SRishi.Srivatsavai@Sun.COM 		    DLADM_OPT_ACTIVE);
1222*10491SRishi.Srivatsavai@Sun.COM 		(void) dladm_destroy_datalink_id(handle, linkid,
1223*10491SRishi.Srivatsavai@Sun.COM 		    DLADM_OPT_ACTIVE);
1224*10491SRishi.Srivatsavai@Sun.COM 	}
1225*10491SRishi.Srivatsavai@Sun.COM 
1226*10491SRishi.Srivatsavai@Sun.COM 	if (flags & DLADM_OPT_PERSIST) {
1227*10491SRishi.Srivatsavai@Sun.COM 		(void) dladm_remove_conf(handle, linkid);
1228*10491SRishi.Srivatsavai@Sun.COM 		(void) dladm_destroy_datalink_id(handle, linkid,
1229*10491SRishi.Srivatsavai@Sun.COM 		    DLADM_OPT_PERSIST);
1230*10491SRishi.Srivatsavai@Sun.COM 	}
1231*10491SRishi.Srivatsavai@Sun.COM 
1232*10491SRishi.Srivatsavai@Sun.COM out:
1233*10491SRishi.Srivatsavai@Sun.COM 
1234*10491SRishi.Srivatsavai@Sun.COM 	return (status);
1235*10491SRishi.Srivatsavai@Sun.COM }
1236*10491SRishi.Srivatsavai@Sun.COM 
1237*10491SRishi.Srivatsavai@Sun.COM /* Check if given name is valid for bridges */
1238*10491SRishi.Srivatsavai@Sun.COM boolean_t
1239*10491SRishi.Srivatsavai@Sun.COM dladm_valid_bridgename(const char *bridge)
1240*10491SRishi.Srivatsavai@Sun.COM {
1241*10491SRishi.Srivatsavai@Sun.COM 	size_t		len = strnlen(bridge, MAXLINKNAMELEN);
1242*10491SRishi.Srivatsavai@Sun.COM 	const char	*cp;
1243*10491SRishi.Srivatsavai@Sun.COM 
1244*10491SRishi.Srivatsavai@Sun.COM 	if (len == MAXLINKNAMELEN)
1245*10491SRishi.Srivatsavai@Sun.COM 		return (B_FALSE);
1246*10491SRishi.Srivatsavai@Sun.COM 
1247*10491SRishi.Srivatsavai@Sun.COM 	/*
1248*10491SRishi.Srivatsavai@Sun.COM 	 * The bridge name cannot start or end with a digit.
1249*10491SRishi.Srivatsavai@Sun.COM 	 */
1250*10491SRishi.Srivatsavai@Sun.COM 	if (isdigit(bridge[0]) || isdigit(bridge[len - 1]))
1251*10491SRishi.Srivatsavai@Sun.COM 		return (B_FALSE);
1252*10491SRishi.Srivatsavai@Sun.COM 
1253*10491SRishi.Srivatsavai@Sun.COM 	/*
1254*10491SRishi.Srivatsavai@Sun.COM 	 * The legal characters within a bridge name are:
1255*10491SRishi.Srivatsavai@Sun.COM 	 * alphanumeric (a-z,  A-Z,  0-9), and the underscore ('_').
1256*10491SRishi.Srivatsavai@Sun.COM 	 */
1257*10491SRishi.Srivatsavai@Sun.COM 	for (cp = bridge; *cp != '\0'; cp++) {
1258*10491SRishi.Srivatsavai@Sun.COM 		if (!isalnum(*cp) && *cp != '_')
1259*10491SRishi.Srivatsavai@Sun.COM 			return (B_FALSE);
1260*10491SRishi.Srivatsavai@Sun.COM 	}
1261*10491SRishi.Srivatsavai@Sun.COM 
1262*10491SRishi.Srivatsavai@Sun.COM 	return (B_TRUE);
1263*10491SRishi.Srivatsavai@Sun.COM }
1264*10491SRishi.Srivatsavai@Sun.COM 
1265*10491SRishi.Srivatsavai@Sun.COM /*
1266*10491SRishi.Srivatsavai@Sun.COM  * Convert a bridge-related observability node name back into the name of the
1267*10491SRishi.Srivatsavai@Sun.COM  * bridge.  Returns B_FALSE without making changes if the input name is not in
1268*10491SRishi.Srivatsavai@Sun.COM  * a legal format.
1269*10491SRishi.Srivatsavai@Sun.COM  */
1270*10491SRishi.Srivatsavai@Sun.COM boolean_t
1271*10491SRishi.Srivatsavai@Sun.COM dladm_observe_to_bridge(char *link)
1272*10491SRishi.Srivatsavai@Sun.COM {
1273*10491SRishi.Srivatsavai@Sun.COM 	int llen;
1274*10491SRishi.Srivatsavai@Sun.COM 
1275*10491SRishi.Srivatsavai@Sun.COM 	llen = strnlen(link, MAXLINKNAMELEN);
1276*10491SRishi.Srivatsavai@Sun.COM 	if (llen < 2 || link[llen - 1] != '0' || isdigit(link[llen - 2]))
1277*10491SRishi.Srivatsavai@Sun.COM 		return (B_FALSE);
1278*10491SRishi.Srivatsavai@Sun.COM 	link[llen - 1] = '\0';
1279*10491SRishi.Srivatsavai@Sun.COM 	return (B_TRUE);
1280*10491SRishi.Srivatsavai@Sun.COM }
1281*10491SRishi.Srivatsavai@Sun.COM 
1282*10491SRishi.Srivatsavai@Sun.COM /*
1283*10491SRishi.Srivatsavai@Sun.COM  * Get bridge property values from the running daemon and return them in a
1284*10491SRishi.Srivatsavai@Sun.COM  * common structure.
1285*10491SRishi.Srivatsavai@Sun.COM  */
1286*10491SRishi.Srivatsavai@Sun.COM dladm_status_t
1287*10491SRishi.Srivatsavai@Sun.COM dladm_bridge_run_properties(const char *instname, UID_STP_CFG_T *smcfg,
1288*10491SRishi.Srivatsavai@Sun.COM     dladm_bridge_prot_t *brprotp)
1289*10491SRishi.Srivatsavai@Sun.COM {
1290*10491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
1291*10491SRishi.Srivatsavai@Sun.COM 	bridge_door_cfg_t bdcf;
1292*10491SRishi.Srivatsavai@Sun.COM 	bridge_door_cfg_t *bdcfp = &bdcf;
1293*10491SRishi.Srivatsavai@Sun.COM 	size_t buflen = sizeof (bdcf);
1294*10491SRishi.Srivatsavai@Sun.COM 
1295*10491SRishi.Srivatsavai@Sun.COM 	status = bridge_door_call(instname, bdcBridgeGetConfig,
1296*10491SRishi.Srivatsavai@Sun.COM 	    DATALINK_INVALID_LINKID, (void **)&bdcfp, 0, &buflen, B_FALSE);
1297*10491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_OK) {
1298*10491SRishi.Srivatsavai@Sun.COM 		*smcfg = bdcfp->bdcf_cfg;
1299*10491SRishi.Srivatsavai@Sun.COM 		*brprotp = bdcfp->bdcf_prot;
1300*10491SRishi.Srivatsavai@Sun.COM 	} else {
1301*10491SRishi.Srivatsavai@Sun.COM 		smcfg->field_mask = 0;
1302*10491SRishi.Srivatsavai@Sun.COM 		*brprotp = DLADM_BRIDGE_PROT_STP;
1303*10491SRishi.Srivatsavai@Sun.COM 	}
1304*10491SRishi.Srivatsavai@Sun.COM 	return (status);
1305*10491SRishi.Srivatsavai@Sun.COM }
1306*10491SRishi.Srivatsavai@Sun.COM 
1307*10491SRishi.Srivatsavai@Sun.COM /*
1308*10491SRishi.Srivatsavai@Sun.COM  * Get bridge state from the running daemon and return in structure borrowed
1309*10491SRishi.Srivatsavai@Sun.COM  * from librstp.
1310*10491SRishi.Srivatsavai@Sun.COM  */
1311*10491SRishi.Srivatsavai@Sun.COM dladm_status_t
1312*10491SRishi.Srivatsavai@Sun.COM dladm_bridge_state(const char *instname, UID_STP_STATE_T *statep)
1313*10491SRishi.Srivatsavai@Sun.COM {
1314*10491SRishi.Srivatsavai@Sun.COM 	size_t buflen = sizeof (*statep);
1315*10491SRishi.Srivatsavai@Sun.COM 
1316*10491SRishi.Srivatsavai@Sun.COM 	return (bridge_door_call(instname, bdcBridgeGetState,
1317*10491SRishi.Srivatsavai@Sun.COM 	    DATALINK_INVALID_LINKID, (void **)&statep, 0, &buflen, B_FALSE));
1318*10491SRishi.Srivatsavai@Sun.COM }
1319*10491SRishi.Srivatsavai@Sun.COM 
1320*10491SRishi.Srivatsavai@Sun.COM /* Returns list of ports (datalink_id_t values) assigned to a bridge instance */
1321*10491SRishi.Srivatsavai@Sun.COM datalink_id_t *
1322*10491SRishi.Srivatsavai@Sun.COM dladm_bridge_get_portlist(const char *instname, uint_t *nports)
1323*10491SRishi.Srivatsavai@Sun.COM {
1324*10491SRishi.Srivatsavai@Sun.COM 	size_t buflen = sizeof (int) + MAXPORTS * sizeof (datalink_id_t);
1325*10491SRishi.Srivatsavai@Sun.COM 	int *rbuf;
1326*10491SRishi.Srivatsavai@Sun.COM 
1327*10491SRishi.Srivatsavai@Sun.COM 	if ((rbuf = malloc(buflen)) == NULL)
1328*10491SRishi.Srivatsavai@Sun.COM 		return (NULL);
1329*10491SRishi.Srivatsavai@Sun.COM 	if (bridge_door_call(instname, bdcBridgeGetPorts,
1330*10491SRishi.Srivatsavai@Sun.COM 	    DATALINK_INVALID_LINKID, (void **)&rbuf, 0, &buflen, B_TRUE) !=
1331*10491SRishi.Srivatsavai@Sun.COM 	    DLADM_STATUS_OK) {
1332*10491SRishi.Srivatsavai@Sun.COM 		free(rbuf);
1333*10491SRishi.Srivatsavai@Sun.COM 		return (NULL);
1334*10491SRishi.Srivatsavai@Sun.COM 	} else {
1335*10491SRishi.Srivatsavai@Sun.COM 		/*
1336*10491SRishi.Srivatsavai@Sun.COM 		 * Returns an array of datalink_id_t values for all the ports
1337*10491SRishi.Srivatsavai@Sun.COM 		 * part of the bridge instance. First entry in the array is the
1338*10491SRishi.Srivatsavai@Sun.COM 		 * number of ports.
1339*10491SRishi.Srivatsavai@Sun.COM 		 */
1340*10491SRishi.Srivatsavai@Sun.COM 		*nports = *rbuf;
1341*10491SRishi.Srivatsavai@Sun.COM 		return ((datalink_id_t *)(rbuf + 1));
1342*10491SRishi.Srivatsavai@Sun.COM 	}
1343*10491SRishi.Srivatsavai@Sun.COM }
1344*10491SRishi.Srivatsavai@Sun.COM 
1345*10491SRishi.Srivatsavai@Sun.COM void
1346*10491SRishi.Srivatsavai@Sun.COM dladm_bridge_free_portlist(datalink_id_t *dlp)
1347*10491SRishi.Srivatsavai@Sun.COM {
1348*10491SRishi.Srivatsavai@Sun.COM 	free((int *)dlp - 1);
1349*10491SRishi.Srivatsavai@Sun.COM }
1350*10491SRishi.Srivatsavai@Sun.COM 
1351*10491SRishi.Srivatsavai@Sun.COM /* Retrieve Bridge port configuration values */
1352*10491SRishi.Srivatsavai@Sun.COM dladm_status_t
1353*10491SRishi.Srivatsavai@Sun.COM dladm_bridge_get_port_cfg(dladm_handle_t handle, datalink_id_t linkid,
1354*10491SRishi.Srivatsavai@Sun.COM     int field, int *valuep)
1355*10491SRishi.Srivatsavai@Sun.COM {
1356*10491SRishi.Srivatsavai@Sun.COM 	UID_STP_PORT_CFG_T portcfg;
1357*10491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
1358*10491SRishi.Srivatsavai@Sun.COM 
1359*10491SRishi.Srivatsavai@Sun.COM 	status = port_door_call(handle, linkid, bdcPortGetConfig, &portcfg,
1360*10491SRishi.Srivatsavai@Sun.COM 	    0, sizeof (portcfg));
1361*10491SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK)
1362*10491SRishi.Srivatsavai@Sun.COM 		return (status);
1363*10491SRishi.Srivatsavai@Sun.COM 
1364*10491SRishi.Srivatsavai@Sun.COM 	switch (field) {
1365*10491SRishi.Srivatsavai@Sun.COM 	case PT_CFG_COST:
1366*10491SRishi.Srivatsavai@Sun.COM 		*valuep = portcfg.admin_port_path_cost;
1367*10491SRishi.Srivatsavai@Sun.COM 		break;
1368*10491SRishi.Srivatsavai@Sun.COM 	case PT_CFG_PRIO:
1369*10491SRishi.Srivatsavai@Sun.COM 		*valuep = portcfg.port_priority;
1370*10491SRishi.Srivatsavai@Sun.COM 		break;
1371*10491SRishi.Srivatsavai@Sun.COM 	case PT_CFG_P2P:
1372*10491SRishi.Srivatsavai@Sun.COM 		*valuep = portcfg.admin_point2point;
1373*10491SRishi.Srivatsavai@Sun.COM 		break;
1374*10491SRishi.Srivatsavai@Sun.COM 	case PT_CFG_EDGE:
1375*10491SRishi.Srivatsavai@Sun.COM 		*valuep = portcfg.admin_edge;
1376*10491SRishi.Srivatsavai@Sun.COM 		break;
1377*10491SRishi.Srivatsavai@Sun.COM 	case PT_CFG_NON_STP:
1378*10491SRishi.Srivatsavai@Sun.COM 		*valuep = !portcfg.admin_non_stp;
1379*10491SRishi.Srivatsavai@Sun.COM 		break;
1380*10491SRishi.Srivatsavai@Sun.COM 	case PT_CFG_MCHECK:
1381*10491SRishi.Srivatsavai@Sun.COM 		*valuep = (portcfg.field_mask & PT_CFG_MCHECK) ? 1 : 0;
1382*10491SRishi.Srivatsavai@Sun.COM 		break;
1383*10491SRishi.Srivatsavai@Sun.COM 	}
1384*10491SRishi.Srivatsavai@Sun.COM 	return (status);
1385*10491SRishi.Srivatsavai@Sun.COM }
1386*10491SRishi.Srivatsavai@Sun.COM 
1387*10491SRishi.Srivatsavai@Sun.COM /* Retreive Bridge port status (disabled, bad SDU etc.) */
1388*10491SRishi.Srivatsavai@Sun.COM dladm_status_t
1389*10491SRishi.Srivatsavai@Sun.COM dladm_bridge_link_state(dladm_handle_t handle, datalink_id_t linkid,
1390*10491SRishi.Srivatsavai@Sun.COM     UID_STP_PORT_STATE_T *spsp)
1391*10491SRishi.Srivatsavai@Sun.COM {
1392*10491SRishi.Srivatsavai@Sun.COM 	return (port_door_call(handle, linkid, bdcPortGetState, spsp, 0,
1393*10491SRishi.Srivatsavai@Sun.COM 	    sizeof (*spsp)));
1394*10491SRishi.Srivatsavai@Sun.COM }
1395*10491SRishi.Srivatsavai@Sun.COM 
1396*10491SRishi.Srivatsavai@Sun.COM /* Retrieve Bridge forwarding status of the given link */
1397*10491SRishi.Srivatsavai@Sun.COM dladm_status_t
1398*10491SRishi.Srivatsavai@Sun.COM dladm_bridge_get_forwarding(dladm_handle_t handle, datalink_id_t linkid,
1399*10491SRishi.Srivatsavai@Sun.COM     uint_t *valuep)
1400*10491SRishi.Srivatsavai@Sun.COM {
1401*10491SRishi.Srivatsavai@Sun.COM 	int twoints[2];
1402*10491SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
1403*10491SRishi.Srivatsavai@Sun.COM 
1404*10491SRishi.Srivatsavai@Sun.COM 	status = port_door_call(handle, linkid, bdcPortGetForwarding, twoints,
1405*10491SRishi.Srivatsavai@Sun.COM 	    0, sizeof (twoints));
1406*10491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_OK)
1407*10491SRishi.Srivatsavai@Sun.COM 		*valuep = twoints[0];
1408*10491SRishi.Srivatsavai@Sun.COM 	return (status);
1409*10491SRishi.Srivatsavai@Sun.COM }
1410*10491SRishi.Srivatsavai@Sun.COM 
1411*10491SRishi.Srivatsavai@Sun.COM /* Retrieve Bridge forwarding table entries */
1412*10491SRishi.Srivatsavai@Sun.COM bridge_listfwd_t *
1413*10491SRishi.Srivatsavai@Sun.COM dladm_bridge_get_fwdtable(dladm_handle_t handle, const char *bridge,
1414*10491SRishi.Srivatsavai@Sun.COM     uint_t *nfwd)
1415*10491SRishi.Srivatsavai@Sun.COM {
1416*10491SRishi.Srivatsavai@Sun.COM 	bridge_listfwd_t *blf = NULL, *newblf, blfread;
1417*10491SRishi.Srivatsavai@Sun.COM 	uint_t nblf = 0, maxblf = 0;
1418*10491SRishi.Srivatsavai@Sun.COM 	static uint8_t zero_addr[ETHERADDRL];
1419*10491SRishi.Srivatsavai@Sun.COM 	int rc;
1420*10491SRishi.Srivatsavai@Sun.COM 
1421*10491SRishi.Srivatsavai@Sun.COM 	(void) memset(&blfread, 0, sizeof (blfread));
1422*10491SRishi.Srivatsavai@Sun.COM 	(void) snprintf(blfread.blf_name, sizeof (blfread.blf_name),
1423*10491SRishi.Srivatsavai@Sun.COM 	    "%s0", bridge);
1424*10491SRishi.Srivatsavai@Sun.COM 	for (;;) {
1425*10491SRishi.Srivatsavai@Sun.COM 		if (nblf >= maxblf) {
1426*10491SRishi.Srivatsavai@Sun.COM 			maxblf = maxblf == 0 ? 64 : (maxblf << 1);
1427*10491SRishi.Srivatsavai@Sun.COM 			newblf = realloc(blf, maxblf * sizeof (*blf));
1428*10491SRishi.Srivatsavai@Sun.COM 			if (newblf == NULL) {
1429*10491SRishi.Srivatsavai@Sun.COM 				free(blf);
1430*10491SRishi.Srivatsavai@Sun.COM 				blf = NULL;
1431*10491SRishi.Srivatsavai@Sun.COM 				break;
1432*10491SRishi.Srivatsavai@Sun.COM 			}
1433*10491SRishi.Srivatsavai@Sun.COM 			blf = newblf;
1434*10491SRishi.Srivatsavai@Sun.COM 		}
1435*10491SRishi.Srivatsavai@Sun.COM 		rc = ioctl(dladm_dld_fd(handle), BRIDGE_IOC_LISTFWD, &blfread);
1436*10491SRishi.Srivatsavai@Sun.COM 		if (rc != 0) {
1437*10491SRishi.Srivatsavai@Sun.COM 			free(blf);
1438*10491SRishi.Srivatsavai@Sun.COM 			blf = NULL;
1439*10491SRishi.Srivatsavai@Sun.COM 			break;
1440*10491SRishi.Srivatsavai@Sun.COM 		}
1441*10491SRishi.Srivatsavai@Sun.COM 		if (memcmp(blfread.blf_dest, zero_addr, ETHERADDRL) == 0)
1442*10491SRishi.Srivatsavai@Sun.COM 			break;
1443*10491SRishi.Srivatsavai@Sun.COM 		blf[nblf++] = blfread;
1444*10491SRishi.Srivatsavai@Sun.COM 	}
1445*10491SRishi.Srivatsavai@Sun.COM 	if (blf != NULL)
1446*10491SRishi.Srivatsavai@Sun.COM 		*nfwd = nblf;
1447*10491SRishi.Srivatsavai@Sun.COM 	return (blf);
1448*10491SRishi.Srivatsavai@Sun.COM }
1449*10491SRishi.Srivatsavai@Sun.COM 
1450*10491SRishi.Srivatsavai@Sun.COM void
1451*10491SRishi.Srivatsavai@Sun.COM dladm_bridge_free_fwdtable(bridge_listfwd_t *blf)
1452*10491SRishi.Srivatsavai@Sun.COM {
1453*10491SRishi.Srivatsavai@Sun.COM 	free(blf);
1454*10491SRishi.Srivatsavai@Sun.COM }
1455*10491SRishi.Srivatsavai@Sun.COM 
1456*10491SRishi.Srivatsavai@Sun.COM /* Retrieve list of TRILL nicknames from the TRILL module */
1457*10491SRishi.Srivatsavai@Sun.COM trill_listnick_t *
1458*10491SRishi.Srivatsavai@Sun.COM dladm_bridge_get_trillnick(const char *bridge, uint_t *nnick)
1459*10491SRishi.Srivatsavai@Sun.COM {
1460*10491SRishi.Srivatsavai@Sun.COM 	int fd;
1461*10491SRishi.Srivatsavai@Sun.COM 	char brcopy[MAXLINKNAMELEN];
1462*10491SRishi.Srivatsavai@Sun.COM 	trill_listnick_t *tln = NULL, *newtln, tlnread;
1463*10491SRishi.Srivatsavai@Sun.COM 	uint_t ntln = 0, maxtln = 0;
1464*10491SRishi.Srivatsavai@Sun.COM 
1465*10491SRishi.Srivatsavai@Sun.COM 	if ((fd = socket(PF_TRILL, SOCK_DGRAM, 0)) == -1)
1466*10491SRishi.Srivatsavai@Sun.COM 		return (NULL);
1467*10491SRishi.Srivatsavai@Sun.COM 	(void) strlcpy(brcopy, bridge, sizeof (brcopy));
1468*10491SRishi.Srivatsavai@Sun.COM 	if (ioctl(fd, TRILL_GETBRIDGE, &brcopy) < 0) {
1469*10491SRishi.Srivatsavai@Sun.COM 		(void) close(fd);
1470*10491SRishi.Srivatsavai@Sun.COM 		return (NULL);
1471*10491SRishi.Srivatsavai@Sun.COM 	}
1472*10491SRishi.Srivatsavai@Sun.COM 	(void) memset(&tlnread, 0, sizeof (tlnread));
1473*10491SRishi.Srivatsavai@Sun.COM 	for (;;) {
1474*10491SRishi.Srivatsavai@Sun.COM 		if (ntln >= maxtln) {
1475*10491SRishi.Srivatsavai@Sun.COM 			maxtln = maxtln == 0 ? 64 : (maxtln << 1);
1476*10491SRishi.Srivatsavai@Sun.COM 			newtln = realloc(tln, maxtln * sizeof (*tln));
1477*10491SRishi.Srivatsavai@Sun.COM 			if (newtln == NULL) {
1478*10491SRishi.Srivatsavai@Sun.COM 				free(tln);
1479*10491SRishi.Srivatsavai@Sun.COM 				tln = NULL;
1480*10491SRishi.Srivatsavai@Sun.COM 				break;
1481*10491SRishi.Srivatsavai@Sun.COM 			}
1482*10491SRishi.Srivatsavai@Sun.COM 			tln = newtln;
1483*10491SRishi.Srivatsavai@Sun.COM 		}
1484*10491SRishi.Srivatsavai@Sun.COM 		if (ioctl(fd, TRILL_LISTNICK, &tlnread) == -1) {
1485*10491SRishi.Srivatsavai@Sun.COM 			free(tln);
1486*10491SRishi.Srivatsavai@Sun.COM 			tln = NULL;
1487*10491SRishi.Srivatsavai@Sun.COM 			break;
1488*10491SRishi.Srivatsavai@Sun.COM 		}
1489*10491SRishi.Srivatsavai@Sun.COM 		if (tlnread.tln_nick == 0)
1490*10491SRishi.Srivatsavai@Sun.COM 			break;
1491*10491SRishi.Srivatsavai@Sun.COM 		tln[ntln++] = tlnread;
1492*10491SRishi.Srivatsavai@Sun.COM 	}
1493*10491SRishi.Srivatsavai@Sun.COM 	(void) close(fd);
1494*10491SRishi.Srivatsavai@Sun.COM 	if (tln != NULL)
1495*10491SRishi.Srivatsavai@Sun.COM 		*nnick = ntln;
1496*10491SRishi.Srivatsavai@Sun.COM 	return (tln);
1497*10491SRishi.Srivatsavai@Sun.COM }
1498*10491SRishi.Srivatsavai@Sun.COM 
1499*10491SRishi.Srivatsavai@Sun.COM void
1500*10491SRishi.Srivatsavai@Sun.COM dladm_bridge_free_trillnick(trill_listnick_t *tln)
1501*10491SRishi.Srivatsavai@Sun.COM {
1502*10491SRishi.Srivatsavai@Sun.COM 	free(tln);
1503*10491SRishi.Srivatsavai@Sun.COM }
1504*10491SRishi.Srivatsavai@Sun.COM 
1505*10491SRishi.Srivatsavai@Sun.COM /* Retrieve any stored TRILL nickname from TRILL SMF service */
1506*10491SRishi.Srivatsavai@Sun.COM uint16_t
1507*10491SRishi.Srivatsavai@Sun.COM dladm_bridge_get_nick(const char *bridge)
1508*10491SRishi.Srivatsavai@Sun.COM {
1509*10491SRishi.Srivatsavai@Sun.COM 	scf_state_t sstate;
1510*10491SRishi.Srivatsavai@Sun.COM 	uint64_t value;
1511*10491SRishi.Srivatsavai@Sun.COM 	uint16_t nickname = RBRIDGE_NICKNAME_NONE;
1512*10491SRishi.Srivatsavai@Sun.COM 
1513*10491SRishi.Srivatsavai@Sun.COM 	if (bind_instance(TRILL_SVC_NAME, bridge, &sstate) != 0)
1514*10491SRishi.Srivatsavai@Sun.COM 		return (nickname);
1515*10491SRishi.Srivatsavai@Sun.COM 
1516*10491SRishi.Srivatsavai@Sun.COM 	if (get_composed_properties("config", B_TRUE, &sstate) == 0 &&
1517*10491SRishi.Srivatsavai@Sun.COM 	    get_count("nickname", &sstate, &value) == 0)
1518*10491SRishi.Srivatsavai@Sun.COM 		nickname = value;
1519*10491SRishi.Srivatsavai@Sun.COM 	shut_down_scf(&sstate);
1520*10491SRishi.Srivatsavai@Sun.COM 	return (nickname);
1521*10491SRishi.Srivatsavai@Sun.COM }
1522*10491SRishi.Srivatsavai@Sun.COM 
1523*10491SRishi.Srivatsavai@Sun.COM /* Stores TRILL nickname in SMF configuraiton for the TRILL service */
1524*10491SRishi.Srivatsavai@Sun.COM void
1525*10491SRishi.Srivatsavai@Sun.COM dladm_bridge_set_nick(const char *bridge, uint16_t nick)
1526*10491SRishi.Srivatsavai@Sun.COM {
1527*10491SRishi.Srivatsavai@Sun.COM 	scf_state_t sstate;
1528*10491SRishi.Srivatsavai@Sun.COM 	scf_transaction_t *tran = NULL;
1529*10491SRishi.Srivatsavai@Sun.COM 	boolean_t new_pg = B_FALSE;
1530*10491SRishi.Srivatsavai@Sun.COM 	int rv = 0;
1531*10491SRishi.Srivatsavai@Sun.COM 	char *fmri;
1532*10491SRishi.Srivatsavai@Sun.COM 
1533*10491SRishi.Srivatsavai@Sun.COM 	if (exact_instance(TRILL_SVC_NAME, &sstate) != DLADM_STATUS_OK)
1534*10491SRishi.Srivatsavai@Sun.COM 		return;
1535*10491SRishi.Srivatsavai@Sun.COM 
1536*10491SRishi.Srivatsavai@Sun.COM 	if (scf_service_get_instance(sstate.ss_svc, bridge, sstate.ss_inst) !=
1537*10491SRishi.Srivatsavai@Sun.COM 	    0)
1538*10491SRishi.Srivatsavai@Sun.COM 		goto out;
1539*10491SRishi.Srivatsavai@Sun.COM 	if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL)
1540*10491SRishi.Srivatsavai@Sun.COM 		goto out;
1541*10491SRishi.Srivatsavai@Sun.COM 	if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL)
1542*10491SRishi.Srivatsavai@Sun.COM 		goto out;
1543*10491SRishi.Srivatsavai@Sun.COM 	if (scf_instance_add_pg(sstate.ss_inst, "config",
1544*10491SRishi.Srivatsavai@Sun.COM 	    SCF_GROUP_APPLICATION, 0, sstate.ss_pg) == 0) {
1545*10491SRishi.Srivatsavai@Sun.COM 		new_pg = B_TRUE;
1546*10491SRishi.Srivatsavai@Sun.COM 	} else if (scf_instance_get_pg(sstate.ss_inst, "config",
1547*10491SRishi.Srivatsavai@Sun.COM 	    sstate.ss_pg) != 0) {
1548*10491SRishi.Srivatsavai@Sun.COM 		goto out;
1549*10491SRishi.Srivatsavai@Sun.COM 	}
1550*10491SRishi.Srivatsavai@Sun.COM 	do {
1551*10491SRishi.Srivatsavai@Sun.COM 		if (scf_transaction_start(tran, sstate.ss_pg) != 0)
1552*10491SRishi.Srivatsavai@Sun.COM 			goto out;
1553*10491SRishi.Srivatsavai@Sun.COM 		if (!set_count_property(sstate.ss_handle, tran, "nickname",
1554*10491SRishi.Srivatsavai@Sun.COM 		    nick))
1555*10491SRishi.Srivatsavai@Sun.COM 			goto out;
1556*10491SRishi.Srivatsavai@Sun.COM 		rv = scf_transaction_commit(tran);
1557*10491SRishi.Srivatsavai@Sun.COM 		scf_transaction_reset(tran);
1558*10491SRishi.Srivatsavai@Sun.COM 		if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1)
1559*10491SRishi.Srivatsavai@Sun.COM 			goto out;
1560*10491SRishi.Srivatsavai@Sun.COM 	} while (rv == 0);
1561*10491SRishi.Srivatsavai@Sun.COM 
1562*10491SRishi.Srivatsavai@Sun.COM out:
1563*10491SRishi.Srivatsavai@Sun.COM 	if (tran != NULL) {
1564*10491SRishi.Srivatsavai@Sun.COM 		scf_transaction_destroy_children(tran);
1565*10491SRishi.Srivatsavai@Sun.COM 		scf_transaction_destroy(tran);
1566*10491SRishi.Srivatsavai@Sun.COM 	}
1567*10491SRishi.Srivatsavai@Sun.COM 
1568*10491SRishi.Srivatsavai@Sun.COM 	if (rv != 1 && new_pg)
1569*10491SRishi.Srivatsavai@Sun.COM 		(void) scf_pg_delete(sstate.ss_pg);
1570*10491SRishi.Srivatsavai@Sun.COM 
1571*10491SRishi.Srivatsavai@Sun.COM 	drop_composed(&sstate);
1572*10491SRishi.Srivatsavai@Sun.COM 	shut_down_scf(&sstate);
1573*10491SRishi.Srivatsavai@Sun.COM 	if (rv == 1 && (fmri = alloc_fmri(TRILL_SVC_NAME, bridge)) != NULL) {
1574*10491SRishi.Srivatsavai@Sun.COM 		(void) smf_refresh_instance(fmri);
1575*10491SRishi.Srivatsavai@Sun.COM 		free(fmri);
1576*10491SRishi.Srivatsavai@Sun.COM 	}
1577*10491SRishi.Srivatsavai@Sun.COM }
1578