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
5*2311Sseb  * Common Development and Distribution License (the "License").
6*2311Sseb  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*2311Sseb  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <stdio.h>
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <string.h>
310Sstevel@tonic-gate #include <fcntl.h>
320Sstevel@tonic-gate #include <unistd.h>
330Sstevel@tonic-gate #include <stropts.h>
340Sstevel@tonic-gate #include <stdlib.h>
350Sstevel@tonic-gate #include <errno.h>
360Sstevel@tonic-gate #include <libdevinfo.h>
370Sstevel@tonic-gate #include <libdlpi.h>
380Sstevel@tonic-gate #include <libdladm.h>
390Sstevel@tonic-gate #include <sys/dld.h>
400Sstevel@tonic-gate #include <net/if.h>
410Sstevel@tonic-gate 
42733Skrgopi typedef struct dladm_dev {
43733Skrgopi 	char			dd_name[IFNAMSIZ];
44733Skrgopi 	struct dladm_dev	*dd_next;
45733Skrgopi } dladm_dev_t;
46733Skrgopi 
47733Skrgopi typedef struct dladm_walk {
48733Skrgopi 	dladm_dev_t		*dw_dev_list;
49733Skrgopi } dladm_walk_t;
50733Skrgopi 
510Sstevel@tonic-gate /*
520Sstevel@tonic-gate  * Issue an ioctl to the specified file descriptor attached to the
530Sstevel@tonic-gate  * DLD control driver interface.
540Sstevel@tonic-gate  */
550Sstevel@tonic-gate static int
56269Sericheng i_dladm_ioctl(int fd, int ic_cmd, void *ic_dp, int ic_len)
570Sstevel@tonic-gate {
580Sstevel@tonic-gate 	struct strioctl	iocb;
590Sstevel@tonic-gate 
600Sstevel@tonic-gate 	iocb.ic_cmd = ic_cmd;
610Sstevel@tonic-gate 	iocb.ic_timout = 0;
620Sstevel@tonic-gate 	iocb.ic_len = ic_len;
63269Sericheng 	iocb.ic_dp = (char *)ic_dp;
640Sstevel@tonic-gate 
650Sstevel@tonic-gate 	return (ioctl(fd, I_STR, &iocb));
660Sstevel@tonic-gate }
670Sstevel@tonic-gate 
680Sstevel@tonic-gate /*
690Sstevel@tonic-gate  * Return the attributes of the specified datalink from the DLD driver.
700Sstevel@tonic-gate  */
710Sstevel@tonic-gate static int
720Sstevel@tonic-gate i_dladm_info(int fd, const char *name, dladm_attr_t *dap)
730Sstevel@tonic-gate {
740Sstevel@tonic-gate 	dld_ioc_attr_t	dia;
750Sstevel@tonic-gate 
760Sstevel@tonic-gate 	if (strlen(name) >= IFNAMSIZ) {
770Sstevel@tonic-gate 		errno = EINVAL;
780Sstevel@tonic-gate 		return (-1);
790Sstevel@tonic-gate 	}
800Sstevel@tonic-gate 
810Sstevel@tonic-gate 	(void) strlcpy(dia.dia_name, name, IFNAMSIZ);
820Sstevel@tonic-gate 
83269Sericheng 	if (i_dladm_ioctl(fd, DLDIOCATTR, &dia, sizeof (dia)) < 0)
840Sstevel@tonic-gate 		return (-1);
850Sstevel@tonic-gate 
860Sstevel@tonic-gate 	(void) strlcpy(dap->da_dev, dia.dia_dev, MAXNAMELEN);
87269Sericheng 	dap->da_max_sdu = dia.dia_max_sdu;
880Sstevel@tonic-gate 	dap->da_vid = dia.dia_vid;
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 	return (0);
910Sstevel@tonic-gate }
920Sstevel@tonic-gate 
930Sstevel@tonic-gate /*
940Sstevel@tonic-gate  * Adds a datalink to the array corresponding to arg.
950Sstevel@tonic-gate  */
960Sstevel@tonic-gate static void
970Sstevel@tonic-gate i_dladm_nt_net_add(void *arg, char *name)
980Sstevel@tonic-gate {
99733Skrgopi 	dladm_walk_t	*dwp = arg;
100733Skrgopi 	dladm_dev_t	*ddp = dwp->dw_dev_list;
101733Skrgopi 	dladm_dev_t	**lastp = &dwp->dw_dev_list;
1020Sstevel@tonic-gate 
103733Skrgopi 	while (ddp) {
104733Skrgopi 		/*
105733Skrgopi 		 * Skip duplicates.
106733Skrgopi 		 */
107733Skrgopi 		if (strcmp(ddp->dd_name, name) == 0)
1080Sstevel@tonic-gate 			return;
109733Skrgopi 
110733Skrgopi 		lastp = &ddp->dd_next;
111733Skrgopi 		ddp = ddp->dd_next;
1120Sstevel@tonic-gate 	}
1130Sstevel@tonic-gate 
114733Skrgopi 	if ((ddp = malloc(sizeof (*ddp))) == NULL)
115733Skrgopi 		return;
116733Skrgopi 
117733Skrgopi 	(void) strlcpy(ddp->dd_name, name, IFNAMSIZ);
118733Skrgopi 	ddp->dd_next = NULL;
119733Skrgopi 	*lastp = ddp;
1200Sstevel@tonic-gate }
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate /*
1230Sstevel@tonic-gate  * Walker callback invoked for each DDI_NT_NET node.
1240Sstevel@tonic-gate  */
1250Sstevel@tonic-gate static int
1260Sstevel@tonic-gate i_dladm_nt_net_walk(di_node_t node, di_minor_t minor, void *arg)
1270Sstevel@tonic-gate {
1280Sstevel@tonic-gate 	dl_info_ack_t	dlia;
1290Sstevel@tonic-gate 	char		name[IFNAMSIZ];
1300Sstevel@tonic-gate 	int		fd;
1310Sstevel@tonic-gate 	char		*provider;
1320Sstevel@tonic-gate 	uint_t		ppa;
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 	provider = di_minor_name(minor);
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	if ((fd = dlpi_open(provider)) < 0)
1370Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 	if (dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, NULL, NULL) < 0) {
1400Sstevel@tonic-gate 		(void) dlpi_close(fd);
1410Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
1420Sstevel@tonic-gate 	}
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	if (dlia.dl_provider_style == DL_STYLE1) {
1450Sstevel@tonic-gate 		i_dladm_nt_net_add(arg, provider);
1460Sstevel@tonic-gate 		(void) dlpi_close(fd);
1470Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
1480Sstevel@tonic-gate 	}
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 	ppa = di_instance(node);
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate 	if (dlpi_attach(fd, -1, ppa) < 0) {
1530Sstevel@tonic-gate 		(void) dlpi_close(fd);
1540Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
1550Sstevel@tonic-gate 	}
1560Sstevel@tonic-gate 	(void) snprintf(name, IFNAMSIZ - 1, "%s%d", provider, ppa);
1570Sstevel@tonic-gate 	i_dladm_nt_net_add(arg, name);
1580Sstevel@tonic-gate 	(void) dlpi_close(fd);
1590Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
1600Sstevel@tonic-gate }
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate /*
1630Sstevel@tonic-gate  * Invoke the specified callback function for each active DDI_NT_NET
1640Sstevel@tonic-gate  * node.
1650Sstevel@tonic-gate  */
1660Sstevel@tonic-gate int
1670Sstevel@tonic-gate dladm_walk(void (*fn)(void *, const char *), void *arg)
1680Sstevel@tonic-gate {
1690Sstevel@tonic-gate 	di_node_t	root;
170733Skrgopi 	dladm_walk_t	dw;
171733Skrgopi 	dladm_dev_t	*ddp, *last_ddp;
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 	if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
1740Sstevel@tonic-gate 		errno = EFAULT;
1750Sstevel@tonic-gate 		return (-1);
1760Sstevel@tonic-gate 	}
177733Skrgopi 	dw.dw_dev_list = NULL;
1780Sstevel@tonic-gate 
179733Skrgopi 	(void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dw,
180733Skrgopi 	    i_dladm_nt_net_walk);
1810Sstevel@tonic-gate 
182733Skrgopi 	di_fini(root);
1830Sstevel@tonic-gate 
184733Skrgopi 	ddp = dw.dw_dev_list;
185733Skrgopi 	while (ddp) {
186733Skrgopi 		fn(arg, ddp->dd_name);
187737Skrgopi 		(void) dladm_walk_vlan(fn, arg, ddp->dd_name);
188733Skrgopi 		last_ddp = ddp;
189733Skrgopi 		ddp = ddp->dd_next;
190733Skrgopi 		free(last_ddp);
1910Sstevel@tonic-gate 	}
1920Sstevel@tonic-gate 
193733Skrgopi 	return (0);
1940Sstevel@tonic-gate }
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate /*
197269Sericheng  * Invoke the specified callback function for each vlan managed by dld
1980Sstevel@tonic-gate  */
1990Sstevel@tonic-gate int
200733Skrgopi dladm_walk_vlan(void (*fn)(void *, const char *), void *arg, const char *name)
2010Sstevel@tonic-gate {
202733Skrgopi 	int		fd, bufsize, i;
203733Skrgopi 	int		nvlan = 4094;
204269Sericheng 	dld_ioc_vlan_t	*iocp = NULL;
205269Sericheng 	dld_vlan_info_t	*dvip;
206269Sericheng 
207269Sericheng 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
208269Sericheng 		return (-1);
209269Sericheng 
210733Skrgopi 	bufsize = sizeof (dld_ioc_vlan_t) + nvlan * sizeof (dld_vlan_info_t);
2110Sstevel@tonic-gate 
212733Skrgopi 	if ((iocp = (dld_ioc_vlan_t *)calloc(1, bufsize)) == NULL)
213733Skrgopi 		return (-1);
214269Sericheng 
215*2311Sseb 	(void) strlcpy((char *)iocp->div_name, name, IFNAMSIZ);
216733Skrgopi 	if (i_dladm_ioctl(fd, DLDIOCVLAN, iocp, bufsize) == 0) {
217733Skrgopi 		dvip = (dld_vlan_info_t *)(iocp + 1);
218733Skrgopi 		for (i = 0; i < iocp->div_count; i++)
219269Sericheng 			(*fn)(arg, dvip[i].dvi_name);
2200Sstevel@tonic-gate 	}
221733Skrgopi 	/*
222733Skrgopi 	 * Note: Callers of dladm_walk_vlan() ignore the return
223733Skrgopi 	 * value of this routine. So ignoring ioctl failure case
224733Skrgopi 	 * and just returning 0.
225733Skrgopi 	 */
226269Sericheng 	free(iocp);
227269Sericheng 	(void) close(fd);
2280Sstevel@tonic-gate 	return (0);
2290Sstevel@tonic-gate }
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate /*
2330Sstevel@tonic-gate  * Returns the current attributes of the specified datalink.
2340Sstevel@tonic-gate  */
2350Sstevel@tonic-gate int
2360Sstevel@tonic-gate dladm_info(const char *name, dladm_attr_t *dap)
2370Sstevel@tonic-gate {
2380Sstevel@tonic-gate 	int		fd;
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
2410Sstevel@tonic-gate 		return (-1);
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	if (i_dladm_info(fd, name, dap) < 0)
2440Sstevel@tonic-gate 		goto failed;
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	(void) close(fd);
2470Sstevel@tonic-gate 	return (0);
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate failed:
2500Sstevel@tonic-gate 	(void) close(fd);
2510Sstevel@tonic-gate 	return (-1);
2520Sstevel@tonic-gate }
253