1*3871Syz147064 /*
2*3871Syz147064  * CDDL HEADER START
3*3871Syz147064  *
4*3871Syz147064  * The contents of this file are subject to the terms of the
5*3871Syz147064  * Common Development and Distribution License (the "License").
6*3871Syz147064  * You may not use this file except in compliance with the License.
7*3871Syz147064  *
8*3871Syz147064  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*3871Syz147064  * or http://www.opensolaris.org/os/licensing.
10*3871Syz147064  * See the License for the specific language governing permissions
11*3871Syz147064  * and limitations under the License.
12*3871Syz147064  *
13*3871Syz147064  * When distributing Covered Code, include this CDDL HEADER in each
14*3871Syz147064  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*3871Syz147064  * If applicable, add the following below this CDDL HEADER, with the
16*3871Syz147064  * fields enclosed by brackets "[]" replaced with your own identifying
17*3871Syz147064  * information: Portions Copyright [yyyy] [name of copyright owner]
18*3871Syz147064  *
19*3871Syz147064  * CDDL HEADER END
20*3871Syz147064  */
21*3871Syz147064 /*
22*3871Syz147064  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*3871Syz147064  * Use is subject to license terms.
24*3871Syz147064  */
25*3871Syz147064 
26*3871Syz147064 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*3871Syz147064 
28*3871Syz147064 #include <sys/types.h>
29*3871Syz147064 #include <unistd.h>
30*3871Syz147064 #include <errno.h>
31*3871Syz147064 #include <fcntl.h>
32*3871Syz147064 #include <strings.h>
33*3871Syz147064 #include <sys/stat.h>
34*3871Syz147064 #include <sys/dld.h>
35*3871Syz147064 #include <libdlpi.h>
36*3871Syz147064 #include <libdevinfo.h>
37*3871Syz147064 #include <libdllink.h>
38*3871Syz147064 #include <libdladm_impl.h>
39*3871Syz147064 
40*3871Syz147064 typedef struct dladm_dev {
41*3871Syz147064 	char			dd_name[IFNAMSIZ];
42*3871Syz147064 	struct dladm_dev	*dd_next;
43*3871Syz147064 } dladm_dev_t;
44*3871Syz147064 
45*3871Syz147064 typedef struct dladm_walk {
46*3871Syz147064 	dladm_dev_t		*dw_dev_list;
47*3871Syz147064 } dladm_walk_t;
48*3871Syz147064 
49*3871Syz147064 /*
50*3871Syz147064  * Return the attributes of the specified datalink from the DLD driver.
51*3871Syz147064  */
52*3871Syz147064 static int
53*3871Syz147064 i_dladm_info(int fd, const char *name, dladm_attr_t *dap)
54*3871Syz147064 {
55*3871Syz147064 	dld_ioc_attr_t	dia;
56*3871Syz147064 
57*3871Syz147064 	if (strlen(name) >= IFNAMSIZ) {
58*3871Syz147064 		errno = EINVAL;
59*3871Syz147064 		return (-1);
60*3871Syz147064 	}
61*3871Syz147064 
62*3871Syz147064 	(void) strlcpy(dia.dia_name, name, IFNAMSIZ);
63*3871Syz147064 
64*3871Syz147064 	if (i_dladm_ioctl(fd, DLDIOCATTR, &dia, sizeof (dia)) < 0)
65*3871Syz147064 		return (-1);
66*3871Syz147064 
67*3871Syz147064 	(void) strlcpy(dap->da_dev, dia.dia_dev, MAXNAMELEN);
68*3871Syz147064 	dap->da_max_sdu = dia.dia_max_sdu;
69*3871Syz147064 	dap->da_vid = dia.dia_vid;
70*3871Syz147064 
71*3871Syz147064 	return (0);
72*3871Syz147064 }
73*3871Syz147064 
74*3871Syz147064 /*
75*3871Syz147064  * Adds a datalink to the array corresponding to arg.
76*3871Syz147064  */
77*3871Syz147064 static void
78*3871Syz147064 i_dladm_nt_net_add(void *arg, char *name)
79*3871Syz147064 {
80*3871Syz147064 	dladm_walk_t	*dwp = arg;
81*3871Syz147064 	dladm_dev_t	*ddp = dwp->dw_dev_list;
82*3871Syz147064 	dladm_dev_t	**lastp = &dwp->dw_dev_list;
83*3871Syz147064 
84*3871Syz147064 	while (ddp) {
85*3871Syz147064 		/*
86*3871Syz147064 		 * Skip duplicates.
87*3871Syz147064 		 */
88*3871Syz147064 		if (strcmp(ddp->dd_name, name) == 0)
89*3871Syz147064 			return;
90*3871Syz147064 
91*3871Syz147064 		lastp = &ddp->dd_next;
92*3871Syz147064 		ddp = ddp->dd_next;
93*3871Syz147064 	}
94*3871Syz147064 
95*3871Syz147064 	if ((ddp = malloc(sizeof (*ddp))) == NULL)
96*3871Syz147064 		return;
97*3871Syz147064 
98*3871Syz147064 	(void) strlcpy(ddp->dd_name, name, IFNAMSIZ);
99*3871Syz147064 	ddp->dd_next = NULL;
100*3871Syz147064 	*lastp = ddp;
101*3871Syz147064 }
102*3871Syz147064 
103*3871Syz147064 /*
104*3871Syz147064  * Walker callback invoked for each DDI_NT_NET node.
105*3871Syz147064  */
106*3871Syz147064 static int
107*3871Syz147064 i_dladm_nt_net_walk(di_node_t node, di_minor_t minor, void *arg)
108*3871Syz147064 {
109*3871Syz147064 	char		linkname[DLPI_LINKNAME_MAX];
110*3871Syz147064 	dlpi_handle_t	dh;
111*3871Syz147064 
112*3871Syz147064 	if (dlpi_makelink(linkname, di_minor_name(minor),
113*3871Syz147064 	    di_instance(node)) != DLPI_SUCCESS)
114*3871Syz147064 		return (DI_WALK_CONTINUE);
115*3871Syz147064 
116*3871Syz147064 	if (dlpi_open(linkname, &dh, 0) == DLPI_SUCCESS) {
117*3871Syz147064 		i_dladm_nt_net_add(arg, linkname);
118*3871Syz147064 		dlpi_close(dh);
119*3871Syz147064 	}
120*3871Syz147064 	return (DI_WALK_CONTINUE);
121*3871Syz147064 }
122*3871Syz147064 
123*3871Syz147064 /*
124*3871Syz147064  * Hold a data-link.
125*3871Syz147064  */
126*3871Syz147064 static int
127*3871Syz147064 i_dladm_hold_link(const char *name, zoneid_t zoneid, boolean_t docheck)
128*3871Syz147064 {
129*3871Syz147064 	int		fd;
130*3871Syz147064 	dld_hold_vlan_t	dhv;
131*3871Syz147064 
132*3871Syz147064 	if (strlen(name) >= IFNAMSIZ) {
133*3871Syz147064 		errno = EINVAL;
134*3871Syz147064 		return (-1);
135*3871Syz147064 	}
136*3871Syz147064 
137*3871Syz147064 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
138*3871Syz147064 		return (-1);
139*3871Syz147064 
140*3871Syz147064 	bzero(&dhv, sizeof (dld_hold_vlan_t));
141*3871Syz147064 	(void) strlcpy(dhv.dhv_name, name, IFNAMSIZ);
142*3871Syz147064 	dhv.dhv_zid = zoneid;
143*3871Syz147064 	dhv.dhv_docheck = docheck;
144*3871Syz147064 
145*3871Syz147064 	if (i_dladm_ioctl(fd, DLDIOCHOLDVLAN, &dhv, sizeof (dhv)) < 0) {
146*3871Syz147064 		int olderrno = errno;
147*3871Syz147064 
148*3871Syz147064 		(void) close(fd);
149*3871Syz147064 		errno = olderrno;
150*3871Syz147064 		return (-1);
151*3871Syz147064 	}
152*3871Syz147064 
153*3871Syz147064 	(void) close(fd);
154*3871Syz147064 	return (0);
155*3871Syz147064 }
156*3871Syz147064 
157*3871Syz147064 /*
158*3871Syz147064  * Release a data-link.
159*3871Syz147064  */
160*3871Syz147064 static int
161*3871Syz147064 i_dladm_rele_link(const char *name, zoneid_t zoneid, boolean_t docheck)
162*3871Syz147064 {
163*3871Syz147064 	int		fd;
164*3871Syz147064 	dld_hold_vlan_t	dhv;
165*3871Syz147064 
166*3871Syz147064 	if (strlen(name) >= IFNAMSIZ) {
167*3871Syz147064 		errno = EINVAL;
168*3871Syz147064 		return (-1);
169*3871Syz147064 	}
170*3871Syz147064 
171*3871Syz147064 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
172*3871Syz147064 		return (-1);
173*3871Syz147064 
174*3871Syz147064 	bzero(&dhv, sizeof (dld_hold_vlan_t));
175*3871Syz147064 	(void) strlcpy(dhv.dhv_name, name, IFNAMSIZ);
176*3871Syz147064 	dhv.dhv_zid = zoneid;
177*3871Syz147064 	dhv.dhv_docheck = docheck;
178*3871Syz147064 
179*3871Syz147064 	if (i_dladm_ioctl(fd, DLDIOCRELEVLAN, &dhv, sizeof (dhv)) < 0) {
180*3871Syz147064 		int olderrno = errno;
181*3871Syz147064 
182*3871Syz147064 		(void) close(fd);
183*3871Syz147064 		errno = olderrno;
184*3871Syz147064 		return (-1);
185*3871Syz147064 	}
186*3871Syz147064 
187*3871Syz147064 	(void) close(fd);
188*3871Syz147064 	return (0);
189*3871Syz147064 }
190*3871Syz147064 
191*3871Syz147064 /*
192*3871Syz147064  * Invoke the specified callback function for each active DDI_NT_NET
193*3871Syz147064  * node.
194*3871Syz147064  */
195*3871Syz147064 int
196*3871Syz147064 dladm_walk(void (*fn)(void *, const char *), void *arg)
197*3871Syz147064 {
198*3871Syz147064 	di_node_t	root;
199*3871Syz147064 	dladm_walk_t	dw;
200*3871Syz147064 	dladm_dev_t	*ddp, *last_ddp;
201*3871Syz147064 
202*3871Syz147064 	if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
203*3871Syz147064 		errno = EFAULT;
204*3871Syz147064 		return (-1);
205*3871Syz147064 	}
206*3871Syz147064 	dw.dw_dev_list = NULL;
207*3871Syz147064 
208*3871Syz147064 	(void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dw,
209*3871Syz147064 	    i_dladm_nt_net_walk);
210*3871Syz147064 
211*3871Syz147064 	di_fini(root);
212*3871Syz147064 
213*3871Syz147064 	ddp = dw.dw_dev_list;
214*3871Syz147064 	while (ddp) {
215*3871Syz147064 		fn(arg, ddp->dd_name);
216*3871Syz147064 		last_ddp = ddp;
217*3871Syz147064 		ddp = ddp->dd_next;
218*3871Syz147064 		free(last_ddp);
219*3871Syz147064 	}
220*3871Syz147064 
221*3871Syz147064 	return (0);
222*3871Syz147064 }
223*3871Syz147064 
224*3871Syz147064 /*
225*3871Syz147064  * MAC Administration Library.
226*3871Syz147064  *
227*3871Syz147064  * This library is used by administration tools such as dladm(1M) to
228*3871Syz147064  * iterate through the list of MAC interfaces
229*3871Syz147064  *
230*3871Syz147064  */
231*3871Syz147064 
232*3871Syz147064 typedef struct dladm_mac_dev {
233*3871Syz147064 	char			dm_name[MAXNAMELEN];
234*3871Syz147064 	struct dladm_mac_dev	*dm_next;
235*3871Syz147064 } dladm_mac_dev_t;
236*3871Syz147064 
237*3871Syz147064 typedef struct macadm_walk {
238*3871Syz147064 	dladm_mac_dev_t		*dmd_dev_list;
239*3871Syz147064 } dladm_mac_walk_t;
240*3871Syz147064 
241*3871Syz147064 /*
242*3871Syz147064  * Local callback invoked for each DDI_NT_NET node.
243*3871Syz147064  */
244*3871Syz147064 /* ARGSUSED */
245*3871Syz147064 static int
246*3871Syz147064 i_dladm_mac_walk(di_node_t node, di_minor_t minor, void *arg)
247*3871Syz147064 {
248*3871Syz147064 	dladm_mac_walk_t	*dmwp = arg;
249*3871Syz147064 	dladm_mac_dev_t		*dmdp = dmwp->dmd_dev_list;
250*3871Syz147064 	dladm_mac_dev_t		**last_dmdp = &dmwp->dmd_dev_list;
251*3871Syz147064 	char			mac[MAXNAMELEN];
252*3871Syz147064 
253*3871Syz147064 	(void) snprintf(mac, MAXNAMELEN, "%s%d",
254*3871Syz147064 	    di_driver_name(node), di_instance(node));
255*3871Syz147064 
256*3871Syz147064 	/*
257*3871Syz147064 	 * Skip aggregations.
258*3871Syz147064 	 */
259*3871Syz147064 	if (strcmp("aggr", di_driver_name(node)) == 0)
260*3871Syz147064 		return (DI_WALK_CONTINUE);
261*3871Syz147064 
262*3871Syz147064 	while (dmdp) {
263*3871Syz147064 		/*
264*3871Syz147064 		 * Skip duplicates.
265*3871Syz147064 		 */
266*3871Syz147064 		if (strcmp(dmdp->dm_name, mac) == 0)
267*3871Syz147064 			return (DI_WALK_CONTINUE);
268*3871Syz147064 
269*3871Syz147064 		last_dmdp = &dmdp->dm_next;
270*3871Syz147064 		dmdp = dmdp->dm_next;
271*3871Syz147064 	}
272*3871Syz147064 
273*3871Syz147064 	if ((dmdp = malloc(sizeof (*dmdp))) == NULL)
274*3871Syz147064 		return (DI_WALK_CONTINUE);
275*3871Syz147064 
276*3871Syz147064 	(void) strlcpy(dmdp->dm_name, mac, MAXNAMELEN);
277*3871Syz147064 	dmdp->dm_next = NULL;
278*3871Syz147064 	*last_dmdp = dmdp;
279*3871Syz147064 
280*3871Syz147064 	return (DI_WALK_CONTINUE);
281*3871Syz147064 }
282*3871Syz147064 
283*3871Syz147064 /*
284*3871Syz147064  * Invoke the specified callback for each DDI_NT_MAC node.
285*3871Syz147064  */
286*3871Syz147064 int
287*3871Syz147064 dladm_mac_walk(void (*fn)(void *, const char *), void *arg)
288*3871Syz147064 {
289*3871Syz147064 	di_node_t		root;
290*3871Syz147064 	dladm_mac_walk_t	dmw;
291*3871Syz147064 	dladm_mac_dev_t		*dmdp, *next;
292*3871Syz147064 
293*3871Syz147064 	if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL)
294*3871Syz147064 		return (-1);
295*3871Syz147064 
296*3871Syz147064 	dmw.dmd_dev_list = NULL;
297*3871Syz147064 
298*3871Syz147064 	(void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dmw,
299*3871Syz147064 	    i_dladm_mac_walk);
300*3871Syz147064 
301*3871Syz147064 	di_fini(root);
302*3871Syz147064 
303*3871Syz147064 	dmdp = dmw.dmd_dev_list;
304*3871Syz147064 	for (dmdp = dmw.dmd_dev_list; dmdp != NULL; dmdp = next) {
305*3871Syz147064 		next = dmdp->dm_next;
306*3871Syz147064 		(*fn)(arg, dmdp->dm_name);
307*3871Syz147064 		free(dmdp);
308*3871Syz147064 	}
309*3871Syz147064 
310*3871Syz147064 	return (0);
311*3871Syz147064 }
312*3871Syz147064 
313*3871Syz147064 /*
314*3871Syz147064  * Returns the current attributes of the specified datalink.
315*3871Syz147064  */
316*3871Syz147064 int
317*3871Syz147064 dladm_info(const char *name, dladm_attr_t *dap)
318*3871Syz147064 {
319*3871Syz147064 	int		fd;
320*3871Syz147064 
321*3871Syz147064 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
322*3871Syz147064 		return (-1);
323*3871Syz147064 
324*3871Syz147064 	if (i_dladm_info(fd, name, dap) < 0)
325*3871Syz147064 		goto failed;
326*3871Syz147064 
327*3871Syz147064 	(void) close(fd);
328*3871Syz147064 	return (0);
329*3871Syz147064 
330*3871Syz147064 failed:
331*3871Syz147064 	(void) close(fd);
332*3871Syz147064 	return (-1);
333*3871Syz147064 }
334*3871Syz147064 
335*3871Syz147064 const char *
336*3871Syz147064 dladm_linkstate2str(link_state_t state, char *buf)
337*3871Syz147064 {
338*3871Syz147064 	const char	*s;
339*3871Syz147064 
340*3871Syz147064 	switch (state) {
341*3871Syz147064 	case LINK_STATE_UP:
342*3871Syz147064 		s = "up";
343*3871Syz147064 		break;
344*3871Syz147064 	case LINK_STATE_DOWN:
345*3871Syz147064 		s = "down";
346*3871Syz147064 		break;
347*3871Syz147064 	default:
348*3871Syz147064 		s = "unknown";
349*3871Syz147064 		break;
350*3871Syz147064 	}
351*3871Syz147064 	(void) snprintf(buf, DLADM_STRSIZE, "%s", s);
352*3871Syz147064 	return (buf);
353*3871Syz147064 }
354*3871Syz147064 
355*3871Syz147064 const char *
356*3871Syz147064 dladm_linkduplex2str(link_duplex_t duplex, char *buf)
357*3871Syz147064 {
358*3871Syz147064 	const char	*s;
359*3871Syz147064 
360*3871Syz147064 	switch (duplex) {
361*3871Syz147064 	case LINK_DUPLEX_FULL:
362*3871Syz147064 		s = "full";
363*3871Syz147064 		break;
364*3871Syz147064 	case LINK_DUPLEX_HALF:
365*3871Syz147064 		s = "half";
366*3871Syz147064 		break;
367*3871Syz147064 	default:
368*3871Syz147064 		s = "unknown";
369*3871Syz147064 		break;
370*3871Syz147064 	}
371*3871Syz147064 	(void) snprintf(buf, DLADM_STRSIZE, "%s", s);
372*3871Syz147064 	return (buf);
373*3871Syz147064 }
374*3871Syz147064 
375*3871Syz147064 /*
376*3871Syz147064  * Do a "hold" operation to a link.
377*3871Syz147064  */
378*3871Syz147064 int
379*3871Syz147064 dladm_hold_link(const char *name, zoneid_t zoneid, boolean_t docheck)
380*3871Syz147064 {
381*3871Syz147064 	return (i_dladm_hold_link(name, zoneid, docheck));
382*3871Syz147064 }
383*3871Syz147064 
384*3871Syz147064 /*
385*3871Syz147064  * Do a "release" operation to a link.
386*3871Syz147064  */
387*3871Syz147064 int
388*3871Syz147064 dladm_rele_link(const char *name, zoneid_t zoneid, boolean_t docheck)
389*3871Syz147064 {
390*3871Syz147064 	return (i_dladm_rele_link(name, zoneid, docheck));
391*3871Syz147064 }
392