10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <stdio.h>
300Sstevel@tonic-gate #include <sys/types.h>
310Sstevel@tonic-gate #include <string.h>
320Sstevel@tonic-gate #include <fcntl.h>
330Sstevel@tonic-gate #include <unistd.h>
340Sstevel@tonic-gate #include <stropts.h>
350Sstevel@tonic-gate #include <stdlib.h>
360Sstevel@tonic-gate #include <errno.h>
370Sstevel@tonic-gate #include <libdevinfo.h>
380Sstevel@tonic-gate #include <libdlpi.h>
390Sstevel@tonic-gate #include <libdladm.h>
400Sstevel@tonic-gate #include <sys/dld.h>
410Sstevel@tonic-gate #include <net/if.h>
420Sstevel@tonic-gate 
43*733Skrgopi typedef struct dladm_dev {
44*733Skrgopi 	char			dd_name[IFNAMSIZ];
45*733Skrgopi 	struct dladm_dev	*dd_next;
46*733Skrgopi } dladm_dev_t;
47*733Skrgopi 
48*733Skrgopi typedef struct dladm_walk {
49*733Skrgopi 	dladm_dev_t		*dw_dev_list;
50*733Skrgopi } dladm_walk_t;
51*733Skrgopi 
520Sstevel@tonic-gate /*
530Sstevel@tonic-gate  * Issue an ioctl to the specified file descriptor attached to the
540Sstevel@tonic-gate  * DLD control driver interface.
550Sstevel@tonic-gate  */
560Sstevel@tonic-gate static int
57269Sericheng i_dladm_ioctl(int fd, int ic_cmd, void *ic_dp, int ic_len)
580Sstevel@tonic-gate {
590Sstevel@tonic-gate 	struct strioctl	iocb;
600Sstevel@tonic-gate 
610Sstevel@tonic-gate 	iocb.ic_cmd = ic_cmd;
620Sstevel@tonic-gate 	iocb.ic_timout = 0;
630Sstevel@tonic-gate 	iocb.ic_len = ic_len;
64269Sericheng 	iocb.ic_dp = (char *)ic_dp;
650Sstevel@tonic-gate 
660Sstevel@tonic-gate 	return (ioctl(fd, I_STR, &iocb));
670Sstevel@tonic-gate }
680Sstevel@tonic-gate 
690Sstevel@tonic-gate /*
700Sstevel@tonic-gate  * Return the attributes of the specified datalink from the DLD driver.
710Sstevel@tonic-gate  */
720Sstevel@tonic-gate static int
730Sstevel@tonic-gate i_dladm_info(int fd, const char *name, dladm_attr_t *dap)
740Sstevel@tonic-gate {
750Sstevel@tonic-gate 	dld_ioc_attr_t	dia;
760Sstevel@tonic-gate 
770Sstevel@tonic-gate 	if (strlen(name) >= IFNAMSIZ) {
780Sstevel@tonic-gate 		errno = EINVAL;
790Sstevel@tonic-gate 		return (-1);
800Sstevel@tonic-gate 	}
810Sstevel@tonic-gate 
820Sstevel@tonic-gate 	(void) strlcpy(dia.dia_name, name, IFNAMSIZ);
830Sstevel@tonic-gate 
84269Sericheng 	if (i_dladm_ioctl(fd, DLDIOCATTR, &dia, sizeof (dia)) < 0)
850Sstevel@tonic-gate 		return (-1);
860Sstevel@tonic-gate 
870Sstevel@tonic-gate 	(void) strlcpy(dap->da_dev, dia.dia_dev, MAXNAMELEN);
88269Sericheng 	dap->da_max_sdu = dia.dia_max_sdu;
890Sstevel@tonic-gate 	dap->da_port = dia.dia_port;
900Sstevel@tonic-gate 	dap->da_vid = dia.dia_vid;
910Sstevel@tonic-gate 
920Sstevel@tonic-gate 	return (0);
930Sstevel@tonic-gate }
940Sstevel@tonic-gate 
950Sstevel@tonic-gate /*
960Sstevel@tonic-gate  * Adds a datalink to the array corresponding to arg.
970Sstevel@tonic-gate  */
980Sstevel@tonic-gate static void
990Sstevel@tonic-gate i_dladm_nt_net_add(void *arg, char *name)
1000Sstevel@tonic-gate {
101*733Skrgopi 	dladm_walk_t	*dwp = arg;
102*733Skrgopi 	dladm_dev_t	*ddp = dwp->dw_dev_list;
103*733Skrgopi 	dladm_dev_t	**lastp = &dwp->dw_dev_list;
1040Sstevel@tonic-gate 
105*733Skrgopi 	while (ddp) {
106*733Skrgopi 		/*
107*733Skrgopi 		 * Skip duplicates.
108*733Skrgopi 		 */
109*733Skrgopi 		if (strcmp(ddp->dd_name, name) == 0)
1100Sstevel@tonic-gate 			return;
111*733Skrgopi 
112*733Skrgopi 		lastp = &ddp->dd_next;
113*733Skrgopi 		ddp = ddp->dd_next;
1140Sstevel@tonic-gate 	}
1150Sstevel@tonic-gate 
116*733Skrgopi 	if ((ddp = malloc(sizeof (*ddp))) == NULL)
117*733Skrgopi 		return;
118*733Skrgopi 
119*733Skrgopi 	(void) strlcpy(ddp->dd_name, name, IFNAMSIZ);
120*733Skrgopi 	ddp->dd_next = NULL;
121*733Skrgopi 	*lastp = ddp;
1220Sstevel@tonic-gate }
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate /*
1250Sstevel@tonic-gate  * Walker callback invoked for each DDI_NT_NET node.
1260Sstevel@tonic-gate  */
1270Sstevel@tonic-gate static int
1280Sstevel@tonic-gate i_dladm_nt_net_walk(di_node_t node, di_minor_t minor, void *arg)
1290Sstevel@tonic-gate {
1300Sstevel@tonic-gate 	dl_info_ack_t	dlia;
1310Sstevel@tonic-gate 	char		name[IFNAMSIZ];
1320Sstevel@tonic-gate 	int		fd;
1330Sstevel@tonic-gate 	char		*provider;
1340Sstevel@tonic-gate 	uint_t		ppa;
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	provider = di_minor_name(minor);
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	if ((fd = dlpi_open(provider)) < 0)
1390Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 	if (dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, NULL, NULL) < 0) {
1420Sstevel@tonic-gate 		(void) dlpi_close(fd);
1430Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
1440Sstevel@tonic-gate 	}
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate 	if (dlia.dl_provider_style == DL_STYLE1) {
1470Sstevel@tonic-gate 		i_dladm_nt_net_add(arg, provider);
1480Sstevel@tonic-gate 		(void) dlpi_close(fd);
1490Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
1500Sstevel@tonic-gate 	}
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate 	ppa = di_instance(node);
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 	if (dlpi_attach(fd, -1, ppa) < 0) {
1550Sstevel@tonic-gate 		(void) dlpi_close(fd);
1560Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
1570Sstevel@tonic-gate 	}
1580Sstevel@tonic-gate 	(void) snprintf(name, IFNAMSIZ - 1, "%s%d", provider, ppa);
1590Sstevel@tonic-gate 	i_dladm_nt_net_add(arg, name);
1600Sstevel@tonic-gate 	(void) dlpi_close(fd);
1610Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
1620Sstevel@tonic-gate }
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate /*
1650Sstevel@tonic-gate  * Invoke the specified callback function for each active DDI_NT_NET
1660Sstevel@tonic-gate  * node.
1670Sstevel@tonic-gate  */
1680Sstevel@tonic-gate int
1690Sstevel@tonic-gate dladm_walk(void (*fn)(void *, const char *), void *arg)
1700Sstevel@tonic-gate {
1710Sstevel@tonic-gate 	di_node_t	root;
172*733Skrgopi 	dladm_walk_t	dw;
173*733Skrgopi 	dladm_dev_t	*ddp, *last_ddp;
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
1760Sstevel@tonic-gate 		errno = EFAULT;
1770Sstevel@tonic-gate 		return (-1);
1780Sstevel@tonic-gate 	}
179*733Skrgopi 	dw.dw_dev_list = NULL;
1800Sstevel@tonic-gate 
181*733Skrgopi 	(void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dw,
182*733Skrgopi 	    i_dladm_nt_net_walk);
1830Sstevel@tonic-gate 
184*733Skrgopi 	di_fini(root);
1850Sstevel@tonic-gate 
186*733Skrgopi 	ddp = dw.dw_dev_list;
187*733Skrgopi 	while (ddp) {
188*733Skrgopi 		fn(arg, ddp->dd_name);
189*733Skrgopi 		dladm_walk_vlan(fn, arg, ddp->dd_name);
190*733Skrgopi 		last_ddp = ddp;
191*733Skrgopi 		ddp = ddp->dd_next;
192*733Skrgopi 		free(last_ddp);
1930Sstevel@tonic-gate 	}
1940Sstevel@tonic-gate 
195*733Skrgopi 	return (0);
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate /*
199269Sericheng  * Invoke the specified callback function for each vlan managed by dld
2000Sstevel@tonic-gate  */
2010Sstevel@tonic-gate int
202*733Skrgopi dladm_walk_vlan(void (*fn)(void *, const char *), void *arg, const char *name)
2030Sstevel@tonic-gate {
204*733Skrgopi 	int		fd, bufsize, i;
205*733Skrgopi 	int		nvlan = 4094;
206269Sericheng 	dld_ioc_vlan_t	*iocp = NULL;
207269Sericheng 	dld_vlan_info_t	*dvip;
208269Sericheng 
209269Sericheng 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
210269Sericheng 		return (-1);
211269Sericheng 
212*733Skrgopi 	bufsize = sizeof (dld_ioc_vlan_t) + nvlan * sizeof (dld_vlan_info_t);
2130Sstevel@tonic-gate 
214*733Skrgopi 	if ((iocp = (dld_ioc_vlan_t *)calloc(1, bufsize)) == NULL)
215*733Skrgopi 		return (-1);
216269Sericheng 
217*733Skrgopi 	if (strncmp(name, "aggr", 4) == 0) {
218*733Skrgopi 		(void) strlcpy((char *)iocp->div_name, "aggr0", IFNAMSIZ);
219*733Skrgopi 		iocp->div_port = atoi(strpbrk(name, "0123456789"));
220*733Skrgopi 	} else {
221*733Skrgopi 		(void) strlcpy((char *)iocp->div_name, name, IFNAMSIZ);
222*733Skrgopi 		iocp->div_port = 0;
2230Sstevel@tonic-gate 	}
224*733Skrgopi 	if (i_dladm_ioctl(fd, DLDIOCVLAN, iocp, bufsize) == 0) {
225*733Skrgopi 		dvip = (dld_vlan_info_t *)(iocp + 1);
226*733Skrgopi 		for (i = 0; i < iocp->div_count; i++)
227269Sericheng 			(*fn)(arg, dvip[i].dvi_name);
2280Sstevel@tonic-gate 	}
229*733Skrgopi 	/*
230*733Skrgopi 	 * Note: Callers of dladm_walk_vlan() ignore the return
231*733Skrgopi 	 * value of this routine. So ignoring ioctl failure case
232*733Skrgopi 	 * and just returning 0.
233*733Skrgopi 	 */
234269Sericheng 	free(iocp);
235269Sericheng 	(void) close(fd);
2360Sstevel@tonic-gate 	return (0);
2370Sstevel@tonic-gate }
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate /*
2410Sstevel@tonic-gate  * Returns the current attributes of the specified datalink.
2420Sstevel@tonic-gate  */
2430Sstevel@tonic-gate int
2440Sstevel@tonic-gate dladm_info(const char *name, dladm_attr_t *dap)
2450Sstevel@tonic-gate {
2460Sstevel@tonic-gate 	int		fd;
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
2490Sstevel@tonic-gate 		return (-1);
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	if (i_dladm_info(fd, name, dap) < 0)
2520Sstevel@tonic-gate 		goto failed;
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 	(void) close(fd);
2550Sstevel@tonic-gate 	return (0);
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate failed:
2580Sstevel@tonic-gate 	(void) close(fd);
2590Sstevel@tonic-gate 	return (-1);
2600Sstevel@tonic-gate }
261