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
52311Sseb * Common Development and Distribution License (the "License").
62311Sseb * 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*10616SSebastien.Roy@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate * IEEE 802.3ad Link Aggregation -- IOCTL processing.
280Sstevel@tonic-gate */
290Sstevel@tonic-gate
300Sstevel@tonic-gate #include <sys/aggr.h>
310Sstevel@tonic-gate #include <sys/aggr_impl.h>
32*10616SSebastien.Roy@Sun.COM #include <sys/policy.h>
330Sstevel@tonic-gate
340Sstevel@tonic-gate /*
350Sstevel@tonic-gate * Process a LAIOC_MODIFY request.
360Sstevel@tonic-gate */
377408SSebastien.Roy@Sun.COM /* ARGSUSED */
380Sstevel@tonic-gate static int
aggr_ioc_modify(void * karg,intptr_t arg,int mode,cred_t * cred,int * rvalp)398275SEric Cheng aggr_ioc_modify(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
400Sstevel@tonic-gate {
417408SSebastien.Roy@Sun.COM laioc_modify_t *modify_arg = karg;
420Sstevel@tonic-gate uint32_t policy;
430Sstevel@tonic-gate boolean_t mac_fixed;
440Sstevel@tonic-gate uchar_t mac_addr[ETHERADDRL];
450Sstevel@tonic-gate uint8_t modify_mask_arg, modify_mask = 0;
460Sstevel@tonic-gate aggr_lacp_mode_t lacp_mode;
470Sstevel@tonic-gate aggr_lacp_timer_t lacp_timer;
480Sstevel@tonic-gate
497408SSebastien.Roy@Sun.COM modify_mask_arg = modify_arg->lu_modify_mask;
500Sstevel@tonic-gate
510Sstevel@tonic-gate if (modify_mask_arg & LAIOC_MODIFY_POLICY) {
520Sstevel@tonic-gate modify_mask |= AGGR_MODIFY_POLICY;
537408SSebastien.Roy@Sun.COM policy = modify_arg->lu_policy;
540Sstevel@tonic-gate }
550Sstevel@tonic-gate
560Sstevel@tonic-gate if (modify_mask_arg & LAIOC_MODIFY_MAC) {
570Sstevel@tonic-gate modify_mask |= AGGR_MODIFY_MAC;
587408SSebastien.Roy@Sun.COM bcopy(modify_arg->lu_mac, mac_addr, ETHERADDRL);
597408SSebastien.Roy@Sun.COM mac_fixed = modify_arg->lu_mac_fixed;
600Sstevel@tonic-gate }
610Sstevel@tonic-gate
620Sstevel@tonic-gate if (modify_mask_arg & LAIOC_MODIFY_LACP_MODE) {
630Sstevel@tonic-gate modify_mask |= AGGR_MODIFY_LACP_MODE;
647408SSebastien.Roy@Sun.COM lacp_mode = modify_arg->lu_lacp_mode;
650Sstevel@tonic-gate }
660Sstevel@tonic-gate
670Sstevel@tonic-gate if (modify_mask_arg & LAIOC_MODIFY_LACP_TIMER) {
680Sstevel@tonic-gate modify_mask |= AGGR_MODIFY_LACP_TIMER;
697408SSebastien.Roy@Sun.COM lacp_timer = modify_arg->lu_lacp_timer;
700Sstevel@tonic-gate }
710Sstevel@tonic-gate
728275SEric Cheng return (aggr_grp_modify(modify_arg->lu_linkid, modify_mask, policy,
738275SEric Cheng mac_fixed, mac_addr, lacp_mode, lacp_timer));
740Sstevel@tonic-gate }
750Sstevel@tonic-gate
760Sstevel@tonic-gate /*
770Sstevel@tonic-gate * Process a LAIOC_CREATE request.
780Sstevel@tonic-gate */
797408SSebastien.Roy@Sun.COM /* ARGSUSED */
800Sstevel@tonic-gate static int
aggr_ioc_create(void * karg,intptr_t arg,int mode,cred_t * cred,int * rvalp)818275SEric Cheng aggr_ioc_create(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
820Sstevel@tonic-gate {
837408SSebastien.Roy@Sun.COM laioc_create_t *create_arg = karg;
840Sstevel@tonic-gate uint16_t nports;
850Sstevel@tonic-gate laioc_port_t *ports = NULL;
867408SSebastien.Roy@Sun.COM size_t ports_size;
870Sstevel@tonic-gate uint32_t policy;
880Sstevel@tonic-gate boolean_t mac_fixed;
895895Syz147064 boolean_t force;
900Sstevel@tonic-gate uchar_t mac_addr[ETHERADDRL];
910Sstevel@tonic-gate aggr_lacp_mode_t lacp_mode;
920Sstevel@tonic-gate aggr_lacp_timer_t lacp_timer;
937408SSebastien.Roy@Sun.COM int rc;
940Sstevel@tonic-gate
957408SSebastien.Roy@Sun.COM nports = create_arg->lc_nports;
960Sstevel@tonic-gate if (nports > AGGR_MAX_PORTS)
970Sstevel@tonic-gate return (EINVAL);
980Sstevel@tonic-gate
997408SSebastien.Roy@Sun.COM policy = create_arg->lc_policy;
1007408SSebastien.Roy@Sun.COM lacp_mode = create_arg->lc_lacp_mode;
1017408SSebastien.Roy@Sun.COM lacp_timer = create_arg->lc_lacp_timer;
1020Sstevel@tonic-gate
1037408SSebastien.Roy@Sun.COM ports_size = nports * sizeof (laioc_port_t);
1047408SSebastien.Roy@Sun.COM ports = kmem_alloc(ports_size, KM_SLEEP);
1050Sstevel@tonic-gate
1067408SSebastien.Roy@Sun.COM if (ddi_copyin((uchar_t *)arg + sizeof (*create_arg), ports,
1077408SSebastien.Roy@Sun.COM ports_size, mode) != 0) {
1087408SSebastien.Roy@Sun.COM rc = EFAULT;
1097408SSebastien.Roy@Sun.COM goto done;
1107408SSebastien.Roy@Sun.COM }
1110Sstevel@tonic-gate
1127408SSebastien.Roy@Sun.COM bcopy(create_arg->lc_mac, mac_addr, ETHERADDRL);
1137408SSebastien.Roy@Sun.COM mac_fixed = create_arg->lc_mac_fixed;
1147408SSebastien.Roy@Sun.COM force = create_arg->lc_force;
1150Sstevel@tonic-gate
1167408SSebastien.Roy@Sun.COM rc = aggr_grp_create(create_arg->lc_linkid, create_arg->lc_key, nports,
117*10616SSebastien.Roy@Sun.COM ports, policy, mac_fixed, force, mac_addr, lacp_mode, lacp_timer,
118*10616SSebastien.Roy@Sun.COM cred);
1197408SSebastien.Roy@Sun.COM
1207408SSebastien.Roy@Sun.COM done:
1217408SSebastien.Roy@Sun.COM kmem_free(ports, ports_size);
1220Sstevel@tonic-gate return (rc);
1230Sstevel@tonic-gate }
1240Sstevel@tonic-gate
1257408SSebastien.Roy@Sun.COM /* ARGSUSED */
1260Sstevel@tonic-gate static int
aggr_ioc_delete(void * karg,intptr_t arg,int mode,cred_t * cred,int * rvalp)1278275SEric Cheng aggr_ioc_delete(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
1280Sstevel@tonic-gate {
1297408SSebastien.Roy@Sun.COM laioc_delete_t *delete_arg = karg;
1300Sstevel@tonic-gate
131*10616SSebastien.Roy@Sun.COM return (aggr_grp_delete(delete_arg->ld_linkid, cred));
1320Sstevel@tonic-gate }
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate typedef struct aggr_ioc_info_state {
1357408SSebastien.Roy@Sun.COM uint32_t bytes_left;
1367408SSebastien.Roy@Sun.COM uchar_t *where; /* in user buffer */
1377408SSebastien.Roy@Sun.COM int mode;
1380Sstevel@tonic-gate } aggr_ioc_info_state_t;
1390Sstevel@tonic-gate
1400Sstevel@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)1415895Syz147064 aggr_ioc_info_new_grp(void *arg, datalink_id_t linkid, uint32_t key,
1425895Syz147064 uchar_t *mac, boolean_t mac_fixed, boolean_t force, uint32_t policy,
1435895Syz147064 uint32_t nports, aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer)
1440Sstevel@tonic-gate {
1450Sstevel@tonic-gate aggr_ioc_info_state_t *state = arg;
1460Sstevel@tonic-gate laioc_info_group_t grp;
1470Sstevel@tonic-gate
1480Sstevel@tonic-gate if (state->bytes_left < sizeof (grp))
1490Sstevel@tonic-gate return (ENOSPC);
1500Sstevel@tonic-gate
1515895Syz147064 grp.lg_linkid = linkid;
1520Sstevel@tonic-gate grp.lg_key = key;
1530Sstevel@tonic-gate bcopy(mac, grp.lg_mac, ETHERADDRL);
1540Sstevel@tonic-gate grp.lg_mac_fixed = mac_fixed;
1555895Syz147064 grp.lg_force = force;
1560Sstevel@tonic-gate grp.lg_policy = policy;
1570Sstevel@tonic-gate grp.lg_nports = nports;
1580Sstevel@tonic-gate grp.lg_lacp_mode = lacp_mode;
1590Sstevel@tonic-gate grp.lg_lacp_timer = lacp_timer;
1600Sstevel@tonic-gate
1617408SSebastien.Roy@Sun.COM if (ddi_copyout(&grp, state->where, sizeof (grp), state->mode) != 0)
1627408SSebastien.Roy@Sun.COM return (EFAULT);
1637408SSebastien.Roy@Sun.COM
1640Sstevel@tonic-gate state->where += sizeof (grp);
1650Sstevel@tonic-gate state->bytes_left -= sizeof (grp);
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate return (0);
1680Sstevel@tonic-gate }
1690Sstevel@tonic-gate
1700Sstevel@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)1715895Syz147064 aggr_ioc_info_new_port(void *arg, datalink_id_t linkid, uchar_t *mac,
1722311Sseb aggr_port_state_t portstate, aggr_lacp_state_t *lacp_state)
1730Sstevel@tonic-gate {
1740Sstevel@tonic-gate aggr_ioc_info_state_t *state = arg;
1750Sstevel@tonic-gate laioc_info_port_t port;
1760Sstevel@tonic-gate
1770Sstevel@tonic-gate if (state->bytes_left < sizeof (port))
1780Sstevel@tonic-gate return (ENOSPC);
1790Sstevel@tonic-gate
1805895Syz147064 port.lp_linkid = linkid;
1810Sstevel@tonic-gate bcopy(mac, port.lp_mac, ETHERADDRL);
1820Sstevel@tonic-gate port.lp_state = portstate;
1830Sstevel@tonic-gate port.lp_lacp_state = *lacp_state;
1840Sstevel@tonic-gate
1857408SSebastien.Roy@Sun.COM if (ddi_copyout(&port, state->where, sizeof (port), state->mode) != 0)
1867408SSebastien.Roy@Sun.COM return (EFAULT);
1877408SSebastien.Roy@Sun.COM
1880Sstevel@tonic-gate state->where += sizeof (port);
1890Sstevel@tonic-gate state->bytes_left -= sizeof (port);
1900Sstevel@tonic-gate
1910Sstevel@tonic-gate return (0);
1920Sstevel@tonic-gate }
1930Sstevel@tonic-gate
1940Sstevel@tonic-gate /*ARGSUSED*/
1950Sstevel@tonic-gate static int
aggr_ioc_info(void * karg,intptr_t arg,int mode,cred_t * cred,int * rvalp)1968275SEric Cheng aggr_ioc_info(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
1970Sstevel@tonic-gate {
1987408SSebastien.Roy@Sun.COM laioc_info_t *info_argp = karg;
1990Sstevel@tonic-gate aggr_ioc_info_state_t state;
2000Sstevel@tonic-gate
2017408SSebastien.Roy@Sun.COM state.bytes_left = info_argp->li_bufsize - sizeof (laioc_info_t);
2027408SSebastien.Roy@Sun.COM state.where = (uchar_t *)arg + sizeof (laioc_info_t);
2037408SSebastien.Roy@Sun.COM state.mode = mode;
2040Sstevel@tonic-gate
205*10616SSebastien.Roy@Sun.COM return (aggr_grp_info(info_argp->li_group_linkid, &state,
206*10616SSebastien.Roy@Sun.COM aggr_ioc_info_new_grp, aggr_ioc_info_new_port, cred));
2070Sstevel@tonic-gate }
2080Sstevel@tonic-gate
2090Sstevel@tonic-gate static int
aggr_ioc_add_remove(laioc_add_rem_t * add_rem_arg,intptr_t arg,int cmd,int mode)2107408SSebastien.Roy@Sun.COM aggr_ioc_add_remove(laioc_add_rem_t *add_rem_arg, intptr_t arg, int cmd,
2117408SSebastien.Roy@Sun.COM int mode)
2120Sstevel@tonic-gate {
2137408SSebastien.Roy@Sun.COM uint16_t nports;
2140Sstevel@tonic-gate laioc_port_t *ports = NULL;
2157408SSebastien.Roy@Sun.COM size_t ports_size;
2167408SSebastien.Roy@Sun.COM int rc;
2170Sstevel@tonic-gate
2187408SSebastien.Roy@Sun.COM nports = add_rem_arg->la_nports;
2190Sstevel@tonic-gate if (nports > AGGR_MAX_PORTS)
2200Sstevel@tonic-gate return (EINVAL);
2210Sstevel@tonic-gate
2227408SSebastien.Roy@Sun.COM ports_size = nports * sizeof (laioc_port_t);
2237408SSebastien.Roy@Sun.COM ports = kmem_alloc(ports_size, KM_SLEEP);
2247408SSebastien.Roy@Sun.COM if (ddi_copyin((uchar_t *)arg + sizeof (*add_rem_arg), ports,
2257408SSebastien.Roy@Sun.COM ports_size, mode) != 0) {
2267408SSebastien.Roy@Sun.COM rc = EFAULT;
2277408SSebastien.Roy@Sun.COM goto done;
2287408SSebastien.Roy@Sun.COM }
2290Sstevel@tonic-gate
2307408SSebastien.Roy@Sun.COM switch (cmd) {
2317408SSebastien.Roy@Sun.COM case LAIOC_ADD:
2327408SSebastien.Roy@Sun.COM rc = aggr_grp_add_ports(add_rem_arg->la_linkid, nports,
2337408SSebastien.Roy@Sun.COM add_rem_arg->la_force, ports);
2347408SSebastien.Roy@Sun.COM break;
2357408SSebastien.Roy@Sun.COM case LAIOC_REMOVE:
2367408SSebastien.Roy@Sun.COM rc = aggr_grp_rem_ports(add_rem_arg->la_linkid, nports, ports);
2377408SSebastien.Roy@Sun.COM break;
2387408SSebastien.Roy@Sun.COM }
2397408SSebastien.Roy@Sun.COM
2407408SSebastien.Roy@Sun.COM done:
2417408SSebastien.Roy@Sun.COM kmem_free(ports, ports_size);
2427408SSebastien.Roy@Sun.COM return (rc);
2437408SSebastien.Roy@Sun.COM }
2440Sstevel@tonic-gate
2457408SSebastien.Roy@Sun.COM /* ARGSUSED */
2467408SSebastien.Roy@Sun.COM static int
aggr_ioc_add(void * karg,intptr_t arg,int mode,cred_t * cred,int * rvalp)2478275SEric Cheng aggr_ioc_add(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
2487408SSebastien.Roy@Sun.COM {
2497408SSebastien.Roy@Sun.COM return (aggr_ioc_add_remove(karg, arg, LAIOC_ADD, mode));
2507408SSebastien.Roy@Sun.COM }
2517408SSebastien.Roy@Sun.COM
2527408SSebastien.Roy@Sun.COM /* ARGSUSED */
2537408SSebastien.Roy@Sun.COM static int
aggr_ioc_remove(void * karg,intptr_t arg,int mode,cred_t * cred,int * rvalp)2548275SEric Cheng aggr_ioc_remove(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
2557408SSebastien.Roy@Sun.COM {
2567408SSebastien.Roy@Sun.COM return (aggr_ioc_add_remove(karg, arg, LAIOC_REMOVE, mode));
2577408SSebastien.Roy@Sun.COM }
2580Sstevel@tonic-gate
2597408SSebastien.Roy@Sun.COM static dld_ioc_info_t aggr_ioc_list[] = {
2608275SEric Cheng {LAIOC_CREATE, DLDCOPYIN, sizeof (laioc_create_t), aggr_ioc_create,
261*10616SSebastien.Roy@Sun.COM secpolicy_dl_config},
2628275SEric Cheng {LAIOC_DELETE, DLDCOPYIN, sizeof (laioc_delete_t), aggr_ioc_delete,
263*10616SSebastien.Roy@Sun.COM secpolicy_dl_config},
264*10616SSebastien.Roy@Sun.COM {LAIOC_INFO, DLDCOPYINOUT, sizeof (laioc_info_t), aggr_ioc_info, NULL},
2658275SEric Cheng {LAIOC_ADD, DLDCOPYIN, sizeof (laioc_add_rem_t), aggr_ioc_add,
266*10616SSebastien.Roy@Sun.COM secpolicy_dl_config},
2678275SEric Cheng {LAIOC_REMOVE, DLDCOPYIN, sizeof (laioc_add_rem_t), aggr_ioc_remove,
268*10616SSebastien.Roy@Sun.COM secpolicy_dl_config},
2698275SEric Cheng {LAIOC_MODIFY, DLDCOPYIN, sizeof (laioc_modify_t), aggr_ioc_modify,
270*10616SSebastien.Roy@Sun.COM secpolicy_dl_config}
2717408SSebastien.Roy@Sun.COM };
2727408SSebastien.Roy@Sun.COM
2737408SSebastien.Roy@Sun.COM int
aggr_ioc_init(void)2747408SSebastien.Roy@Sun.COM aggr_ioc_init(void)
2757408SSebastien.Roy@Sun.COM {
2767408SSebastien.Roy@Sun.COM return (dld_ioc_register(AGGR_IOC, aggr_ioc_list,
2777408SSebastien.Roy@Sun.COM DLDIOCCNT(aggr_ioc_list)));
2780Sstevel@tonic-gate }
2790Sstevel@tonic-gate
280269Sericheng void
aggr_ioc_fini(void)2817408SSebastien.Roy@Sun.COM aggr_ioc_fini(void)
2820Sstevel@tonic-gate {
2837408SSebastien.Roy@Sun.COM dld_ioc_unregister(AGGR_IOC);
2840Sstevel@tonic-gate }
285