17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5ba2e4443Sseb * Common Development and Distribution License (the "License").
6ba2e4443Sseb * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22*2b24ab6bSSebastien Roy * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate * IEEE 802.3ad Link Aggregation -- IOCTL processing.
287c478bd9Sstevel@tonic-gate */
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate #include <sys/aggr.h>
317c478bd9Sstevel@tonic-gate #include <sys/aggr_impl.h>
32*2b24ab6bSSebastien Roy #include <sys/policy.h>
337c478bd9Sstevel@tonic-gate
347c478bd9Sstevel@tonic-gate /*
357c478bd9Sstevel@tonic-gate * Process a LAIOC_MODIFY request.
367c478bd9Sstevel@tonic-gate */
37eae72b5bSSebastien Roy /* ARGSUSED */
387c478bd9Sstevel@tonic-gate static int
aggr_ioc_modify(void * karg,intptr_t arg,int mode,cred_t * cred,int * rvalp)39da14cebeSEric Cheng aggr_ioc_modify(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
407c478bd9Sstevel@tonic-gate {
41eae72b5bSSebastien Roy laioc_modify_t *modify_arg = karg;
427c478bd9Sstevel@tonic-gate uint32_t policy;
437c478bd9Sstevel@tonic-gate boolean_t mac_fixed;
447c478bd9Sstevel@tonic-gate uchar_t mac_addr[ETHERADDRL];
457c478bd9Sstevel@tonic-gate uint8_t modify_mask_arg, modify_mask = 0;
467c478bd9Sstevel@tonic-gate aggr_lacp_mode_t lacp_mode;
477c478bd9Sstevel@tonic-gate aggr_lacp_timer_t lacp_timer;
487c478bd9Sstevel@tonic-gate
49eae72b5bSSebastien Roy modify_mask_arg = modify_arg->lu_modify_mask;
507c478bd9Sstevel@tonic-gate
517c478bd9Sstevel@tonic-gate if (modify_mask_arg & LAIOC_MODIFY_POLICY) {
527c478bd9Sstevel@tonic-gate modify_mask |= AGGR_MODIFY_POLICY;
53eae72b5bSSebastien Roy policy = modify_arg->lu_policy;
547c478bd9Sstevel@tonic-gate }
557c478bd9Sstevel@tonic-gate
567c478bd9Sstevel@tonic-gate if (modify_mask_arg & LAIOC_MODIFY_MAC) {
577c478bd9Sstevel@tonic-gate modify_mask |= AGGR_MODIFY_MAC;
58eae72b5bSSebastien Roy bcopy(modify_arg->lu_mac, mac_addr, ETHERADDRL);
59eae72b5bSSebastien Roy mac_fixed = modify_arg->lu_mac_fixed;
607c478bd9Sstevel@tonic-gate }
617c478bd9Sstevel@tonic-gate
627c478bd9Sstevel@tonic-gate if (modify_mask_arg & LAIOC_MODIFY_LACP_MODE) {
637c478bd9Sstevel@tonic-gate modify_mask |= AGGR_MODIFY_LACP_MODE;
64eae72b5bSSebastien Roy lacp_mode = modify_arg->lu_lacp_mode;
657c478bd9Sstevel@tonic-gate }
667c478bd9Sstevel@tonic-gate
677c478bd9Sstevel@tonic-gate if (modify_mask_arg & LAIOC_MODIFY_LACP_TIMER) {
687c478bd9Sstevel@tonic-gate modify_mask |= AGGR_MODIFY_LACP_TIMER;
69eae72b5bSSebastien Roy lacp_timer = modify_arg->lu_lacp_timer;
707c478bd9Sstevel@tonic-gate }
717c478bd9Sstevel@tonic-gate
72da14cebeSEric Cheng return (aggr_grp_modify(modify_arg->lu_linkid, modify_mask, policy,
73da14cebeSEric Cheng mac_fixed, mac_addr, lacp_mode, lacp_timer));
747c478bd9Sstevel@tonic-gate }
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate /*
777c478bd9Sstevel@tonic-gate * Process a LAIOC_CREATE request.
787c478bd9Sstevel@tonic-gate */
79eae72b5bSSebastien Roy /* ARGSUSED */
807c478bd9Sstevel@tonic-gate static int
aggr_ioc_create(void * karg,intptr_t arg,int mode,cred_t * cred,int * rvalp)81da14cebeSEric Cheng aggr_ioc_create(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
827c478bd9Sstevel@tonic-gate {
83eae72b5bSSebastien Roy laioc_create_t *create_arg = karg;
847c478bd9Sstevel@tonic-gate uint16_t nports;
857c478bd9Sstevel@tonic-gate laioc_port_t *ports = NULL;
86eae72b5bSSebastien Roy size_t ports_size;
877c478bd9Sstevel@tonic-gate uint32_t policy;
887c478bd9Sstevel@tonic-gate boolean_t mac_fixed;
89d62bc4baSyz147064 boolean_t force;
907c478bd9Sstevel@tonic-gate uchar_t mac_addr[ETHERADDRL];
917c478bd9Sstevel@tonic-gate aggr_lacp_mode_t lacp_mode;
927c478bd9Sstevel@tonic-gate aggr_lacp_timer_t lacp_timer;
93eae72b5bSSebastien Roy int rc;
947c478bd9Sstevel@tonic-gate
95eae72b5bSSebastien Roy nports = create_arg->lc_nports;
967c478bd9Sstevel@tonic-gate if (nports > AGGR_MAX_PORTS)
977c478bd9Sstevel@tonic-gate return (EINVAL);
987c478bd9Sstevel@tonic-gate
99eae72b5bSSebastien Roy policy = create_arg->lc_policy;
100eae72b5bSSebastien Roy lacp_mode = create_arg->lc_lacp_mode;
101eae72b5bSSebastien Roy lacp_timer = create_arg->lc_lacp_timer;
1027c478bd9Sstevel@tonic-gate
103eae72b5bSSebastien Roy ports_size = nports * sizeof (laioc_port_t);
104eae72b5bSSebastien Roy ports = kmem_alloc(ports_size, KM_SLEEP);
1057c478bd9Sstevel@tonic-gate
106eae72b5bSSebastien Roy if (ddi_copyin((uchar_t *)arg + sizeof (*create_arg), ports,
107eae72b5bSSebastien Roy ports_size, mode) != 0) {
108eae72b5bSSebastien Roy rc = EFAULT;
109eae72b5bSSebastien Roy goto done;
110eae72b5bSSebastien Roy }
1117c478bd9Sstevel@tonic-gate
112eae72b5bSSebastien Roy bcopy(create_arg->lc_mac, mac_addr, ETHERADDRL);
113eae72b5bSSebastien Roy mac_fixed = create_arg->lc_mac_fixed;
114eae72b5bSSebastien Roy force = create_arg->lc_force;
1157c478bd9Sstevel@tonic-gate
116eae72b5bSSebastien Roy rc = aggr_grp_create(create_arg->lc_linkid, create_arg->lc_key, nports,
117*2b24ab6bSSebastien Roy ports, policy, mac_fixed, force, mac_addr, lacp_mode, lacp_timer,
118*2b24ab6bSSebastien Roy cred);
1197c478bd9Sstevel@tonic-gate
120eae72b5bSSebastien Roy done:
121eae72b5bSSebastien Roy kmem_free(ports, ports_size);
1227c478bd9Sstevel@tonic-gate return (rc);
1237c478bd9Sstevel@tonic-gate }
1247c478bd9Sstevel@tonic-gate
125eae72b5bSSebastien Roy /* ARGSUSED */
1267c478bd9Sstevel@tonic-gate static int
aggr_ioc_delete(void * karg,intptr_t arg,int mode,cred_t * cred,int * rvalp)127da14cebeSEric Cheng aggr_ioc_delete(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
1287c478bd9Sstevel@tonic-gate {
129eae72b5bSSebastien Roy laioc_delete_t *delete_arg = karg;
1307c478bd9Sstevel@tonic-gate
131*2b24ab6bSSebastien Roy return (aggr_grp_delete(delete_arg->ld_linkid, cred));
1327c478bd9Sstevel@tonic-gate }
1337c478bd9Sstevel@tonic-gate
1347c478bd9Sstevel@tonic-gate typedef struct aggr_ioc_info_state {
1357c478bd9Sstevel@tonic-gate uint32_t bytes_left;
136eae72b5bSSebastien Roy uchar_t *where; /* in user buffer */
137eae72b5bSSebastien Roy int mode;
1387c478bd9Sstevel@tonic-gate } aggr_ioc_info_state_t;
1397c478bd9Sstevel@tonic-gate
1407c478bd9Sstevel@tonic-gate static int
aggr_ioc_info_new_grp(void * arg,datalink_id_t linkid,uint32_t key,uchar_t * mac,boolean_t mac_fixed,boolean_t force,uint32_t policy,uint32_t nports,aggr_lacp_mode_t lacp_mode,aggr_lacp_timer_t lacp_timer)141d62bc4baSyz147064 aggr_ioc_info_new_grp(void *arg, datalink_id_t linkid, uint32_t key,
142d62bc4baSyz147064 uchar_t *mac, boolean_t mac_fixed, boolean_t force, uint32_t policy,
143d62bc4baSyz147064 uint32_t nports, aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer)
1447c478bd9Sstevel@tonic-gate {
1457c478bd9Sstevel@tonic-gate aggr_ioc_info_state_t *state = arg;
1467c478bd9Sstevel@tonic-gate laioc_info_group_t grp;
1477c478bd9Sstevel@tonic-gate
1487c478bd9Sstevel@tonic-gate if (state->bytes_left < sizeof (grp))
1497c478bd9Sstevel@tonic-gate return (ENOSPC);
1507c478bd9Sstevel@tonic-gate
151d62bc4baSyz147064 grp.lg_linkid = linkid;
1527c478bd9Sstevel@tonic-gate grp.lg_key = key;
1537c478bd9Sstevel@tonic-gate bcopy(mac, grp.lg_mac, ETHERADDRL);
1547c478bd9Sstevel@tonic-gate grp.lg_mac_fixed = mac_fixed;
155d62bc4baSyz147064 grp.lg_force = force;
1567c478bd9Sstevel@tonic-gate grp.lg_policy = policy;
1577c478bd9Sstevel@tonic-gate grp.lg_nports = nports;
1587c478bd9Sstevel@tonic-gate grp.lg_lacp_mode = lacp_mode;
1597c478bd9Sstevel@tonic-gate grp.lg_lacp_timer = lacp_timer;
1607c478bd9Sstevel@tonic-gate
161eae72b5bSSebastien Roy if (ddi_copyout(&grp, state->where, sizeof (grp), state->mode) != 0)
162eae72b5bSSebastien Roy return (EFAULT);
163eae72b5bSSebastien Roy
1647c478bd9Sstevel@tonic-gate state->where += sizeof (grp);
1657c478bd9Sstevel@tonic-gate state->bytes_left -= sizeof (grp);
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate return (0);
1687c478bd9Sstevel@tonic-gate }
1697c478bd9Sstevel@tonic-gate
1707c478bd9Sstevel@tonic-gate static int
aggr_ioc_info_new_port(void * arg,datalink_id_t linkid,uchar_t * mac,aggr_port_state_t portstate,aggr_lacp_state_t * lacp_state)171d62bc4baSyz147064 aggr_ioc_info_new_port(void *arg, datalink_id_t linkid, uchar_t *mac,
172ba2e4443Sseb aggr_port_state_t portstate, aggr_lacp_state_t *lacp_state)
1737c478bd9Sstevel@tonic-gate {
1747c478bd9Sstevel@tonic-gate aggr_ioc_info_state_t *state = arg;
1757c478bd9Sstevel@tonic-gate laioc_info_port_t port;
1767c478bd9Sstevel@tonic-gate
1777c478bd9Sstevel@tonic-gate if (state->bytes_left < sizeof (port))
1787c478bd9Sstevel@tonic-gate return (ENOSPC);
1797c478bd9Sstevel@tonic-gate
180d62bc4baSyz147064 port.lp_linkid = linkid;
1817c478bd9Sstevel@tonic-gate bcopy(mac, port.lp_mac, ETHERADDRL);
1827c478bd9Sstevel@tonic-gate port.lp_state = portstate;
1837c478bd9Sstevel@tonic-gate port.lp_lacp_state = *lacp_state;
1847c478bd9Sstevel@tonic-gate
185eae72b5bSSebastien Roy if (ddi_copyout(&port, state->where, sizeof (port), state->mode) != 0)
186eae72b5bSSebastien Roy return (EFAULT);
187eae72b5bSSebastien Roy
1887c478bd9Sstevel@tonic-gate state->where += sizeof (port);
1897c478bd9Sstevel@tonic-gate state->bytes_left -= sizeof (port);
1907c478bd9Sstevel@tonic-gate
1917c478bd9Sstevel@tonic-gate return (0);
1927c478bd9Sstevel@tonic-gate }
1937c478bd9Sstevel@tonic-gate
1947c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1957c478bd9Sstevel@tonic-gate static int
aggr_ioc_info(void * karg,intptr_t arg,int mode,cred_t * cred,int * rvalp)196da14cebeSEric Cheng aggr_ioc_info(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
1977c478bd9Sstevel@tonic-gate {
198eae72b5bSSebastien Roy laioc_info_t *info_argp = karg;
1997c478bd9Sstevel@tonic-gate aggr_ioc_info_state_t state;
2007c478bd9Sstevel@tonic-gate
201eae72b5bSSebastien Roy state.bytes_left = info_argp->li_bufsize - sizeof (laioc_info_t);
202eae72b5bSSebastien Roy state.where = (uchar_t *)arg + sizeof (laioc_info_t);
203eae72b5bSSebastien Roy state.mode = mode;
2047c478bd9Sstevel@tonic-gate
205*2b24ab6bSSebastien Roy return (aggr_grp_info(info_argp->li_group_linkid, &state,
206*2b24ab6bSSebastien Roy aggr_ioc_info_new_grp, aggr_ioc_info_new_port, cred));
2077c478bd9Sstevel@tonic-gate }
2087c478bd9Sstevel@tonic-gate
2097c478bd9Sstevel@tonic-gate static int
aggr_ioc_add_remove(laioc_add_rem_t * add_rem_arg,intptr_t arg,int cmd,int mode)210eae72b5bSSebastien Roy aggr_ioc_add_remove(laioc_add_rem_t *add_rem_arg, intptr_t arg, int cmd,
211eae72b5bSSebastien Roy int mode)
2127c478bd9Sstevel@tonic-gate {
213eae72b5bSSebastien Roy uint16_t nports;
2147c478bd9Sstevel@tonic-gate laioc_port_t *ports = NULL;
215eae72b5bSSebastien Roy size_t ports_size;
216eae72b5bSSebastien Roy int rc;
2177c478bd9Sstevel@tonic-gate
218eae72b5bSSebastien Roy nports = add_rem_arg->la_nports;
2197c478bd9Sstevel@tonic-gate if (nports > AGGR_MAX_PORTS)
2207c478bd9Sstevel@tonic-gate return (EINVAL);
2217c478bd9Sstevel@tonic-gate
222eae72b5bSSebastien Roy ports_size = nports * sizeof (laioc_port_t);
223eae72b5bSSebastien Roy ports = kmem_alloc(ports_size, KM_SLEEP);
224eae72b5bSSebastien Roy if (ddi_copyin((uchar_t *)arg + sizeof (*add_rem_arg), ports,
225eae72b5bSSebastien Roy ports_size, mode) != 0) {
226eae72b5bSSebastien Roy rc = EFAULT;
227210db224Sericheng goto done;
2287c478bd9Sstevel@tonic-gate }
2297c478bd9Sstevel@tonic-gate
230eae72b5bSSebastien Roy switch (cmd) {
231eae72b5bSSebastien Roy case LAIOC_ADD:
232eae72b5bSSebastien Roy rc = aggr_grp_add_ports(add_rem_arg->la_linkid, nports,
233eae72b5bSSebastien Roy add_rem_arg->la_force, ports);
234210db224Sericheng break;
235eae72b5bSSebastien Roy case LAIOC_REMOVE:
236eae72b5bSSebastien Roy rc = aggr_grp_rem_ports(add_rem_arg->la_linkid, nports, ports);
237eae72b5bSSebastien Roy break;
238210db224Sericheng }
239210db224Sericheng
240210db224Sericheng done:
241eae72b5bSSebastien Roy kmem_free(ports, ports_size);
242eae72b5bSSebastien Roy return (rc);
243eae72b5bSSebastien Roy }
244eae72b5bSSebastien Roy
245eae72b5bSSebastien Roy /* ARGSUSED */
246eae72b5bSSebastien Roy static int
aggr_ioc_add(void * karg,intptr_t arg,int mode,cred_t * cred,int * rvalp)247da14cebeSEric Cheng aggr_ioc_add(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
248eae72b5bSSebastien Roy {
249eae72b5bSSebastien Roy return (aggr_ioc_add_remove(karg, arg, LAIOC_ADD, mode));
250eae72b5bSSebastien Roy }
251eae72b5bSSebastien Roy
252eae72b5bSSebastien Roy /* ARGSUSED */
253eae72b5bSSebastien Roy static int
aggr_ioc_remove(void * karg,intptr_t arg,int mode,cred_t * cred,int * rvalp)254da14cebeSEric Cheng aggr_ioc_remove(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
255eae72b5bSSebastien Roy {
256eae72b5bSSebastien Roy return (aggr_ioc_add_remove(karg, arg, LAIOC_REMOVE, mode));
257eae72b5bSSebastien Roy }
258eae72b5bSSebastien Roy
259eae72b5bSSebastien Roy static dld_ioc_info_t aggr_ioc_list[] = {
260da14cebeSEric Cheng {LAIOC_CREATE, DLDCOPYIN, sizeof (laioc_create_t), aggr_ioc_create,
261*2b24ab6bSSebastien Roy secpolicy_dl_config},
262da14cebeSEric Cheng {LAIOC_DELETE, DLDCOPYIN, sizeof (laioc_delete_t), aggr_ioc_delete,
263*2b24ab6bSSebastien Roy secpolicy_dl_config},
264*2b24ab6bSSebastien Roy {LAIOC_INFO, DLDCOPYINOUT, sizeof (laioc_info_t), aggr_ioc_info, NULL},
265da14cebeSEric Cheng {LAIOC_ADD, DLDCOPYIN, sizeof (laioc_add_rem_t), aggr_ioc_add,
266*2b24ab6bSSebastien Roy secpolicy_dl_config},
267da14cebeSEric Cheng {LAIOC_REMOVE, DLDCOPYIN, sizeof (laioc_add_rem_t), aggr_ioc_remove,
268*2b24ab6bSSebastien Roy secpolicy_dl_config},
269da14cebeSEric Cheng {LAIOC_MODIFY, DLDCOPYIN, sizeof (laioc_modify_t), aggr_ioc_modify,
270*2b24ab6bSSebastien Roy secpolicy_dl_config}
271eae72b5bSSebastien Roy };
272eae72b5bSSebastien Roy
273eae72b5bSSebastien Roy int
aggr_ioc_init(void)274eae72b5bSSebastien Roy aggr_ioc_init(void)
275eae72b5bSSebastien Roy {
276eae72b5bSSebastien Roy return (dld_ioc_register(AGGR_IOC, aggr_ioc_list,
277eae72b5bSSebastien Roy DLDIOCCNT(aggr_ioc_list)));
278eae72b5bSSebastien Roy }
279eae72b5bSSebastien Roy
280eae72b5bSSebastien Roy void
aggr_ioc_fini(void)281eae72b5bSSebastien Roy aggr_ioc_fini(void)
282eae72b5bSSebastien Roy {
283eae72b5bSSebastien Roy dld_ioc_unregister(AGGR_IOC);
2847c478bd9Sstevel@tonic-gate }
285