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 /*
222b24ab6bSSebastien 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>
322b24ab6bSSebastien 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
49*34a4e6b5SToomas Soome policy = 0;
50*34a4e6b5SToomas Soome mac_fixed = B_FALSE;
51*34a4e6b5SToomas Soome lacp_mode = AGGR_LACP_OFF;
52*34a4e6b5SToomas Soome lacp_timer = AGGR_LACP_TIMER_LONG;
53*34a4e6b5SToomas Soome
54eae72b5bSSebastien Roy modify_mask_arg = modify_arg->lu_modify_mask;
557c478bd9Sstevel@tonic-gate
567c478bd9Sstevel@tonic-gate if (modify_mask_arg & LAIOC_MODIFY_POLICY) {
577c478bd9Sstevel@tonic-gate modify_mask |= AGGR_MODIFY_POLICY;
58eae72b5bSSebastien Roy policy = modify_arg->lu_policy;
597c478bd9Sstevel@tonic-gate }
607c478bd9Sstevel@tonic-gate
617c478bd9Sstevel@tonic-gate if (modify_mask_arg & LAIOC_MODIFY_MAC) {
627c478bd9Sstevel@tonic-gate modify_mask |= AGGR_MODIFY_MAC;
63eae72b5bSSebastien Roy bcopy(modify_arg->lu_mac, mac_addr, ETHERADDRL);
64eae72b5bSSebastien Roy mac_fixed = modify_arg->lu_mac_fixed;
657c478bd9Sstevel@tonic-gate }
667c478bd9Sstevel@tonic-gate
677c478bd9Sstevel@tonic-gate if (modify_mask_arg & LAIOC_MODIFY_LACP_MODE) {
687c478bd9Sstevel@tonic-gate modify_mask |= AGGR_MODIFY_LACP_MODE;
69eae72b5bSSebastien Roy lacp_mode = modify_arg->lu_lacp_mode;
707c478bd9Sstevel@tonic-gate }
717c478bd9Sstevel@tonic-gate
727c478bd9Sstevel@tonic-gate if (modify_mask_arg & LAIOC_MODIFY_LACP_TIMER) {
737c478bd9Sstevel@tonic-gate modify_mask |= AGGR_MODIFY_LACP_TIMER;
74eae72b5bSSebastien Roy lacp_timer = modify_arg->lu_lacp_timer;
757c478bd9Sstevel@tonic-gate }
767c478bd9Sstevel@tonic-gate
77da14cebeSEric Cheng return (aggr_grp_modify(modify_arg->lu_linkid, modify_mask, policy,
78da14cebeSEric Cheng mac_fixed, mac_addr, lacp_mode, lacp_timer));
797c478bd9Sstevel@tonic-gate }
807c478bd9Sstevel@tonic-gate
817c478bd9Sstevel@tonic-gate /*
827c478bd9Sstevel@tonic-gate * Process a LAIOC_CREATE request.
837c478bd9Sstevel@tonic-gate */
84eae72b5bSSebastien Roy /* ARGSUSED */
857c478bd9Sstevel@tonic-gate static int
aggr_ioc_create(void * karg,intptr_t arg,int mode,cred_t * cred,int * rvalp)86da14cebeSEric Cheng aggr_ioc_create(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
877c478bd9Sstevel@tonic-gate {
88eae72b5bSSebastien Roy laioc_create_t *create_arg = karg;
897c478bd9Sstevel@tonic-gate uint16_t nports;
907c478bd9Sstevel@tonic-gate laioc_port_t *ports = NULL;
91eae72b5bSSebastien Roy size_t ports_size;
927c478bd9Sstevel@tonic-gate uint32_t policy;
937c478bd9Sstevel@tonic-gate boolean_t mac_fixed;
94d62bc4baSyz boolean_t force;
957c478bd9Sstevel@tonic-gate uchar_t mac_addr[ETHERADDRL];
967c478bd9Sstevel@tonic-gate aggr_lacp_mode_t lacp_mode;
977c478bd9Sstevel@tonic-gate aggr_lacp_timer_t lacp_timer;
98eae72b5bSSebastien Roy int rc;
997c478bd9Sstevel@tonic-gate
100eae72b5bSSebastien Roy nports = create_arg->lc_nports;
1017c478bd9Sstevel@tonic-gate if (nports > AGGR_MAX_PORTS)
1027c478bd9Sstevel@tonic-gate return (EINVAL);
1037c478bd9Sstevel@tonic-gate
104eae72b5bSSebastien Roy policy = create_arg->lc_policy;
105eae72b5bSSebastien Roy lacp_mode = create_arg->lc_lacp_mode;
106eae72b5bSSebastien Roy lacp_timer = create_arg->lc_lacp_timer;
1077c478bd9Sstevel@tonic-gate
108eae72b5bSSebastien Roy ports_size = nports * sizeof (laioc_port_t);
109eae72b5bSSebastien Roy ports = kmem_alloc(ports_size, KM_SLEEP);
1107c478bd9Sstevel@tonic-gate
111eae72b5bSSebastien Roy if (ddi_copyin((uchar_t *)arg + sizeof (*create_arg), ports,
112eae72b5bSSebastien Roy ports_size, mode) != 0) {
113eae72b5bSSebastien Roy rc = EFAULT;
114eae72b5bSSebastien Roy goto done;
115eae72b5bSSebastien Roy }
1167c478bd9Sstevel@tonic-gate
117eae72b5bSSebastien Roy bcopy(create_arg->lc_mac, mac_addr, ETHERADDRL);
118eae72b5bSSebastien Roy mac_fixed = create_arg->lc_mac_fixed;
119eae72b5bSSebastien Roy force = create_arg->lc_force;
1207c478bd9Sstevel@tonic-gate
121eae72b5bSSebastien Roy rc = aggr_grp_create(create_arg->lc_linkid, create_arg->lc_key, nports,
1222b24ab6bSSebastien Roy ports, policy, mac_fixed, force, mac_addr, lacp_mode, lacp_timer,
1232b24ab6bSSebastien Roy cred);
1247c478bd9Sstevel@tonic-gate
125eae72b5bSSebastien Roy done:
126eae72b5bSSebastien Roy kmem_free(ports, ports_size);
1277c478bd9Sstevel@tonic-gate return (rc);
1287c478bd9Sstevel@tonic-gate }
1297c478bd9Sstevel@tonic-gate
130eae72b5bSSebastien Roy /* ARGSUSED */
1317c478bd9Sstevel@tonic-gate static int
aggr_ioc_delete(void * karg,intptr_t arg,int mode,cred_t * cred,int * rvalp)132da14cebeSEric Cheng aggr_ioc_delete(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
1337c478bd9Sstevel@tonic-gate {
134eae72b5bSSebastien Roy laioc_delete_t *delete_arg = karg;
1357c478bd9Sstevel@tonic-gate
1362b24ab6bSSebastien Roy return (aggr_grp_delete(delete_arg->ld_linkid, cred));
1377c478bd9Sstevel@tonic-gate }
1387c478bd9Sstevel@tonic-gate
1397c478bd9Sstevel@tonic-gate typedef struct aggr_ioc_info_state {
140eae72b5bSSebastien Roy uint32_t bytes_left;
141eae72b5bSSebastien Roy uchar_t *where; /* in user buffer */
142eae72b5bSSebastien Roy int mode;
1437c478bd9Sstevel@tonic-gate } aggr_ioc_info_state_t;
1447c478bd9Sstevel@tonic-gate
1457c478bd9Sstevel@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)146d62bc4baSyz aggr_ioc_info_new_grp(void *arg, datalink_id_t linkid, uint32_t key,
147d62bc4baSyz uchar_t *mac, boolean_t mac_fixed, boolean_t force, uint32_t policy,
148d62bc4baSyz uint32_t nports, aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer)
1497c478bd9Sstevel@tonic-gate {
1507c478bd9Sstevel@tonic-gate aggr_ioc_info_state_t *state = arg;
1517c478bd9Sstevel@tonic-gate laioc_info_group_t grp;
1527c478bd9Sstevel@tonic-gate
1537c478bd9Sstevel@tonic-gate if (state->bytes_left < sizeof (grp))
1547c478bd9Sstevel@tonic-gate return (ENOSPC);
1557c478bd9Sstevel@tonic-gate
156d62bc4baSyz grp.lg_linkid = linkid;
1577c478bd9Sstevel@tonic-gate grp.lg_key = key;
1587c478bd9Sstevel@tonic-gate bcopy(mac, grp.lg_mac, ETHERADDRL);
1597c478bd9Sstevel@tonic-gate grp.lg_mac_fixed = mac_fixed;
160d62bc4baSyz grp.lg_force = force;
1617c478bd9Sstevel@tonic-gate grp.lg_policy = policy;
1627c478bd9Sstevel@tonic-gate grp.lg_nports = nports;
1637c478bd9Sstevel@tonic-gate grp.lg_lacp_mode = lacp_mode;
1647c478bd9Sstevel@tonic-gate grp.lg_lacp_timer = lacp_timer;
1657c478bd9Sstevel@tonic-gate
166eae72b5bSSebastien Roy if (ddi_copyout(&grp, state->where, sizeof (grp), state->mode) != 0)
167eae72b5bSSebastien Roy return (EFAULT);
168eae72b5bSSebastien Roy
1697c478bd9Sstevel@tonic-gate state->where += sizeof (grp);
1707c478bd9Sstevel@tonic-gate state->bytes_left -= sizeof (grp);
1717c478bd9Sstevel@tonic-gate
1727c478bd9Sstevel@tonic-gate return (0);
1737c478bd9Sstevel@tonic-gate }
1747c478bd9Sstevel@tonic-gate
1757c478bd9Sstevel@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)176d62bc4baSyz aggr_ioc_info_new_port(void *arg, datalink_id_t linkid, uchar_t *mac,
177ba2e4443Sseb aggr_port_state_t portstate, aggr_lacp_state_t *lacp_state)
1787c478bd9Sstevel@tonic-gate {
1797c478bd9Sstevel@tonic-gate aggr_ioc_info_state_t *state = arg;
1807c478bd9Sstevel@tonic-gate laioc_info_port_t port;
1817c478bd9Sstevel@tonic-gate
1827c478bd9Sstevel@tonic-gate if (state->bytes_left < sizeof (port))
1837c478bd9Sstevel@tonic-gate return (ENOSPC);
1847c478bd9Sstevel@tonic-gate
185d62bc4baSyz port.lp_linkid = linkid;
1867c478bd9Sstevel@tonic-gate bcopy(mac, port.lp_mac, ETHERADDRL);
1877c478bd9Sstevel@tonic-gate port.lp_state = portstate;
1887c478bd9Sstevel@tonic-gate port.lp_lacp_state = *lacp_state;
1897c478bd9Sstevel@tonic-gate
190eae72b5bSSebastien Roy if (ddi_copyout(&port, state->where, sizeof (port), state->mode) != 0)
191eae72b5bSSebastien Roy return (EFAULT);
192eae72b5bSSebastien Roy
1937c478bd9Sstevel@tonic-gate state->where += sizeof (port);
1947c478bd9Sstevel@tonic-gate state->bytes_left -= sizeof (port);
1957c478bd9Sstevel@tonic-gate
1967c478bd9Sstevel@tonic-gate return (0);
1977c478bd9Sstevel@tonic-gate }
1987c478bd9Sstevel@tonic-gate
1997c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2007c478bd9Sstevel@tonic-gate static int
aggr_ioc_info(void * karg,intptr_t arg,int mode,cred_t * cred,int * rvalp)201da14cebeSEric Cheng aggr_ioc_info(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
2027c478bd9Sstevel@tonic-gate {
203eae72b5bSSebastien Roy laioc_info_t *info_argp = karg;
2047c478bd9Sstevel@tonic-gate aggr_ioc_info_state_t state;
2057c478bd9Sstevel@tonic-gate
206eae72b5bSSebastien Roy state.bytes_left = info_argp->li_bufsize - sizeof (laioc_info_t);
207eae72b5bSSebastien Roy state.where = (uchar_t *)arg + sizeof (laioc_info_t);
208eae72b5bSSebastien Roy state.mode = mode;
2097c478bd9Sstevel@tonic-gate
2102b24ab6bSSebastien Roy return (aggr_grp_info(info_argp->li_group_linkid, &state,
2112b24ab6bSSebastien Roy aggr_ioc_info_new_grp, aggr_ioc_info_new_port, cred));
2127c478bd9Sstevel@tonic-gate }
2137c478bd9Sstevel@tonic-gate
2147c478bd9Sstevel@tonic-gate static int
aggr_ioc_add_remove(laioc_add_rem_t * add_rem_arg,intptr_t arg,int cmd,int mode)215eae72b5bSSebastien Roy aggr_ioc_add_remove(laioc_add_rem_t *add_rem_arg, intptr_t arg, int cmd,
216eae72b5bSSebastien Roy int mode)
2177c478bd9Sstevel@tonic-gate {
218eae72b5bSSebastien Roy uint16_t nports;
2197c478bd9Sstevel@tonic-gate laioc_port_t *ports = NULL;
220eae72b5bSSebastien Roy size_t ports_size;
221eae72b5bSSebastien Roy int rc;
2227c478bd9Sstevel@tonic-gate
223eae72b5bSSebastien Roy nports = add_rem_arg->la_nports;
2247c478bd9Sstevel@tonic-gate if (nports > AGGR_MAX_PORTS)
2257c478bd9Sstevel@tonic-gate return (EINVAL);
2267c478bd9Sstevel@tonic-gate
227eae72b5bSSebastien Roy ports_size = nports * sizeof (laioc_port_t);
228eae72b5bSSebastien Roy ports = kmem_alloc(ports_size, KM_SLEEP);
229eae72b5bSSebastien Roy if (ddi_copyin((uchar_t *)arg + sizeof (*add_rem_arg), ports,
230eae72b5bSSebastien Roy ports_size, mode) != 0) {
231eae72b5bSSebastien Roy rc = EFAULT;
232eae72b5bSSebastien Roy goto done;
233eae72b5bSSebastien Roy }
2347c478bd9Sstevel@tonic-gate
235eae72b5bSSebastien Roy switch (cmd) {
236eae72b5bSSebastien Roy case LAIOC_ADD:
237eae72b5bSSebastien Roy rc = aggr_grp_add_ports(add_rem_arg->la_linkid, nports,
238eae72b5bSSebastien Roy add_rem_arg->la_force, ports);
239eae72b5bSSebastien Roy break;
240eae72b5bSSebastien Roy case LAIOC_REMOVE:
241eae72b5bSSebastien Roy rc = aggr_grp_rem_ports(add_rem_arg->la_linkid, nports, ports);
242eae72b5bSSebastien Roy break;
243*34a4e6b5SToomas Soome default:
244*34a4e6b5SToomas Soome rc = 0;
245*34a4e6b5SToomas Soome break;
246eae72b5bSSebastien Roy }
2477c478bd9Sstevel@tonic-gate
248eae72b5bSSebastien Roy done:
249eae72b5bSSebastien Roy kmem_free(ports, ports_size);
2507c478bd9Sstevel@tonic-gate return (rc);
2517c478bd9Sstevel@tonic-gate }
2527c478bd9Sstevel@tonic-gate
253eae72b5bSSebastien Roy /* ARGSUSED */
2547c478bd9Sstevel@tonic-gate static int
aggr_ioc_add(void * karg,intptr_t arg,int mode,cred_t * cred,int * rvalp)255da14cebeSEric Cheng aggr_ioc_add(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
2567c478bd9Sstevel@tonic-gate {
257eae72b5bSSebastien Roy return (aggr_ioc_add_remove(karg, arg, LAIOC_ADD, mode));
258eae72b5bSSebastien Roy }
2597c478bd9Sstevel@tonic-gate
260eae72b5bSSebastien Roy /* ARGSUSED */
261eae72b5bSSebastien Roy static int
aggr_ioc_remove(void * karg,intptr_t arg,int mode,cred_t * cred,int * rvalp)262da14cebeSEric Cheng aggr_ioc_remove(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
263eae72b5bSSebastien Roy {
264eae72b5bSSebastien Roy return (aggr_ioc_add_remove(karg, arg, LAIOC_REMOVE, mode));
265eae72b5bSSebastien Roy }
2667c478bd9Sstevel@tonic-gate
267eae72b5bSSebastien Roy static dld_ioc_info_t aggr_ioc_list[] = {
268da14cebeSEric Cheng {LAIOC_CREATE, DLDCOPYIN, sizeof (laioc_create_t), aggr_ioc_create,
2692b24ab6bSSebastien Roy secpolicy_dl_config},
270da14cebeSEric Cheng {LAIOC_DELETE, DLDCOPYIN, sizeof (laioc_delete_t), aggr_ioc_delete,
2712b24ab6bSSebastien Roy secpolicy_dl_config},
2722b24ab6bSSebastien Roy {LAIOC_INFO, DLDCOPYINOUT, sizeof (laioc_info_t), aggr_ioc_info, NULL},
273da14cebeSEric Cheng {LAIOC_ADD, DLDCOPYIN, sizeof (laioc_add_rem_t), aggr_ioc_add,
2742b24ab6bSSebastien Roy secpolicy_dl_config},
275da14cebeSEric Cheng {LAIOC_REMOVE, DLDCOPYIN, sizeof (laioc_add_rem_t), aggr_ioc_remove,
2762b24ab6bSSebastien Roy secpolicy_dl_config},
277da14cebeSEric Cheng {LAIOC_MODIFY, DLDCOPYIN, sizeof (laioc_modify_t), aggr_ioc_modify,
2782b24ab6bSSebastien Roy secpolicy_dl_config}
279eae72b5bSSebastien Roy };
280eae72b5bSSebastien Roy
281eae72b5bSSebastien Roy int
aggr_ioc_init(void)282eae72b5bSSebastien Roy aggr_ioc_init(void)
283eae72b5bSSebastien Roy {
284eae72b5bSSebastien Roy return (dld_ioc_register(AGGR_IOC, aggr_ioc_list,
285eae72b5bSSebastien Roy DLDIOCCNT(aggr_ioc_list)));
2867c478bd9Sstevel@tonic-gate }
2877c478bd9Sstevel@tonic-gate
288210db224Sericheng void
aggr_ioc_fini(void)289eae72b5bSSebastien Roy aggr_ioc_fini(void)
2907c478bd9Sstevel@tonic-gate {
291eae72b5bSSebastien Roy dld_ioc_unregister(AGGR_IOC);
2927c478bd9Sstevel@tonic-gate }
293