xref: /titanic_50/usr/src/uts/common/io/aggr/aggr_ctl.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 /*
30  * IEEE 802.3ad Link Aggregation -- IOCTL processing.
31  */
32 
33 #include <sys/ddi.h>
34 #include <sys/aggr.h>
35 #include <sys/aggr_impl.h>
36 
37 static int aggr_ioc_create(int, void *, int);
38 static int aggr_ioc_delete(int, void *, int);
39 static int aggr_ioc_info(int, void *, int);
40 static int aggr_ioc_add_remove(int, void *, int);
41 static int aggr_ioc_status(int, void *, int);
42 static int aggr_ioc_modify(int, void *, int);
43 
44 typedef struct ioc_cmd_s {
45 	int ic_cmd;
46 	int (*ic_func)(int, void *, int);
47 } ioc_cmd_t;
48 
49 static ioc_cmd_t ioc_cmd[] = {
50 	{LAIOC_CREATE, aggr_ioc_create},
51 	{LAIOC_DELETE, aggr_ioc_delete},
52 	{LAIOC_INFO, aggr_ioc_info},
53 	{LAIOC_ADD, aggr_ioc_add_remove},
54 	{LAIOC_REMOVE, aggr_ioc_add_remove},
55 	{LAIOC_MODIFY, aggr_ioc_modify}};
56 
57 /*ARGSUSED*/
58 int
59 aggr_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
60 {
61 	/* only the control interface can be opened */
62 	if (getminor(*devp) != AGGR_MINOR_CTL)
63 		return (ENOSYS);
64 	return (0);
65 }
66 
67 /*ARGSUSED*/
68 int
69 aggr_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
70 {
71 	return (0);
72 }
73 
74 /*
75  * Process a LAIOC_MODIFY request.
76  */
77 /* ARGSUSED */
78 static int
79 aggr_ioc_modify(int cmd, void *arg, int mode)
80 {
81 	STRUCT_DECL(laioc_modify, modify_arg);
82 	uint32_t policy;
83 	boolean_t mac_fixed;
84 	uchar_t mac_addr[ETHERADDRL];
85 	uint8_t modify_mask_arg, modify_mask = 0;
86 	uint32_t key;
87 	aggr_lacp_mode_t lacp_mode;
88 	aggr_lacp_timer_t lacp_timer;
89 
90 	STRUCT_INIT(modify_arg, mode);
91 
92 	if (copyin(arg, STRUCT_BUF(modify_arg), STRUCT_SIZE(modify_arg)) != 0)
93 		return (EFAULT);
94 
95 	key = STRUCT_FGET(modify_arg, lu_key);
96 	modify_mask_arg = STRUCT_FGET(modify_arg, lu_modify_mask);
97 
98 	if (modify_mask_arg & LAIOC_MODIFY_POLICY) {
99 		modify_mask |= AGGR_MODIFY_POLICY;
100 		policy = STRUCT_FGET(modify_arg, lu_policy);
101 	}
102 
103 	if (modify_mask_arg & LAIOC_MODIFY_MAC) {
104 		modify_mask |= AGGR_MODIFY_MAC;
105 		bcopy(STRUCT_FGET(modify_arg, lu_mac), mac_addr, ETHERADDRL);
106 		mac_fixed = STRUCT_FGET(modify_arg, lu_mac_fixed);
107 	}
108 
109 	if (modify_mask_arg & LAIOC_MODIFY_LACP_MODE) {
110 		modify_mask |= AGGR_MODIFY_LACP_MODE;
111 		lacp_mode = STRUCT_FGET(modify_arg, lu_lacp_mode);
112 	}
113 
114 	if (modify_mask_arg & LAIOC_MODIFY_LACP_TIMER) {
115 		modify_mask |= AGGR_MODIFY_LACP_TIMER;
116 		lacp_timer = STRUCT_FGET(modify_arg, lu_lacp_timer);
117 	}
118 
119 	return (aggr_grp_modify(key, NULL, modify_mask, policy, mac_fixed,
120 	    mac_addr, lacp_mode, lacp_timer));
121 }
122 
123 /*
124  * Process a LAIOC_CREATE request.
125  */
126 /* ARGSUSED */
127 static int
128 aggr_ioc_create(int cmd, void *arg, int mode)
129 {
130 	STRUCT_DECL(laioc_create, create_arg);
131 	uint16_t nports;
132 	laioc_port_t *ports = NULL;
133 	uint32_t policy;
134 	boolean_t mac_fixed;
135 	uchar_t mac_addr[ETHERADDRL];
136 	aggr_lacp_mode_t lacp_mode;
137 	aggr_lacp_timer_t lacp_timer;
138 	int rc;
139 
140 	STRUCT_INIT(create_arg, mode);
141 
142 	if (copyin(arg, STRUCT_BUF(create_arg), STRUCT_SIZE(create_arg)) != 0)
143 		return (EFAULT);
144 
145 	nports = STRUCT_FGET(create_arg, lc_nports);
146 	if (nports > AGGR_MAX_PORTS)
147 		return (EINVAL);
148 
149 	policy = STRUCT_FGET(create_arg, lc_policy);
150 	lacp_mode = STRUCT_FGET(create_arg, lc_lacp_mode);
151 	lacp_timer = STRUCT_FGET(create_arg, lc_lacp_timer);
152 
153 	ports = kmem_alloc(nports * sizeof (laioc_port_t), KM_SLEEP);
154 
155 	if (copyin(STRUCT_FGETP(create_arg, lc_ports), ports,
156 	    nports * sizeof (laioc_port_t)) != 0) {
157 		rc = EFAULT;
158 		goto bail;
159 	}
160 
161 	bcopy(STRUCT_FGET(create_arg, lc_mac), mac_addr, ETHERADDRL);
162 	mac_fixed = STRUCT_FGET(create_arg, lc_mac_fixed);
163 
164 	rc = aggr_grp_create(STRUCT_FGET(create_arg, lc_key),
165 	    nports, ports, policy, mac_fixed, mac_addr, lacp_mode, lacp_timer);
166 
167 bail:
168 	kmem_free(ports, nports * sizeof (laioc_port_t));
169 	return (rc);
170 }
171 
172 /* ARGSUSED */
173 static int
174 aggr_ioc_delete(int cmd, void *arg, int mode)
175 {
176 	STRUCT_DECL(laioc_delete, delete_arg);
177 
178 	STRUCT_INIT(delete_arg, mode);
179 
180 	if (copyin(arg, STRUCT_BUF(delete_arg), STRUCT_SIZE(delete_arg)) != 0)
181 		return (EFAULT);
182 
183 	return (aggr_grp_delete(STRUCT_FGET(delete_arg, ld_key)));
184 }
185 
186 typedef struct aggr_ioc_info_state {
187 	uint32_t bytes_left;
188 	uchar_t *where;			/* in user buffer */
189 } aggr_ioc_info_state_t;
190 
191 static int
192 aggr_ioc_info_new_grp(void *arg, uint32_t key, uchar_t *mac,
193     boolean_t mac_fixed, uint32_t policy, uint32_t nports,
194     aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer)
195 {
196 	aggr_ioc_info_state_t *state = arg;
197 	laioc_info_group_t grp;
198 
199 	if (state->bytes_left < sizeof (grp))
200 		return (ENOSPC);
201 
202 	grp.lg_key = key;
203 	bcopy(mac, grp.lg_mac, ETHERADDRL);
204 	grp.lg_mac_fixed = mac_fixed;
205 	grp.lg_policy = policy;
206 	grp.lg_nports = nports;
207 	grp.lg_lacp_mode = lacp_mode;
208 	grp.lg_lacp_timer = lacp_timer;
209 
210 	if (copyout(&grp, state->where, sizeof (grp)) != 0)
211 		return (EFAULT);
212 
213 	state->where += sizeof (grp);
214 	state->bytes_left -= sizeof (grp);
215 
216 	return (0);
217 }
218 
219 static int
220 aggr_ioc_info_new_port(void *arg, char *devname, uint32_t portnum,
221     uchar_t *mac, aggr_port_state_t portstate, aggr_lacp_state_t *lacp_state)
222 {
223 	aggr_ioc_info_state_t *state = arg;
224 	laioc_info_port_t port;
225 
226 	if (state->bytes_left < sizeof (port))
227 		return (ENOSPC);
228 
229 	bcopy(devname, port.lp_devname, MAXNAMELEN + 1);
230 	port.lp_port = portnum;
231 	bcopy(mac, port.lp_mac, ETHERADDRL);
232 	port.lp_state = portstate;
233 	port.lp_lacp_state = *lacp_state;
234 
235 	if (copyout(&port, state->where, sizeof (port)) != 0)
236 		return (EFAULT);
237 
238 	state->where += sizeof (port);
239 	state->bytes_left -= sizeof (port);
240 
241 	return (0);
242 }
243 
244 /*ARGSUSED*/
245 static int
246 aggr_ioc_info(int cmd, void *arg, int mode)
247 {
248 	laioc_info_t info_arg;
249 	uint32_t ngroups, group_key;
250 	int rc;
251 	aggr_ioc_info_state_t state;
252 
253 	if (copyin(arg, &info_arg, sizeof (info_arg)) != 0)
254 		return (EFAULT);
255 
256 	/*
257 	 * Key of the group to return. If zero, the call returns information
258 	 * regarding all groups currently defined.
259 	 */
260 	group_key = info_arg.li_group_key;
261 
262 	state.bytes_left = info_arg.li_bufsize - sizeof (laioc_info_t);
263 	state.where = (uchar_t *)arg + sizeof (laioc_info_t);
264 
265 	rc = aggr_grp_info(&ngroups, group_key, &state, aggr_ioc_info_new_grp,
266 	    aggr_ioc_info_new_port);
267 	if (rc == 0) {
268 		info_arg.li_ngroups = ngroups;
269 		if (copyout(&info_arg, arg, sizeof (info_arg)) != 0)
270 			return (EFAULT);
271 	}
272 	return (rc);
273 }
274 
275 /*ARGSUSED*/
276 static int
277 aggr_ioc_add_remove(int cmd, void *arg, int mode)
278 {
279 	STRUCT_DECL(laioc_add_rem, add_rem_arg);
280 	uint16_t nports;
281 	laioc_port_t *ports = NULL;
282 	int rc;
283 
284 	STRUCT_INIT(add_rem_arg, mode);
285 
286 	if (copyin(arg, STRUCT_BUF(add_rem_arg), STRUCT_SIZE(add_rem_arg)) != 0)
287 		return (EFAULT);
288 
289 	nports = STRUCT_FGET(add_rem_arg, la_nports);
290 	if (nports > AGGR_MAX_PORTS)
291 		return (EINVAL);
292 
293 	ports = kmem_alloc(nports * sizeof (laioc_port_t), KM_SLEEP);
294 
295 	if (copyin(STRUCT_FGETP(add_rem_arg, la_ports), ports,
296 	    nports * sizeof (laioc_port_t)) != 0) {
297 		rc = EFAULT;
298 		goto bail;
299 	}
300 
301 	switch (cmd) {
302 	case LAIOC_ADD:
303 		rc = aggr_grp_add_ports(STRUCT_FGET(add_rem_arg, la_key),
304 		    nports, ports);
305 		break;
306 	case LAIOC_REMOVE:
307 		rc = aggr_grp_rem_ports(STRUCT_FGET(add_rem_arg, la_key),
308 		    nports, ports);
309 		break;
310 	default:
311 		rc = EINVAL;
312 	}
313 
314 bail:
315 	if (ports != NULL)
316 		kmem_free(ports, nports * sizeof (laioc_port_t));
317 	return (rc);
318 }
319 
320 /*ARGSUSED*/
321 static int
322 aggr_ioc_remove(void *arg, int mode)
323 {
324 	STRUCT_DECL(laioc_add_rem, rem_arg);
325 	uint16_t nports;
326 	laioc_port_t *ports = NULL;
327 	int rc;
328 
329 	STRUCT_INIT(rem_arg, mode);
330 
331 	if (copyin(arg, STRUCT_BUF(rem_arg), STRUCT_SIZE(rem_arg)) != 0)
332 		return (EFAULT);
333 
334 	nports = STRUCT_FGET(rem_arg, la_nports);
335 	if (nports > AGGR_MAX_PORTS)
336 		return (EINVAL);
337 
338 	ports = kmem_alloc(nports * sizeof (laioc_port_t), KM_SLEEP);
339 
340 	if (copyin(STRUCT_FGETP(rem_arg, la_ports), ports,
341 	    nports * sizeof (laioc_port_t)) != 0) {
342 		rc = EFAULT;
343 		goto bail;
344 	}
345 
346 	rc = aggr_grp_rem_ports(STRUCT_FGET(rem_arg, la_key),
347 	    nports, ports);
348 
349 bail:
350 	if (ports != NULL)
351 		kmem_free(ports, nports * sizeof (laioc_port_t));
352 	return (rc);
353 }
354 
355 /*ARGSUSED*/
356 int
357 aggr_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rv)
358 {
359 	int i;
360 
361 	for (i = 0; i < sizeof (ioc_cmd) / sizeof (ioc_cmd_t); i++) {
362 		if (cmd == ioc_cmd[i].ic_cmd)
363 			return (ioc_cmd[i].ic_func(cmd, (void *)arg, mode));
364 	}
365 
366 	return (EINVAL);
367 }
368