xref: /illumos-gate/usr/src/lib/libdladm/common/libdladm.c (revision 0dee7919e2f2a6479d16b370af93747b9416b242)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <sys/types.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <stropts.h>
35 #include <stdlib.h>
36 #include <errno.h>
37 #include <libdevinfo.h>
38 #include <libdlpi.h>
39 #include <libdladm.h>
40 #include <sys/dld.h>
41 #include <net/if.h>
42 
43 /*
44  * Issue an ioctl to the specified file descriptor attached to the
45  * DLD control driver interface.
46  */
47 static int
48 i_dladm_ioctl(int fd, int ic_cmd, void *ic_dp, int ic_len)
49 {
50 	struct strioctl	iocb;
51 
52 	iocb.ic_cmd = ic_cmd;
53 	iocb.ic_timout = 0;
54 	iocb.ic_len = ic_len;
55 	iocb.ic_dp = (char *)ic_dp;
56 
57 	return (ioctl(fd, I_STR, &iocb));
58 }
59 
60 /*
61  * Return the attributes of the specified datalink from the DLD driver.
62  */
63 static int
64 i_dladm_info(int fd, const char *name, dladm_attr_t *dap)
65 {
66 	dld_ioc_attr_t	dia;
67 
68 	if (strlen(name) >= IFNAMSIZ) {
69 		errno = EINVAL;
70 		return (-1);
71 	}
72 
73 	(void) strlcpy(dia.dia_name, name, IFNAMSIZ);
74 
75 	if (i_dladm_ioctl(fd, DLDIOCATTR, &dia, sizeof (dia)) < 0)
76 		return (-1);
77 
78 	(void) strlcpy(dap->da_dev, dia.dia_dev, MAXNAMELEN);
79 	dap->da_max_sdu = dia.dia_max_sdu;
80 	dap->da_port = dia.dia_port;
81 	dap->da_vid = dia.dia_vid;
82 
83 	return (0);
84 }
85 
86 /*
87  * Callback function used to count the number of DDI_NT_NET.
88  */
89 /* ARGSUSED */
90 static int
91 i_dladm_nt_net_count(di_node_t node, di_minor_t minor, void *arg)
92 {
93 	uint_t		*countp = arg;
94 
95 	(*countp)++;
96 	return (DI_WALK_CONTINUE);
97 }
98 
99 /*
100  * Adds a datalink to the array corresponding to arg.
101  */
102 static void
103 i_dladm_nt_net_add(void *arg, char *name)
104 {
105 	char		**array = arg;
106 	char		*elem;
107 
108 	for (;;) {
109 		elem = *(array++);
110 		if (elem[0] == '\0')
111 			break;
112 		if (strcmp(elem, name) == 0)
113 			return;
114 	}
115 
116 	(void) strlcpy(elem, name, MAXNAMELEN);
117 }
118 
119 /*
120  * Walker callback invoked for each DDI_NT_NET node.
121  */
122 static int
123 i_dladm_nt_net_walk(di_node_t node, di_minor_t minor, void *arg)
124 {
125 	dl_info_ack_t	dlia;
126 	char		name[IFNAMSIZ];
127 	int		fd;
128 	char		*provider;
129 	uint_t		ppa;
130 
131 	provider = di_minor_name(minor);
132 
133 	if ((fd = dlpi_open(provider)) < 0)
134 		return (DI_WALK_CONTINUE);
135 
136 	if (dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, NULL, NULL) < 0) {
137 		(void) dlpi_close(fd);
138 		return (DI_WALK_CONTINUE);
139 	}
140 
141 	if (dlia.dl_provider_style == DL_STYLE1) {
142 		i_dladm_nt_net_add(arg, provider);
143 		(void) dlpi_close(fd);
144 		return (DI_WALK_CONTINUE);
145 	}
146 
147 	ppa = di_instance(node);
148 
149 	if (dlpi_attach(fd, -1, ppa) < 0) {
150 		(void) dlpi_close(fd);
151 		return (DI_WALK_CONTINUE);
152 	}
153 
154 	(void) snprintf(name, IFNAMSIZ - 1, "%s%d", provider, ppa);
155 	i_dladm_nt_net_add(arg, name);
156 	(void) dlpi_close(fd);
157 	return (DI_WALK_CONTINUE);
158 }
159 
160 /*
161  * Invoke the specified callback function for each active DDI_NT_NET
162  * node.
163  */
164 int
165 dladm_walk(void (*fn)(void *, const char *), void *arg)
166 {
167 	di_node_t	root;
168 	uint_t		count;
169 	char		**array;
170 	char		*elem;
171 	int		i;
172 
173 	if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
174 		errno = EFAULT;
175 		return (-1);
176 	}
177 
178 	count = 0;
179 	(void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, (void *)&count,
180 	    i_dladm_nt_net_count);
181 
182 	if (count == 0)
183 		return (dladm_walk_vlan(fn, arg));
184 
185 	if ((array = malloc(count * sizeof (char *))) == NULL)
186 		goto done;
187 
188 	for (i = 0; i < count; i++) {
189 		if ((array[i] = malloc(IFNAMSIZ)) != NULL) {
190 			(void) memset(array[i], '\0', IFNAMSIZ);
191 			continue;
192 		}
193 
194 		while (--i >= 0)
195 			free(array[i]);
196 		goto done;
197 	}
198 
199 	(void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, (void *)array,
200 	    i_dladm_nt_net_walk);
201 	di_fini(root);
202 
203 	for (i = 0; i < count; i++) {
204 		elem = array[i];
205 		if (elem[0] != '\0')
206 			fn(arg, (const char *)elem);
207 		free(elem);
208 	}
209 
210 done:
211 	free(array);
212 	return (dladm_walk_vlan(fn, arg));
213 }
214 
215 /*
216  * Invoke the specified callback function for each vlan managed by dld
217  */
218 int
219 dladm_walk_vlan(void (*fn)(void *, const char *), void *arg)
220 {
221 	int		fd, bufsize, rc, i;
222 	int		nvlan = 512;
223 	dld_ioc_vlan_t	*iocp = NULL;
224 	dld_vlan_info_t	*dvip;
225 
226 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
227 		return (-1);
228 
229 	for (;;) {
230 		bufsize = sizeof (dld_ioc_vlan_t) +
231 		    nvlan * sizeof (dld_vlan_info_t);
232 
233 		iocp = (dld_ioc_vlan_t *)calloc(1, bufsize);
234 		if (iocp == NULL)
235 			goto done;
236 
237 		rc = i_dladm_ioctl(fd, DLDIOCVLAN, iocp, bufsize);
238 		if (rc == 0)
239 			break;
240 
241 		if (errno == ENOSPC) {
242 			nvlan *= 2;
243 			free(iocp);
244 			continue;
245 		}
246 		goto done;
247 	}
248 
249 	dvip = (dld_vlan_info_t *)(iocp + 1);
250 
251 	for (i = 0; i < iocp->div_count; i++) {
252 		if (dvip[i].dvi_vid != 0)
253 			(*fn)(arg, dvip[i].dvi_name);
254 	}
255 
256 done:
257 	free(iocp);
258 	(void) close(fd);
259 	return (0);
260 }
261 
262 
263 /*
264  * Returns the current attributes of the specified datalink.
265  */
266 int
267 dladm_info(const char *name, dladm_attr_t *dap)
268 {
269 	int		fd;
270 
271 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
272 		return (-1);
273 
274 	if (i_dladm_info(fd, name, dap) < 0)
275 		goto failed;
276 
277 	(void) close(fd);
278 	return (0);
279 
280 failed:
281 	(void) close(fd);
282 	return (-1);
283 }
284