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 /* 228874SSebastien.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 * Data-Link Driver 280Sstevel@tonic-gate */ 290Sstevel@tonic-gate 300Sstevel@tonic-gate #include <sys/conf.h> 31269Sericheng #include <sys/mkdev.h> 32269Sericheng #include <sys/modctl.h> 330Sstevel@tonic-gate #include <sys/stat.h> 34269Sericheng #include <sys/dld_impl.h> 35269Sericheng #include <sys/dls_impl.h> 365895Syz147064 #include <sys/softmac.h> 378275SEric Cheng #include <sys/mac.h> 388275SEric Cheng #include <sys/mac_ether.h> 398275SEric Cheng #include <sys/mac_client.h> 408275SEric Cheng #include <sys/mac_client_impl.h> 418275SEric Cheng #include <sys/mac_client_priv.h> 428275SEric Cheng #include <inet/common.h> 437408SSebastien.Roy@Sun.COM #include <sys/policy.h> 448275SEric Cheng #include <sys/priv_names.h> 450Sstevel@tonic-gate 460Sstevel@tonic-gate static void drv_init(void); 470Sstevel@tonic-gate static int drv_fini(void); 480Sstevel@tonic-gate 490Sstevel@tonic-gate static int drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 500Sstevel@tonic-gate static int drv_attach(dev_info_t *, ddi_attach_cmd_t); 510Sstevel@tonic-gate static int drv_detach(dev_info_t *, ddi_detach_cmd_t); 520Sstevel@tonic-gate 53269Sericheng /* 543147Sxc151355 * Secure objects declarations 553147Sxc151355 */ 563147Sxc151355 #define SECOBJ_WEP_HASHSZ 67 573147Sxc151355 static krwlock_t drv_secobj_lock; 583147Sxc151355 static kmem_cache_t *drv_secobj_cachep; 593147Sxc151355 static mod_hash_t *drv_secobj_hash; 603147Sxc151355 static void drv_secobj_init(void); 613147Sxc151355 static void drv_secobj_fini(void); 627342SAruna.Ramakrishna@Sun.COM static int drv_ioc_setap(datalink_id_t, struct dlautopush *); 637342SAruna.Ramakrishna@Sun.COM static int drv_ioc_getap(datalink_id_t, struct dlautopush *); 647342SAruna.Ramakrishna@Sun.COM static int drv_ioc_clrap(datalink_id_t); 653147Sxc151355 667408SSebastien.Roy@Sun.COM 673147Sxc151355 /* 68269Sericheng * The following entry points are private to dld and are used for control 69269Sericheng * operations only. The entry points exported to mac drivers are defined 70269Sericheng * in dld_str.c. Refer to the comment on top of dld_str.c for details. 71269Sericheng */ 727408SSebastien.Roy@Sun.COM static int drv_open(dev_t *, int, int, cred_t *); 737408SSebastien.Roy@Sun.COM static int drv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 740Sstevel@tonic-gate 757408SSebastien.Roy@Sun.COM static dev_info_t *dld_dip; /* dev_info_t for the driver */ 767408SSebastien.Roy@Sun.COM uint32_t dld_opt = 0; /* Global options */ 770Sstevel@tonic-gate 785895Syz147064 #define NAUTOPUSH 32 795895Syz147064 static mod_hash_t *dld_ap_hashp; 805895Syz147064 static krwlock_t dld_ap_hash_lock; 815895Syz147064 827408SSebastien.Roy@Sun.COM static struct cb_ops drv_cb_ops = { 837408SSebastien.Roy@Sun.COM drv_open, /* open */ 847408SSebastien.Roy@Sun.COM nulldev, /* close */ 857408SSebastien.Roy@Sun.COM nulldev, /* strategy */ 867408SSebastien.Roy@Sun.COM nulldev, /* print */ 877408SSebastien.Roy@Sun.COM nodev, /* dump */ 887408SSebastien.Roy@Sun.COM nodev, /* read */ 897408SSebastien.Roy@Sun.COM nodev, /* write */ 907408SSebastien.Roy@Sun.COM drv_ioctl, /* ioctl */ 917408SSebastien.Roy@Sun.COM nodev, /* devmap */ 927408SSebastien.Roy@Sun.COM nodev, /* mmap */ 937408SSebastien.Roy@Sun.COM nodev, /* segmap */ 947408SSebastien.Roy@Sun.COM nochpoll, /* poll */ 957408SSebastien.Roy@Sun.COM ddi_prop_op, /* cb_prop_op */ 967408SSebastien.Roy@Sun.COM 0, /* streamtab */ 977408SSebastien.Roy@Sun.COM D_MP /* Driver compatibility flag */ 980Sstevel@tonic-gate }; 990Sstevel@tonic-gate 1007408SSebastien.Roy@Sun.COM static struct dev_ops drv_ops = { 1017408SSebastien.Roy@Sun.COM DEVO_REV, /* devo_rev */ 1027408SSebastien.Roy@Sun.COM 0, /* refcnt */ 1037408SSebastien.Roy@Sun.COM drv_getinfo, /* get_dev_info */ 1047408SSebastien.Roy@Sun.COM nulldev, /* identify */ 1057408SSebastien.Roy@Sun.COM nulldev, /* probe */ 1067408SSebastien.Roy@Sun.COM drv_attach, /* attach */ 1077408SSebastien.Roy@Sun.COM drv_detach, /* detach */ 1087408SSebastien.Roy@Sun.COM nodev, /* reset */ 1097408SSebastien.Roy@Sun.COM &drv_cb_ops, /* driver operations */ 1107408SSebastien.Roy@Sun.COM NULL, /* bus operations */ 1117656SSherry.Moore@Sun.COM nodev, /* dev power */ 1127656SSherry.Moore@Sun.COM ddi_quiesce_not_supported, /* dev quiesce */ 1130Sstevel@tonic-gate }; 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate /* 1160Sstevel@tonic-gate * Module linkage information for the kernel. 1170Sstevel@tonic-gate */ 1180Sstevel@tonic-gate static struct modldrv drv_modldrv = { 1190Sstevel@tonic-gate &mod_driverops, 1200Sstevel@tonic-gate DLD_INFO, 1210Sstevel@tonic-gate &drv_ops 1220Sstevel@tonic-gate }; 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate static struct modlinkage drv_modlinkage = { 1250Sstevel@tonic-gate MODREV_1, 1260Sstevel@tonic-gate &drv_modldrv, 1270Sstevel@tonic-gate NULL 1280Sstevel@tonic-gate }; 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate int 1310Sstevel@tonic-gate _init(void) 1320Sstevel@tonic-gate { 1337408SSebastien.Roy@Sun.COM return (mod_install(&drv_modlinkage)); 1340Sstevel@tonic-gate } 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate int 1370Sstevel@tonic-gate _fini(void) 1380Sstevel@tonic-gate { 1397408SSebastien.Roy@Sun.COM return (mod_remove(&drv_modlinkage)); 1400Sstevel@tonic-gate } 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate int 1430Sstevel@tonic-gate _info(struct modinfo *modinfop) 1440Sstevel@tonic-gate { 1450Sstevel@tonic-gate return (mod_info(&drv_modlinkage, modinfop)); 1460Sstevel@tonic-gate } 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate /* 149269Sericheng * Initialize component modules. 1500Sstevel@tonic-gate */ 1510Sstevel@tonic-gate static void 1520Sstevel@tonic-gate drv_init(void) 1530Sstevel@tonic-gate { 1543147Sxc151355 drv_secobj_init(); 1550Sstevel@tonic-gate dld_str_init(); 1568275SEric Cheng 1575895Syz147064 /* 1585895Syz147064 * Create a hash table for autopush configuration. 1595895Syz147064 */ 1605895Syz147064 dld_ap_hashp = mod_hash_create_idhash("dld_autopush_hash", 1615895Syz147064 NAUTOPUSH, mod_hash_null_valdtor); 1625895Syz147064 1635895Syz147064 ASSERT(dld_ap_hashp != NULL); 1645895Syz147064 rw_init(&dld_ap_hash_lock, NULL, RW_DRIVER, NULL); 1655895Syz147064 } 1665895Syz147064 1675895Syz147064 /* ARGSUSED */ 1685895Syz147064 static uint_t 1695895Syz147064 drv_ap_exist(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 1705895Syz147064 { 1715895Syz147064 boolean_t *pexist = arg; 1725895Syz147064 1735895Syz147064 *pexist = B_TRUE; 1745895Syz147064 return (MH_WALK_TERMINATE); 1750Sstevel@tonic-gate } 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate static int 1780Sstevel@tonic-gate drv_fini(void) 1790Sstevel@tonic-gate { 1805895Syz147064 int err; 1815895Syz147064 boolean_t exist = B_FALSE; 1825895Syz147064 1835895Syz147064 rw_enter(&dld_ap_hash_lock, RW_READER); 1845895Syz147064 mod_hash_walk(dld_ap_hashp, drv_ap_exist, &exist); 1855895Syz147064 rw_exit(&dld_ap_hash_lock); 1865895Syz147064 if (exist) 1875895Syz147064 return (EBUSY); 1880Sstevel@tonic-gate 189269Sericheng if ((err = dld_str_fini()) != 0) 1900Sstevel@tonic-gate return (err); 1910Sstevel@tonic-gate 1923147Sxc151355 drv_secobj_fini(); 1935895Syz147064 mod_hash_destroy_idhash(dld_ap_hashp); 1945895Syz147064 rw_destroy(&dld_ap_hash_lock); 1950Sstevel@tonic-gate return (0); 1960Sstevel@tonic-gate } 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate /* 1990Sstevel@tonic-gate * devo_getinfo: getinfo(9e) 2000Sstevel@tonic-gate */ 2010Sstevel@tonic-gate /*ARGSUSED*/ 2020Sstevel@tonic-gate static int 2030Sstevel@tonic-gate drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resp) 2040Sstevel@tonic-gate { 2050Sstevel@tonic-gate if (dld_dip == NULL) 2060Sstevel@tonic-gate return (DDI_FAILURE); 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate switch (cmd) { 2090Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 2107408SSebastien.Roy@Sun.COM *resp = 0; 2110Sstevel@tonic-gate break; 2120Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 2137408SSebastien.Roy@Sun.COM *resp = dld_dip; 2140Sstevel@tonic-gate break; 2150Sstevel@tonic-gate default: 2160Sstevel@tonic-gate return (DDI_FAILURE); 2170Sstevel@tonic-gate } 2180Sstevel@tonic-gate 2190Sstevel@tonic-gate return (DDI_SUCCESS); 2200Sstevel@tonic-gate } 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate /* 2230Sstevel@tonic-gate * Check properties to set options. (See dld.h for property definitions). 2240Sstevel@tonic-gate */ 2250Sstevel@tonic-gate static void 2260Sstevel@tonic-gate drv_set_opt(dev_info_t *dip) 2270Sstevel@tonic-gate { 2280Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 2290Sstevel@tonic-gate DLD_PROP_NO_FASTPATH, 0) != 0) { 2300Sstevel@tonic-gate dld_opt |= DLD_OPT_NO_FASTPATH; 2310Sstevel@tonic-gate } 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 2340Sstevel@tonic-gate DLD_PROP_NO_POLL, 0) != 0) { 2350Sstevel@tonic-gate dld_opt |= DLD_OPT_NO_POLL; 2360Sstevel@tonic-gate } 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 2390Sstevel@tonic-gate DLD_PROP_NO_ZEROCOPY, 0) != 0) { 2400Sstevel@tonic-gate dld_opt |= DLD_OPT_NO_ZEROCOPY; 2410Sstevel@tonic-gate } 2424114Sja97890 2434114Sja97890 if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 2444114Sja97890 DLD_PROP_NO_SOFTRING, 0) != 0) { 2454114Sja97890 dld_opt |= DLD_OPT_NO_SOFTRING; 2464114Sja97890 } 2470Sstevel@tonic-gate } 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate /* 2500Sstevel@tonic-gate * devo_attach: attach(9e) 2510Sstevel@tonic-gate */ 2520Sstevel@tonic-gate static int 2530Sstevel@tonic-gate drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2540Sstevel@tonic-gate { 2550Sstevel@tonic-gate if (cmd != DDI_ATTACH) 2560Sstevel@tonic-gate return (DDI_FAILURE); 2570Sstevel@tonic-gate 2580Sstevel@tonic-gate ASSERT(ddi_get_instance(dip) == 0); 2597408SSebastien.Roy@Sun.COM drv_init(); 2600Sstevel@tonic-gate drv_set_opt(dip); 2610Sstevel@tonic-gate 2620Sstevel@tonic-gate /* 2630Sstevel@tonic-gate * Create control node. DLPI provider nodes will be created on demand. 2640Sstevel@tonic-gate */ 2650Sstevel@tonic-gate if (ddi_create_minor_node(dip, DLD_CONTROL_MINOR_NAME, S_IFCHR, 2660Sstevel@tonic-gate DLD_CONTROL_MINOR, DDI_PSEUDO, 0) != DDI_SUCCESS) 2670Sstevel@tonic-gate return (DDI_FAILURE); 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate dld_dip = dip; 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate /* 2720Sstevel@tonic-gate * Log the fact that the driver is now attached. 2730Sstevel@tonic-gate */ 2740Sstevel@tonic-gate ddi_report_dev(dip); 2750Sstevel@tonic-gate return (DDI_SUCCESS); 2760Sstevel@tonic-gate } 2770Sstevel@tonic-gate 2780Sstevel@tonic-gate /* 2790Sstevel@tonic-gate * devo_detach: detach(9e) 2800Sstevel@tonic-gate */ 2810Sstevel@tonic-gate static int 2820Sstevel@tonic-gate drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2830Sstevel@tonic-gate { 2840Sstevel@tonic-gate if (cmd != DDI_DETACH) 2850Sstevel@tonic-gate return (DDI_FAILURE); 2860Sstevel@tonic-gate 2870Sstevel@tonic-gate ASSERT(dld_dip == dip); 2887408SSebastien.Roy@Sun.COM if (drv_fini() != 0) 2897408SSebastien.Roy@Sun.COM return (DDI_FAILURE); 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate /* 2920Sstevel@tonic-gate * Remove the control node. 2930Sstevel@tonic-gate */ 2940Sstevel@tonic-gate ddi_remove_minor_node(dip, DLD_CONTROL_MINOR_NAME); 2950Sstevel@tonic-gate dld_dip = NULL; 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate return (DDI_SUCCESS); 2980Sstevel@tonic-gate } 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate /* 301269Sericheng * dld control node open procedure. 3020Sstevel@tonic-gate */ 3030Sstevel@tonic-gate /*ARGSUSED*/ 3040Sstevel@tonic-gate static int 3057408SSebastien.Roy@Sun.COM drv_open(dev_t *devp, int flag, int sflag, cred_t *credp) 3060Sstevel@tonic-gate { 3070Sstevel@tonic-gate /* 3087408SSebastien.Roy@Sun.COM * Only the control node can be opened. 3090Sstevel@tonic-gate */ 3107408SSebastien.Roy@Sun.COM if (getminor(*devp) != DLD_CONTROL_MINOR) 3117408SSebastien.Roy@Sun.COM return (ENODEV); 3120Sstevel@tonic-gate return (0); 3130Sstevel@tonic-gate } 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate /* 3165895Syz147064 * DLDIOC_ATTR 3170Sstevel@tonic-gate */ 3187408SSebastien.Roy@Sun.COM /* ARGSUSED */ 3197408SSebastien.Roy@Sun.COM static int 3208275SEric Cheng drv_ioc_attr(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 3210Sstevel@tonic-gate { 3227408SSebastien.Roy@Sun.COM dld_ioc_attr_t *diap = karg; 3235895Syz147064 dls_dl_handle_t dlh; 3248275SEric Cheng dls_link_t *dlp; 3255895Syz147064 int err; 3268275SEric Cheng mac_perim_handle_t mph; 3275895Syz147064 3285895Syz147064 if ((err = dls_devnet_hold_tmp(diap->dia_linkid, &dlh)) != 0) 3297408SSebastien.Roy@Sun.COM return (err); 330269Sericheng 3318275SEric Cheng if ((err = mac_perim_enter_by_macname( 3328275SEric Cheng dls_devnet_mac(dlh), &mph)) != 0) { 3335895Syz147064 dls_devnet_rele_tmp(dlh); 3347408SSebastien.Roy@Sun.COM return (err); 335269Sericheng } 336269Sericheng 3378275SEric Cheng if ((err = dls_link_hold(dls_devnet_mac(dlh), &dlp)) != 0) { 3388275SEric Cheng mac_perim_exit(mph); 3398275SEric Cheng dls_devnet_rele_tmp(dlh); 3408275SEric Cheng return (err); 3418275SEric Cheng } 3428275SEric Cheng 3438275SEric Cheng mac_sdu_get(dlp->dl_mh, NULL, &diap->dia_max_sdu); 3448275SEric Cheng 3458275SEric Cheng dls_link_rele(dlp); 3468275SEric Cheng mac_perim_exit(mph); 3475895Syz147064 dls_devnet_rele_tmp(dlh); 3480Sstevel@tonic-gate 3497408SSebastien.Roy@Sun.COM return (0); 350269Sericheng } 351269Sericheng 3523448Sdh155122 /* 3535895Syz147064 * DLDIOC_PHYS_ATTR 3543448Sdh155122 */ 3557408SSebastien.Roy@Sun.COM /* ARGSUSED */ 3567408SSebastien.Roy@Sun.COM static int 3578275SEric Cheng drv_ioc_phys_attr(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 3583448Sdh155122 { 3597408SSebastien.Roy@Sun.COM dld_ioc_phys_attr_t *dipp = karg; 3605895Syz147064 int err; 3615895Syz147064 dls_dl_handle_t dlh; 3625895Syz147064 dls_dev_handle_t ddh; 3635895Syz147064 dev_t phydev; 3645895Syz147064 3655895Syz147064 /* 3665895Syz147064 * Every physical link should have its physical dev_t kept in the 3675895Syz147064 * daemon. If not, it is not a valid physical link. 3685895Syz147064 */ 3697408SSebastien.Roy@Sun.COM if (dls_mgmt_get_phydev(dipp->dip_linkid, &phydev) != 0) 3707408SSebastien.Roy@Sun.COM return (EINVAL); 3713448Sdh155122 3724049Sdh155122 /* 3735895Syz147064 * Although this is a valid physical link, it might already be removed 3745895Syz147064 * by DR or during system shutdown. softmac_hold_device() would return 3755895Syz147064 * ENOENT in this case. 3765895Syz147064 */ 3775895Syz147064 if ((err = softmac_hold_device(phydev, &ddh)) != 0) 3787408SSebastien.Roy@Sun.COM return (err); 3795895Syz147064 3805895Syz147064 if (dls_devnet_hold_tmp(dipp->dip_linkid, &dlh) != 0) { 3815895Syz147064 /* 3825895Syz147064 * Although this is an active physical link, its link type is 3835895Syz147064 * not supported by GLDv3, and therefore it does not have 3845895Syz147064 * vanity naming support. 3855895Syz147064 */ 3865895Syz147064 dipp->dip_novanity = B_TRUE; 3875895Syz147064 } else { 3885895Syz147064 dipp->dip_novanity = B_FALSE; 3895895Syz147064 dls_devnet_rele_tmp(dlh); 3905895Syz147064 } 3915895Syz147064 /* 3925895Syz147064 * Get the physical device name from the major number and the instance 3935895Syz147064 * number derived from phydev. 3944049Sdh155122 */ 3955895Syz147064 (void) snprintf(dipp->dip_dev, MAXLINKNAMELEN, "%s%d", 3965895Syz147064 ddi_major_to_name(getmajor(phydev)), getminor(phydev) - 1); 3975895Syz147064 3985895Syz147064 softmac_rele_device(ddh); 3997408SSebastien.Roy@Sun.COM return (0); 4005895Syz147064 } 4015895Syz147064 4028275SEric Cheng /* ARGSUSED */ 4038275SEric Cheng static int 4048275SEric Cheng drv_ioc_hwgrpget(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 4058275SEric Cheng { 4068275SEric Cheng dld_ioc_hwgrpget_t *hwgrpp = karg; 4078275SEric Cheng dld_hwgrpinfo_t hwgrp, *hip; 4088275SEric Cheng mac_handle_t mh = NULL; 4098275SEric Cheng int i, err, grpnum; 4108275SEric Cheng uint_t bytes_left; 4118275SEric Cheng 4128275SEric Cheng hwgrpp->dih_n_groups = 0; 4138275SEric Cheng err = mac_open_by_linkid(hwgrpp->dih_linkid, &mh); 4148275SEric Cheng if (err != 0) 4158275SEric Cheng goto done; 4168275SEric Cheng 4178275SEric Cheng hip = (dld_hwgrpinfo_t *) 4188275SEric Cheng ((uchar_t *)arg + sizeof (dld_ioc_hwgrpget_t)); 4198275SEric Cheng bytes_left = hwgrpp->dih_size; 4208275SEric Cheng grpnum = mac_hwgrp_num(mh); 4218275SEric Cheng for (i = 0; i < grpnum; i++) { 4228275SEric Cheng if (sizeof (dld_hwgrpinfo_t) > bytes_left) { 4238275SEric Cheng err = ENOSPC; 4248275SEric Cheng goto done; 4258275SEric Cheng } 4268275SEric Cheng 4278275SEric Cheng bzero(&hwgrp, sizeof (hwgrp)); 4288275SEric Cheng bcopy(mac_name(mh), hwgrp.dhi_link_name, 4298275SEric Cheng sizeof (hwgrp.dhi_link_name)); 4308275SEric Cheng mac_get_hwgrp_info(mh, i, &hwgrp.dhi_grp_num, 4318275SEric Cheng &hwgrp.dhi_n_rings, &hwgrp.dhi_grp_type, 4328275SEric Cheng &hwgrp.dhi_n_clnts, hwgrp.dhi_clnts); 4338275SEric Cheng if (copyout(&hwgrp, hip, sizeof (hwgrp)) != 0) { 4348275SEric Cheng err = EFAULT; 4358275SEric Cheng goto done; 4368275SEric Cheng } 4378275SEric Cheng 4388275SEric Cheng hip++; 4398275SEric Cheng bytes_left -= sizeof (dld_hwgrpinfo_t); 4408275SEric Cheng } 4418275SEric Cheng 4428275SEric Cheng done: 4438275SEric Cheng if (mh != NULL) 4448275SEric Cheng dld_mac_close(mh); 4458275SEric Cheng if (err == 0) 4468275SEric Cheng hwgrpp->dih_n_groups = grpnum; 4478275SEric Cheng return (err); 4488275SEric Cheng } 4498275SEric Cheng 4508275SEric Cheng /* ARGSUSED */ 4518275SEric Cheng static int 4528275SEric Cheng drv_ioc_macaddrget(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 4538275SEric Cheng { 4548275SEric Cheng dld_ioc_macaddrget_t *magp = karg; 4558275SEric Cheng dld_macaddrinfo_t mai, *maip; 4568275SEric Cheng mac_handle_t mh = NULL; 4578275SEric Cheng int i, err; 4588275SEric Cheng uint_t bytes_left; 4598275SEric Cheng boolean_t is_used; 4608275SEric Cheng 4618275SEric Cheng magp->dig_count = 0; 4628275SEric Cheng err = mac_open_by_linkid(magp->dig_linkid, &mh); 4638275SEric Cheng if (err != 0) 4648275SEric Cheng goto done; 4658275SEric Cheng 4668275SEric Cheng maip = (dld_macaddrinfo_t *) 4678275SEric Cheng ((uchar_t *)arg + sizeof (dld_ioc_macaddrget_t)); 4688275SEric Cheng bytes_left = magp->dig_size; 4698275SEric Cheng 4708275SEric Cheng for (i = 0; i < mac_addr_factory_num(mh) + 1; i++) { 4718275SEric Cheng if (sizeof (dld_macaddrinfo_t) > bytes_left) { 4728275SEric Cheng err = ENOSPC; 4738275SEric Cheng goto done; 4748275SEric Cheng } 4758275SEric Cheng 4768275SEric Cheng bzero(&mai, sizeof (mai)); 4778275SEric Cheng 4788275SEric Cheng if (i == 0) { 4798275SEric Cheng /* primary MAC address */ 4808275SEric Cheng mac_unicast_primary_get(mh, mai.dmi_addr); 4818275SEric Cheng mai.dmi_addrlen = mac_addr_len(mh); 4828275SEric Cheng mac_unicast_primary_info(mh, mai.dmi_client_name, 4838275SEric Cheng &is_used); 4848275SEric Cheng } else { 4858275SEric Cheng /* factory MAC address slot */ 4868275SEric Cheng mac_addr_factory_value(mh, i, mai.dmi_addr, 4878275SEric Cheng &mai.dmi_addrlen, mai.dmi_client_name, &is_used); 4888275SEric Cheng } 4898275SEric Cheng 4908275SEric Cheng mai.dmi_slot = i; 4918275SEric Cheng if (is_used) 4928275SEric Cheng mai.dmi_flags |= DLDIOCMACADDR_USED; 4938275SEric Cheng 4948275SEric Cheng if (copyout(&mai, maip, sizeof (mai)) != 0) { 4958275SEric Cheng err = EFAULT; 4968275SEric Cheng goto done; 4978275SEric Cheng } 4988275SEric Cheng 4998275SEric Cheng maip++; 5008275SEric Cheng bytes_left -= sizeof (dld_macaddrinfo_t); 5018275SEric Cheng } 5028275SEric Cheng 5038275SEric Cheng done: 5048275SEric Cheng if (mh != NULL) 5058275SEric Cheng dld_mac_close(mh); 5068275SEric Cheng if (err == 0) 5078275SEric Cheng magp->dig_count = mac_addr_factory_num(mh) + 1; 5088275SEric Cheng return (err); 5098275SEric Cheng } 5108275SEric Cheng 5115895Syz147064 /* 5128275SEric Cheng * DLDIOC_SET/GETPROP 5135903Ssowmini */ 5147408SSebastien.Roy@Sun.COM static int 5158275SEric Cheng drv_ioc_prop_common(dld_ioc_macprop_t *prop, intptr_t arg, boolean_t set, 5167408SSebastien.Roy@Sun.COM int mode) 5175903Ssowmini { 5188275SEric Cheng int err = EINVAL; 5198275SEric Cheng dls_dl_handle_t dlh = NULL; 5208275SEric Cheng dls_link_t *dlp = NULL; 5218275SEric Cheng mac_perim_handle_t mph = NULL; 5225903Ssowmini mac_prop_t macprop; 5238275SEric Cheng dld_ioc_macprop_t *kprop; 5248275SEric Cheng datalink_id_t linkid; 5258275SEric Cheng uint_t dsize; 5268275SEric Cheng 5275903Ssowmini 5287408SSebastien.Roy@Sun.COM /* 5298275SEric Cheng * We only use pr_valsize from prop, as the caller only did a 5307408SSebastien.Roy@Sun.COM * copyin() for sizeof (dld_ioc_prop_t), which doesn't cover 5317408SSebastien.Roy@Sun.COM * the property data. We copyin the full dld_ioc_prop_t 5328275SEric Cheng * including the data into kprop down below. 5337408SSebastien.Roy@Sun.COM */ 5348275SEric Cheng dsize = sizeof (dld_ioc_macprop_t) + prop->pr_valsize - 1; 5358275SEric Cheng if (dsize < prop->pr_valsize) 5367408SSebastien.Roy@Sun.COM return (EINVAL); 5377408SSebastien.Roy@Sun.COM 5387408SSebastien.Roy@Sun.COM /* 5397408SSebastien.Roy@Sun.COM * The property data is variable size, so we need to allocate 5407408SSebastien.Roy@Sun.COM * a buffer for kernel use as this data was not part of the 5418275SEric Cheng * prop allocation and copyin() done by the framework. 5427408SSebastien.Roy@Sun.COM */ 5438275SEric Cheng if ((kprop = kmem_alloc(dsize, KM_NOSLEEP)) == NULL) 5447408SSebastien.Roy@Sun.COM return (ENOMEM); 5458275SEric Cheng 5468275SEric Cheng if (ddi_copyin((void *)arg, kprop, dsize, mode) != 0) { 5477408SSebastien.Roy@Sun.COM err = EFAULT; 5485903Ssowmini goto done; 5497408SSebastien.Roy@Sun.COM } 5505903Ssowmini 5518275SEric Cheng linkid = kprop->pr_linkid; 5528275SEric Cheng if ((err = dls_devnet_hold_tmp(linkid, &dlh)) != 0) 5538275SEric Cheng goto done; 5545903Ssowmini 5558275SEric Cheng if ((err = mac_perim_enter_by_macname(dls_devnet_mac(dlh), 5568275SEric Cheng &mph)) != 0) { 5578275SEric Cheng goto done; 5588275SEric Cheng } 5598275SEric Cheng 5608874SSebastien.Roy@Sun.COM if ((err = dls_link_hold(dls_devnet_mac(dlh), &dlp)) != 0) 5618874SSebastien.Roy@Sun.COM goto done; 5628874SSebastien.Roy@Sun.COM 5638275SEric Cheng switch (kprop->pr_num) { 5648874SSebastien.Roy@Sun.COM case MAC_PROP_ZONE: 5657342SAruna.Ramakrishna@Sun.COM if (set) { 5668874SSebastien.Roy@Sun.COM dld_ioc_zid_t *dzp = (dld_ioc_zid_t *)kprop->pr_val; 5678275SEric Cheng 5687342SAruna.Ramakrishna@Sun.COM err = dls_devnet_setzid(dzp->diz_link, dzp->diz_zid); 5697342SAruna.Ramakrishna@Sun.COM } else { 5708275SEric Cheng kprop->pr_perm_flags = MAC_PROP_PERM_RW; 5718275SEric Cheng err = dls_devnet_getzid(linkid, 5728275SEric Cheng (zoneid_t *)kprop->pr_val); 5737342SAruna.Ramakrishna@Sun.COM } 5748874SSebastien.Roy@Sun.COM break; 5758275SEric Cheng case MAC_PROP_AUTOPUSH: { 5768874SSebastien.Roy@Sun.COM struct dlautopush *dlap = (struct dlautopush *)kprop->pr_val; 5778275SEric Cheng 5787342SAruna.Ramakrishna@Sun.COM if (set) { 5798874SSebastien.Roy@Sun.COM if (kprop->pr_valsize != 0) 5807342SAruna.Ramakrishna@Sun.COM err = drv_ioc_setap(linkid, dlap); 5818874SSebastien.Roy@Sun.COM else 5827342SAruna.Ramakrishna@Sun.COM err = drv_ioc_clrap(linkid); 5837342SAruna.Ramakrishna@Sun.COM } else { 5848275SEric Cheng kprop->pr_perm_flags = MAC_PROP_PERM_RW; 5857342SAruna.Ramakrishna@Sun.COM err = drv_ioc_getap(linkid, dlap); 5867342SAruna.Ramakrishna@Sun.COM } 5877342SAruna.Ramakrishna@Sun.COM break; 5887342SAruna.Ramakrishna@Sun.COM } 5898874SSebastien.Roy@Sun.COM case MAC_PROP_TAGMODE: 5908874SSebastien.Roy@Sun.COM if (set) { 5918874SSebastien.Roy@Sun.COM link_tagmode_t mode = *(link_tagmode_t *)kprop->pr_val; 5925903Ssowmini 5938874SSebastien.Roy@Sun.COM if (mode != LINK_TAGMODE_VLANONLY && 5948874SSebastien.Roy@Sun.COM mode != LINK_TAGMODE_NORMAL) { 5958874SSebastien.Roy@Sun.COM err = EINVAL; 5968874SSebastien.Roy@Sun.COM } else { 5978874SSebastien.Roy@Sun.COM dlp->dl_tagmode = mode; 5988874SSebastien.Roy@Sun.COM err = 0; 5998874SSebastien.Roy@Sun.COM } 6008874SSebastien.Roy@Sun.COM } else { 6018874SSebastien.Roy@Sun.COM *(link_tagmode_t *)kprop->pr_val = dlp->dl_tagmode; 6028874SSebastien.Roy@Sun.COM kprop->pr_perm_flags = MAC_PROP_PERM_RW; 6038874SSebastien.Roy@Sun.COM err = 0; 6048874SSebastien.Roy@Sun.COM } 6058874SSebastien.Roy@Sun.COM break; 6068874SSebastien.Roy@Sun.COM default: 6078874SSebastien.Roy@Sun.COM macprop.mp_name = kprop->pr_name; 6088874SSebastien.Roy@Sun.COM macprop.mp_id = kprop->pr_num; 6098874SSebastien.Roy@Sun.COM macprop.mp_flags = kprop->pr_flags; 6108874SSebastien.Roy@Sun.COM 6118874SSebastien.Roy@Sun.COM if (set) { 6128874SSebastien.Roy@Sun.COM err = mac_set_prop(dlp->dl_mh, &macprop, kprop->pr_val, 6138874SSebastien.Roy@Sun.COM kprop->pr_valsize); 6148874SSebastien.Roy@Sun.COM } else { 6158874SSebastien.Roy@Sun.COM kprop->pr_perm_flags = MAC_PROP_PERM_RW; 6168874SSebastien.Roy@Sun.COM err = mac_get_prop(dlp->dl_mh, &macprop, kprop->pr_val, 6178874SSebastien.Roy@Sun.COM kprop->pr_valsize, &kprop->pr_perm_flags); 6188874SSebastien.Roy@Sun.COM } 6197408SSebastien.Roy@Sun.COM } 6205903Ssowmini 6215903Ssowmini done: 6227408SSebastien.Roy@Sun.COM if (!set && err == 0 && 6238275SEric Cheng ddi_copyout(kprop, (void *)arg, dsize, mode) != 0) 6247408SSebastien.Roy@Sun.COM err = EFAULT; 6258275SEric Cheng 6268275SEric Cheng if (dlp != NULL) 6278275SEric Cheng dls_link_rele(dlp); 6288275SEric Cheng 6298275SEric Cheng if (mph != NULL) { 6308275SEric Cheng int32_t cpuid; 6318275SEric Cheng void *mdip = NULL; 6328275SEric Cheng 6338275SEric Cheng if (dlp != NULL && set && err == 0) { 6348275SEric Cheng cpuid = mac_client_intr_cpu(dlp->dl_mch); 6358275SEric Cheng mdip = mac_get_devinfo(dlp->dl_mh); 6368275SEric Cheng } 6378275SEric Cheng 6388275SEric Cheng mac_perim_exit(mph); 6398275SEric Cheng 6408275SEric Cheng if (mdip != NULL) 6418275SEric Cheng mac_client_set_intr_cpu(mdip, dlp->dl_mch, cpuid); 6428275SEric Cheng } 6438275SEric Cheng if (dlh != NULL) 6448275SEric Cheng dls_devnet_rele_tmp(dlh); 6458275SEric Cheng 6468275SEric Cheng if (kprop != NULL) 6478275SEric Cheng kmem_free(kprop, dsize); 6487408SSebastien.Roy@Sun.COM return (err); 6495903Ssowmini } 6505903Ssowmini 6517408SSebastien.Roy@Sun.COM /* ARGSUSED */ 6527408SSebastien.Roy@Sun.COM static int 6538275SEric Cheng drv_ioc_setprop(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 6545903Ssowmini { 6557408SSebastien.Roy@Sun.COM return (drv_ioc_prop_common(karg, arg, B_TRUE, mode)); 6565903Ssowmini } 6575903Ssowmini 6587408SSebastien.Roy@Sun.COM /* ARGSUSED */ 6597408SSebastien.Roy@Sun.COM static int 6608275SEric Cheng drv_ioc_getprop(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 6615903Ssowmini { 6627408SSebastien.Roy@Sun.COM return (drv_ioc_prop_common(karg, arg, B_FALSE, mode)); 6635903Ssowmini } 6645903Ssowmini 6655903Ssowmini /* 6665895Syz147064 * DLDIOC_RENAME. 6675895Syz147064 * 6685895Syz147064 * This function handles two cases of link renaming. See more in comments above 6695895Syz147064 * dls_datalink_rename(). 6705895Syz147064 */ 6717408SSebastien.Roy@Sun.COM /* ARGSUSED */ 6727408SSebastien.Roy@Sun.COM static int 6738275SEric Cheng drv_ioc_rename(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 6745895Syz147064 { 6757408SSebastien.Roy@Sun.COM dld_ioc_rename_t *dir = karg; 6765895Syz147064 mod_hash_key_t key; 6775895Syz147064 mod_hash_val_t val; 6785895Syz147064 int err; 6795895Syz147064 6805895Syz147064 if ((err = dls_devnet_rename(dir->dir_linkid1, dir->dir_linkid2, 6817408SSebastien.Roy@Sun.COM dir->dir_link)) != 0) 6827408SSebastien.Roy@Sun.COM return (err); 6835895Syz147064 6845895Syz147064 if (dir->dir_linkid2 == DATALINK_INVALID_LINKID) 6857408SSebastien.Roy@Sun.COM return (0); 6865895Syz147064 6875895Syz147064 /* 6885895Syz147064 * if dir_linkid2 is not DATALINK_INVALID_LINKID, it means this 6895895Syz147064 * renaming request is to rename a valid physical link (dir_linkid1) 6905895Syz147064 * to a "removed" physical link (dir_linkid2, which is removed by DR 6915895Syz147064 * or during system shutdown). In this case, the link (specified by 6925895Syz147064 * dir_linkid1) would inherit all the configuration of dir_linkid2, 6935895Syz147064 * and dir_linkid1 and its configuration would be lost. 6945895Syz147064 * 6955895Syz147064 * Remove per-link autopush configuration of dir_linkid1 in this case. 6965895Syz147064 */ 6975895Syz147064 key = (mod_hash_key_t)(uintptr_t)dir->dir_linkid1; 6985895Syz147064 rw_enter(&dld_ap_hash_lock, RW_WRITER); 6995895Syz147064 if (mod_hash_find(dld_ap_hashp, key, &val) != 0) { 7005895Syz147064 rw_exit(&dld_ap_hash_lock); 7017408SSebastien.Roy@Sun.COM return (0); 7025895Syz147064 } 7035895Syz147064 7045895Syz147064 VERIFY(mod_hash_remove(dld_ap_hashp, key, &val) == 0); 7055895Syz147064 kmem_free(val, sizeof (dld_ap_t)); 7065895Syz147064 rw_exit(&dld_ap_hash_lock); 7077408SSebastien.Roy@Sun.COM return (0); 7085895Syz147064 } 7095895Syz147064 7107342SAruna.Ramakrishna@Sun.COM static int 7117342SAruna.Ramakrishna@Sun.COM drv_ioc_setap(datalink_id_t linkid, struct dlautopush *dlap) 7123448Sdh155122 { 7135895Syz147064 dld_ap_t *dap; 7147408SSebastien.Roy@Sun.COM int i; 7155895Syz147064 mod_hash_key_t key; 7163448Sdh155122 7177408SSebastien.Roy@Sun.COM if (dlap->dap_npush == 0 || dlap->dap_npush > MAXAPUSH) 7187408SSebastien.Roy@Sun.COM return (EINVAL); 7193448Sdh155122 7205895Syz147064 /* 7215895Syz147064 * Validate that the specified list of modules exist. 7225895Syz147064 */ 7237342SAruna.Ramakrishna@Sun.COM for (i = 0; i < dlap->dap_npush; i++) { 7247408SSebastien.Roy@Sun.COM if (fmodsw_find(dlap->dap_aplist[i], FMODSW_LOAD) == NULL) 7257408SSebastien.Roy@Sun.COM return (EINVAL); 7263448Sdh155122 } 7273448Sdh155122 7287408SSebastien.Roy@Sun.COM 7297342SAruna.Ramakrishna@Sun.COM key = (mod_hash_key_t)(uintptr_t)linkid; 7305895Syz147064 7315895Syz147064 rw_enter(&dld_ap_hash_lock, RW_WRITER); 7325895Syz147064 if (mod_hash_find(dld_ap_hashp, key, (mod_hash_val_t *)&dap) != 0) { 7335895Syz147064 dap = kmem_zalloc(sizeof (dld_ap_t), KM_NOSLEEP); 7345895Syz147064 if (dap == NULL) { 7355895Syz147064 rw_exit(&dld_ap_hash_lock); 7367408SSebastien.Roy@Sun.COM return (ENOMEM); 7375895Syz147064 } 7385895Syz147064 7397342SAruna.Ramakrishna@Sun.COM dap->da_linkid = linkid; 7407408SSebastien.Roy@Sun.COM VERIFY(mod_hash_insert(dld_ap_hashp, key, 7417408SSebastien.Roy@Sun.COM (mod_hash_val_t)dap) == 0); 7423448Sdh155122 } 7433448Sdh155122 7445895Syz147064 /* 7455895Syz147064 * Update the configuration. 7465895Syz147064 */ 7477342SAruna.Ramakrishna@Sun.COM dap->da_anchor = dlap->dap_anchor; 7487342SAruna.Ramakrishna@Sun.COM dap->da_npush = dlap->dap_npush; 7497342SAruna.Ramakrishna@Sun.COM for (i = 0; i < dlap->dap_npush; i++) { 7507342SAruna.Ramakrishna@Sun.COM (void) strlcpy(dap->da_aplist[i], dlap->dap_aplist[i], 7515895Syz147064 FMNAMESZ + 1); 7525895Syz147064 } 7535895Syz147064 rw_exit(&dld_ap_hash_lock); 7545895Syz147064 7557342SAruna.Ramakrishna@Sun.COM return (0); 7563448Sdh155122 } 7573448Sdh155122 7587342SAruna.Ramakrishna@Sun.COM static int 7597342SAruna.Ramakrishna@Sun.COM drv_ioc_getap(datalink_id_t linkid, struct dlautopush *dlap) 7605895Syz147064 { 7615895Syz147064 dld_ap_t *dap; 7627408SSebastien.Roy@Sun.COM int i; 7635895Syz147064 7645895Syz147064 rw_enter(&dld_ap_hash_lock, RW_READER); 7655895Syz147064 if (mod_hash_find(dld_ap_hashp, 7667342SAruna.Ramakrishna@Sun.COM (mod_hash_key_t)(uintptr_t)linkid, 7675895Syz147064 (mod_hash_val_t *)&dap) != 0) { 7685895Syz147064 rw_exit(&dld_ap_hash_lock); 7697408SSebastien.Roy@Sun.COM return (ENOENT); 7705895Syz147064 } 7715895Syz147064 7725895Syz147064 /* 7735895Syz147064 * Retrieve the configuration. 7745895Syz147064 */ 7757342SAruna.Ramakrishna@Sun.COM dlap->dap_anchor = dap->da_anchor; 7767342SAruna.Ramakrishna@Sun.COM dlap->dap_npush = dap->da_npush; 7775895Syz147064 for (i = 0; i < dap->da_npush; i++) { 7787342SAruna.Ramakrishna@Sun.COM (void) strlcpy(dlap->dap_aplist[i], dap->da_aplist[i], 7795895Syz147064 FMNAMESZ + 1); 7805895Syz147064 } 7815895Syz147064 rw_exit(&dld_ap_hash_lock); 7825895Syz147064 7837342SAruna.Ramakrishna@Sun.COM return (0); 7845895Syz147064 } 7855895Syz147064 7867342SAruna.Ramakrishna@Sun.COM static int 7877342SAruna.Ramakrishna@Sun.COM drv_ioc_clrap(datalink_id_t linkid) 7885895Syz147064 { 7895895Syz147064 mod_hash_val_t val; 7905895Syz147064 mod_hash_key_t key; 7915895Syz147064 7927342SAruna.Ramakrishna@Sun.COM key = (mod_hash_key_t)(uintptr_t)linkid; 7935895Syz147064 7945895Syz147064 rw_enter(&dld_ap_hash_lock, RW_WRITER); 7955895Syz147064 if (mod_hash_find(dld_ap_hashp, key, &val) != 0) { 7965895Syz147064 rw_exit(&dld_ap_hash_lock); 7977342SAruna.Ramakrishna@Sun.COM return (0); 7985895Syz147064 } 7995895Syz147064 8005895Syz147064 VERIFY(mod_hash_remove(dld_ap_hashp, key, &val) == 0); 8015895Syz147064 kmem_free(val, sizeof (dld_ap_t)); 8025895Syz147064 rw_exit(&dld_ap_hash_lock); 8037342SAruna.Ramakrishna@Sun.COM return (0); 8045895Syz147064 } 8055895Syz147064 8065895Syz147064 /* 8075895Syz147064 * DLDIOC_DOORSERVER 8085895Syz147064 */ 8097408SSebastien.Roy@Sun.COM /* ARGSUSED */ 8107408SSebastien.Roy@Sun.COM static int 8118275SEric Cheng drv_ioc_doorserver(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 8123448Sdh155122 { 8137408SSebastien.Roy@Sun.COM dld_ioc_door_t *did = karg; 814269Sericheng 8157408SSebastien.Roy@Sun.COM return (dls_mgmt_door_set(did->did_start_door)); 8160Sstevel@tonic-gate } 8173147Sxc151355 8183147Sxc151355 /* 8198275SEric Cheng * DLDIOC_USAGELOG 8208275SEric Cheng */ 8218275SEric Cheng /* ARGSUSED */ 8228275SEric Cheng static int 8238275SEric Cheng drv_ioc_usagelog(void *karg, intptr_t arg, int mode, cred_t *cred, 8248275SEric Cheng int *rvalp) 8258275SEric Cheng { 8268275SEric Cheng dld_ioc_usagelog_t *log_info = (dld_ioc_usagelog_t *)karg; 827*9073SCathy.Zhou@Sun.COM int err = 0; 8288275SEric Cheng 8298275SEric Cheng if (log_info->ul_type < MAC_LOGTYPE_LINK || 8308275SEric Cheng log_info->ul_type > MAC_LOGTYPE_FLOW) 8318275SEric Cheng return (EINVAL); 8328275SEric Cheng 833*9073SCathy.Zhou@Sun.COM if (log_info->ul_onoff) { 834*9073SCathy.Zhou@Sun.COM err = mac_start_logusage(log_info->ul_type, 835*9073SCathy.Zhou@Sun.COM log_info->ul_interval); 836*9073SCathy.Zhou@Sun.COM } else { 8378275SEric Cheng mac_stop_logusage(log_info->ul_type); 838*9073SCathy.Zhou@Sun.COM } 839*9073SCathy.Zhou@Sun.COM return (err); 8408275SEric Cheng } 8418275SEric Cheng 8428275SEric Cheng /* 8438275SEric Cheng * Process a DLDIOC_ADDFLOW request. 8448275SEric Cheng */ 8458275SEric Cheng /* ARGSUSED */ 8468275SEric Cheng static int 8478275SEric Cheng drv_ioc_addflow(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 8488275SEric Cheng { 8498275SEric Cheng dld_ioc_addflow_t *afp = karg; 8508275SEric Cheng 8518275SEric Cheng return (dld_add_flow(afp->af_linkid, afp->af_name, 8528275SEric Cheng &afp->af_flow_desc, &afp->af_resource_props)); 8538275SEric Cheng } 8548275SEric Cheng 8558275SEric Cheng /* 8568275SEric Cheng * Process a DLDIOC_REMOVEFLOW request. 8578275SEric Cheng */ 8588275SEric Cheng /* ARGSUSED */ 8598275SEric Cheng static int 8608275SEric Cheng drv_ioc_removeflow(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 8618275SEric Cheng { 8628275SEric Cheng dld_ioc_removeflow_t *rfp = karg; 8638275SEric Cheng 8648275SEric Cheng return (dld_remove_flow(rfp->rf_name)); 8658275SEric Cheng } 8668275SEric Cheng 8678275SEric Cheng /* 8688275SEric Cheng * Process a DLDIOC_MODIFYFLOW request. 8698275SEric Cheng */ 8708275SEric Cheng /* ARGSUSED */ 8718275SEric Cheng static int 8728275SEric Cheng drv_ioc_modifyflow(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 8738275SEric Cheng { 8748275SEric Cheng dld_ioc_modifyflow_t *mfp = karg; 8758275SEric Cheng 8768275SEric Cheng return (dld_modify_flow(mfp->mf_name, &mfp->mf_resource_props)); 8778275SEric Cheng } 8788275SEric Cheng 8798275SEric Cheng /* 8808275SEric Cheng * Process a DLDIOC_WALKFLOW request. 8818275SEric Cheng */ 8828275SEric Cheng /* ARGSUSED */ 8838275SEric Cheng static int 8848275SEric Cheng drv_ioc_walkflow(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 8858275SEric Cheng { 8868275SEric Cheng dld_ioc_walkflow_t *wfp = karg; 8878275SEric Cheng 8888275SEric Cheng return (dld_walk_flow(wfp, arg)); 8898275SEric Cheng } 8908275SEric Cheng 8918275SEric Cheng /* 8925895Syz147064 * Check for GLDv3 autopush information. There are three cases: 8935895Syz147064 * 8945895Syz147064 * 1. If devp points to a GLDv3 datalink and it has autopush configuration, 8955895Syz147064 * fill dlap in with that information and return 0. 8965895Syz147064 * 8975895Syz147064 * 2. If devp points to a GLDv3 datalink but it doesn't have autopush 8985895Syz147064 * configuration, then replace devp with the physical device (if one 8995895Syz147064 * exists) and return 1. This allows stropen() to find the old-school 9005895Syz147064 * per-driver autopush configuration. (For softmac, the result is that 9015895Syz147064 * the softmac dev_t is replaced with the legacy device's dev_t). 9025895Syz147064 * 9035895Syz147064 * 3. If neither of the above apply, don't touch the args and return -1. 9045895Syz147064 */ 9055895Syz147064 int 9065895Syz147064 dld_autopush(dev_t *devp, struct dlautopush *dlap) 9075895Syz147064 { 9085895Syz147064 dld_ap_t *dap; 9095895Syz147064 datalink_id_t linkid; 9105895Syz147064 dev_t phydev; 9115895Syz147064 9125895Syz147064 if (!GLDV3_DRV(getmajor(*devp))) 9135895Syz147064 return (-1); 9145895Syz147064 9155895Syz147064 /* 9165895Syz147064 * Find the linkid by the link's dev_t. 9175895Syz147064 */ 9185895Syz147064 if (dls_devnet_dev2linkid(*devp, &linkid) != 0) 9195895Syz147064 return (-1); 9205895Syz147064 9215895Syz147064 /* 9225895Syz147064 * Find the autopush configuration associated with the linkid. 9235895Syz147064 */ 9245895Syz147064 rw_enter(&dld_ap_hash_lock, RW_READER); 9255895Syz147064 if (mod_hash_find(dld_ap_hashp, (mod_hash_key_t)(uintptr_t)linkid, 9265895Syz147064 (mod_hash_val_t *)&dap) == 0) { 9275895Syz147064 *dlap = dap->da_ap; 9285895Syz147064 rw_exit(&dld_ap_hash_lock); 9295895Syz147064 return (0); 9305895Syz147064 } 9315895Syz147064 rw_exit(&dld_ap_hash_lock); 9325895Syz147064 9335895Syz147064 if (dls_devnet_phydev(linkid, &phydev) != 0) 9345895Syz147064 return (-1); 9355895Syz147064 9365895Syz147064 *devp = phydev; 9375895Syz147064 return (1); 9385895Syz147064 } 9395895Syz147064 9405895Syz147064 /* 9413147Sxc151355 * Secure objects implementation 9423147Sxc151355 */ 9433147Sxc151355 9443147Sxc151355 /* ARGSUSED */ 9453147Sxc151355 static int 9463147Sxc151355 drv_secobj_ctor(void *buf, void *arg, int kmflag) 9473147Sxc151355 { 9483147Sxc151355 bzero(buf, sizeof (dld_secobj_t)); 9493147Sxc151355 return (0); 9503147Sxc151355 } 9513147Sxc151355 9523147Sxc151355 static void 9533147Sxc151355 drv_secobj_init(void) 9543147Sxc151355 { 9553147Sxc151355 rw_init(&drv_secobj_lock, NULL, RW_DEFAULT, NULL); 9563147Sxc151355 drv_secobj_cachep = kmem_cache_create("drv_secobj_cache", 9573147Sxc151355 sizeof (dld_secobj_t), 0, drv_secobj_ctor, NULL, 9583147Sxc151355 NULL, NULL, NULL, 0); 9593147Sxc151355 drv_secobj_hash = mod_hash_create_extended("drv_secobj_hash", 9603147Sxc151355 SECOBJ_WEP_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, 9613147Sxc151355 mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 9623147Sxc151355 } 9633147Sxc151355 9643147Sxc151355 static void 9653147Sxc151355 drv_secobj_fini(void) 9663147Sxc151355 { 9673147Sxc151355 mod_hash_destroy_hash(drv_secobj_hash); 9683147Sxc151355 kmem_cache_destroy(drv_secobj_cachep); 9693147Sxc151355 rw_destroy(&drv_secobj_lock); 9703147Sxc151355 } 9713147Sxc151355 9727408SSebastien.Roy@Sun.COM /* ARGSUSED */ 9737408SSebastien.Roy@Sun.COM static int 9748275SEric Cheng drv_ioc_secobj_set(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 9753147Sxc151355 { 9767408SSebastien.Roy@Sun.COM dld_ioc_secobj_set_t *ssp = karg; 9773147Sxc151355 dld_secobj_t *sobjp, *objp; 9787408SSebastien.Roy@Sun.COM int err; 9793147Sxc151355 9803147Sxc151355 sobjp = &ssp->ss_obj; 9813147Sxc151355 9824126Szf162725 if (sobjp->so_class != DLD_SECOBJ_CLASS_WEP && 9834126Szf162725 sobjp->so_class != DLD_SECOBJ_CLASS_WPA) 9847408SSebastien.Roy@Sun.COM return (EINVAL); 9853147Sxc151355 9863147Sxc151355 if (sobjp->so_name[DLD_SECOBJ_NAME_MAX - 1] != '\0' || 9873147Sxc151355 sobjp->so_len > DLD_SECOBJ_VAL_MAX) 9887408SSebastien.Roy@Sun.COM return (EINVAL); 9893147Sxc151355 9903147Sxc151355 rw_enter(&drv_secobj_lock, RW_WRITER); 9913147Sxc151355 err = mod_hash_find(drv_secobj_hash, (mod_hash_key_t)sobjp->so_name, 9923147Sxc151355 (mod_hash_val_t *)&objp); 9933147Sxc151355 if (err == 0) { 9943147Sxc151355 if ((ssp->ss_flags & DLD_SECOBJ_OPT_CREATE) != 0) { 9953147Sxc151355 rw_exit(&drv_secobj_lock); 9967408SSebastien.Roy@Sun.COM return (EEXIST); 9973147Sxc151355 } 9983147Sxc151355 } else { 9993147Sxc151355 ASSERT(err == MH_ERR_NOTFOUND); 10003147Sxc151355 if ((ssp->ss_flags & DLD_SECOBJ_OPT_CREATE) == 0) { 10013147Sxc151355 rw_exit(&drv_secobj_lock); 10027408SSebastien.Roy@Sun.COM return (ENOENT); 10033147Sxc151355 } 10043147Sxc151355 objp = kmem_cache_alloc(drv_secobj_cachep, KM_SLEEP); 10053147Sxc151355 (void) strlcpy(objp->so_name, sobjp->so_name, 10063147Sxc151355 DLD_SECOBJ_NAME_MAX); 10073147Sxc151355 10087408SSebastien.Roy@Sun.COM VERIFY(mod_hash_insert(drv_secobj_hash, 10097408SSebastien.Roy@Sun.COM (mod_hash_key_t)objp->so_name, (mod_hash_val_t)objp) == 0); 10103147Sxc151355 } 10113147Sxc151355 bcopy(sobjp->so_val, objp->so_val, sobjp->so_len); 10123147Sxc151355 objp->so_len = sobjp->so_len; 10133147Sxc151355 objp->so_class = sobjp->so_class; 10143147Sxc151355 rw_exit(&drv_secobj_lock); 10157408SSebastien.Roy@Sun.COM return (0); 10163147Sxc151355 } 10173147Sxc151355 10183147Sxc151355 typedef struct dld_secobj_state { 10193147Sxc151355 uint_t ss_free; 10203147Sxc151355 uint_t ss_count; 10213147Sxc151355 int ss_rc; 10227408SSebastien.Roy@Sun.COM int ss_mode; 10233147Sxc151355 dld_secobj_t *ss_objp; 10243147Sxc151355 } dld_secobj_state_t; 10253147Sxc151355 10263147Sxc151355 /* ARGSUSED */ 10273147Sxc151355 static uint_t 10283147Sxc151355 drv_secobj_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 10293147Sxc151355 { 10303147Sxc151355 dld_secobj_state_t *statep = arg; 10313147Sxc151355 dld_secobj_t *sobjp = (dld_secobj_t *)val; 10323147Sxc151355 10333147Sxc151355 if (statep->ss_free < sizeof (dld_secobj_t)) { 10343147Sxc151355 statep->ss_rc = ENOSPC; 10353147Sxc151355 return (MH_WALK_TERMINATE); 10363147Sxc151355 } 10377408SSebastien.Roy@Sun.COM if (ddi_copyout(sobjp, statep->ss_objp, sizeof (*sobjp), 10387408SSebastien.Roy@Sun.COM statep->ss_mode) != 0) { 10397408SSebastien.Roy@Sun.COM statep->ss_rc = EFAULT; 10407408SSebastien.Roy@Sun.COM return (MH_WALK_TERMINATE); 10417408SSebastien.Roy@Sun.COM } 10423147Sxc151355 statep->ss_objp++; 10433147Sxc151355 statep->ss_free -= sizeof (dld_secobj_t); 10443147Sxc151355 statep->ss_count++; 10453147Sxc151355 return (MH_WALK_CONTINUE); 10463147Sxc151355 } 10473147Sxc151355 10487408SSebastien.Roy@Sun.COM /* ARGSUSED */ 10497408SSebastien.Roy@Sun.COM static int 10508275SEric Cheng drv_ioc_secobj_get(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 10513147Sxc151355 { 10527408SSebastien.Roy@Sun.COM dld_ioc_secobj_get_t *sgp = karg; 10533147Sxc151355 dld_secobj_t *sobjp, *objp; 10547408SSebastien.Roy@Sun.COM int err; 10553147Sxc151355 10563147Sxc151355 sobjp = &sgp->sg_obj; 10573147Sxc151355 if (sobjp->so_name[DLD_SECOBJ_NAME_MAX - 1] != '\0') 10587408SSebastien.Roy@Sun.COM return (EINVAL); 10593147Sxc151355 10603147Sxc151355 rw_enter(&drv_secobj_lock, RW_READER); 10613147Sxc151355 if (sobjp->so_name[0] != '\0') { 10623147Sxc151355 err = mod_hash_find(drv_secobj_hash, 10633147Sxc151355 (mod_hash_key_t)sobjp->so_name, (mod_hash_val_t *)&objp); 10643147Sxc151355 if (err != 0) { 10653147Sxc151355 ASSERT(err == MH_ERR_NOTFOUND); 10663147Sxc151355 rw_exit(&drv_secobj_lock); 10677408SSebastien.Roy@Sun.COM return (ENOENT); 10683147Sxc151355 } 10693147Sxc151355 bcopy(objp->so_val, sobjp->so_val, objp->so_len); 10703147Sxc151355 sobjp->so_len = objp->so_len; 10713147Sxc151355 sobjp->so_class = objp->so_class; 10723147Sxc151355 sgp->sg_count = 1; 10733147Sxc151355 } else { 10743147Sxc151355 dld_secobj_state_t state; 10753147Sxc151355 10767408SSebastien.Roy@Sun.COM state.ss_free = sgp->sg_size - sizeof (dld_ioc_secobj_get_t); 10773147Sxc151355 state.ss_count = 0; 10783147Sxc151355 state.ss_rc = 0; 10797408SSebastien.Roy@Sun.COM state.ss_mode = mode; 10807408SSebastien.Roy@Sun.COM state.ss_objp = (dld_secobj_t *)((uchar_t *)arg + 10817408SSebastien.Roy@Sun.COM sizeof (dld_ioc_secobj_get_t)); 10827408SSebastien.Roy@Sun.COM 10833147Sxc151355 mod_hash_walk(drv_secobj_hash, drv_secobj_walker, &state); 10843147Sxc151355 if (state.ss_rc != 0) { 10853147Sxc151355 rw_exit(&drv_secobj_lock); 10867408SSebastien.Roy@Sun.COM return (state.ss_rc); 10873147Sxc151355 } 10883147Sxc151355 sgp->sg_count = state.ss_count; 10893147Sxc151355 } 10903147Sxc151355 rw_exit(&drv_secobj_lock); 10917408SSebastien.Roy@Sun.COM return (0); 10923147Sxc151355 } 10933147Sxc151355 10947408SSebastien.Roy@Sun.COM /* ARGSUSED */ 10957408SSebastien.Roy@Sun.COM static int 10968275SEric Cheng drv_ioc_secobj_unset(void *karg, intptr_t arg, int mode, cred_t *cred, 10978275SEric Cheng int *rvalp) 10983147Sxc151355 { 10997408SSebastien.Roy@Sun.COM dld_ioc_secobj_unset_t *sup = karg; 11003147Sxc151355 dld_secobj_t *objp; 11013147Sxc151355 mod_hash_val_t val; 11027408SSebastien.Roy@Sun.COM int err; 11033147Sxc151355 11043147Sxc151355 if (sup->su_name[DLD_SECOBJ_NAME_MAX - 1] != '\0') 11057408SSebastien.Roy@Sun.COM return (EINVAL); 11063147Sxc151355 11073147Sxc151355 rw_enter(&drv_secobj_lock, RW_WRITER); 11083147Sxc151355 err = mod_hash_find(drv_secobj_hash, (mod_hash_key_t)sup->su_name, 11093147Sxc151355 (mod_hash_val_t *)&objp); 11103147Sxc151355 if (err != 0) { 11113147Sxc151355 ASSERT(err == MH_ERR_NOTFOUND); 11123147Sxc151355 rw_exit(&drv_secobj_lock); 11137408SSebastien.Roy@Sun.COM return (ENOENT); 11143147Sxc151355 } 11157408SSebastien.Roy@Sun.COM VERIFY(mod_hash_remove(drv_secobj_hash, (mod_hash_key_t)sup->su_name, 11167408SSebastien.Roy@Sun.COM (mod_hash_val_t *)&val) == 0); 11173147Sxc151355 ASSERT(objp == (dld_secobj_t *)val); 11183147Sxc151355 11193147Sxc151355 kmem_cache_free(drv_secobj_cachep, objp); 11203147Sxc151355 rw_exit(&drv_secobj_lock); 11217408SSebastien.Roy@Sun.COM return (0); 11227408SSebastien.Roy@Sun.COM } 11237408SSebastien.Roy@Sun.COM 11248275SEric Cheng static int 11258275SEric Cheng drv_check_policy(dld_ioc_info_t *info, cred_t *cred) 11268275SEric Cheng { 11278275SEric Cheng int i, err = 0; 11288275SEric Cheng 11298275SEric Cheng for (i = 0; info->di_priv[i] != NULL && i < DLD_MAX_PRIV; i++) { 11308275SEric Cheng if ((err = secpolicy_dld_ioctl(cred, info->di_priv[i], 11318275SEric Cheng "dld ioctl")) != 0) { 11328275SEric Cheng break; 11338275SEric Cheng } 11348275SEric Cheng } 11358275SEric Cheng if (err == 0) 11368275SEric Cheng return (0); 11378275SEric Cheng 11388275SEric Cheng return (secpolicy_net_config(cred, B_FALSE)); 11398275SEric Cheng } 11408275SEric Cheng 11417408SSebastien.Roy@Sun.COM static dld_ioc_info_t drv_ioc_list[] = { 11427408SSebastien.Roy@Sun.COM {DLDIOC_ATTR, DLDCOPYINOUT, sizeof (dld_ioc_attr_t), 11438275SEric Cheng drv_ioc_attr, {NULL}}, 11447408SSebastien.Roy@Sun.COM {DLDIOC_PHYS_ATTR, DLDCOPYINOUT, sizeof (dld_ioc_phys_attr_t), 11458275SEric Cheng drv_ioc_phys_attr, {NULL}}, 11468275SEric Cheng {DLDIOC_SECOBJ_SET, DLDCOPYIN, sizeof (dld_ioc_secobj_set_t), 11478275SEric Cheng drv_ioc_secobj_set, {PRIV_SYS_DL_CONFIG}}, 11488275SEric Cheng {DLDIOC_SECOBJ_GET, DLDCOPYINOUT, sizeof (dld_ioc_secobj_get_t), 11498275SEric Cheng drv_ioc_secobj_get, {PRIV_SYS_DL_CONFIG}}, 11508275SEric Cheng {DLDIOC_SECOBJ_UNSET, DLDCOPYIN, sizeof (dld_ioc_secobj_unset_t), 11518275SEric Cheng drv_ioc_secobj_unset, {PRIV_SYS_DL_CONFIG}}, 11528275SEric Cheng {DLDIOC_DOORSERVER, DLDCOPYIN, sizeof (dld_ioc_door_t), 11538275SEric Cheng drv_ioc_doorserver, {PRIV_SYS_DL_CONFIG}}, 11548275SEric Cheng {DLDIOC_RENAME, DLDCOPYIN, sizeof (dld_ioc_rename_t), 11558275SEric Cheng drv_ioc_rename, {PRIV_SYS_DL_CONFIG}}, 11568275SEric Cheng {DLDIOC_MACADDRGET, DLDCOPYINOUT, sizeof (dld_ioc_macaddrget_t), 11578275SEric Cheng drv_ioc_macaddrget, {PRIV_SYS_DL_CONFIG}}, 11588275SEric Cheng {DLDIOC_ADDFLOW, DLDCOPYIN, sizeof (dld_ioc_addflow_t), 11598275SEric Cheng drv_ioc_addflow, {PRIV_SYS_DL_CONFIG}}, 11608275SEric Cheng {DLDIOC_REMOVEFLOW, DLDCOPYIN, sizeof (dld_ioc_removeflow_t), 11618275SEric Cheng drv_ioc_removeflow, {PRIV_SYS_DL_CONFIG}}, 11628275SEric Cheng {DLDIOC_MODIFYFLOW, DLDCOPYIN, sizeof (dld_ioc_modifyflow_t), 11638275SEric Cheng drv_ioc_modifyflow, {PRIV_SYS_DL_CONFIG}}, 11648275SEric Cheng {DLDIOC_WALKFLOW, DLDCOPYINOUT, sizeof (dld_ioc_walkflow_t), 11658275SEric Cheng drv_ioc_walkflow, {NULL}}, 11668275SEric Cheng {DLDIOC_USAGELOG, DLDCOPYIN, sizeof (dld_ioc_usagelog_t), 11678275SEric Cheng drv_ioc_usagelog, {PRIV_SYS_DL_CONFIG}}, 11688275SEric Cheng {DLDIOC_SETMACPROP, DLDCOPYIN, sizeof (dld_ioc_macprop_t), 11698275SEric Cheng drv_ioc_setprop, {PRIV_SYS_DL_CONFIG}}, 11707408SSebastien.Roy@Sun.COM {DLDIOC_GETMACPROP, DLDCOPYIN, sizeof (dld_ioc_macprop_t), 11718275SEric Cheng drv_ioc_getprop, {NULL}}, 11728275SEric Cheng {DLDIOC_GETHWGRP, DLDCOPYINOUT, sizeof (dld_ioc_hwgrpget_t), 11738275SEric Cheng drv_ioc_hwgrpget, {PRIV_SYS_DL_CONFIG}}, 11747408SSebastien.Roy@Sun.COM }; 11757408SSebastien.Roy@Sun.COM 11767408SSebastien.Roy@Sun.COM typedef struct dld_ioc_modentry { 11777408SSebastien.Roy@Sun.COM uint16_t dim_modid; /* Top 16 bits of ioctl command */ 11787408SSebastien.Roy@Sun.COM char *dim_modname; /* Module to be loaded */ 11797408SSebastien.Roy@Sun.COM dld_ioc_info_t *dim_list; /* array of ioctl structures */ 11807408SSebastien.Roy@Sun.COM uint_t dim_count; /* number of elements in dim_list */ 11817408SSebastien.Roy@Sun.COM } dld_ioc_modentry_t; 11827408SSebastien.Roy@Sun.COM 11837408SSebastien.Roy@Sun.COM /* 11847408SSebastien.Roy@Sun.COM * For all modules except for dld, dim_list and dim_count are assigned 11857408SSebastien.Roy@Sun.COM * when the modules register their ioctls in dld_ioc_register(). We 11867408SSebastien.Roy@Sun.COM * can statically initialize dld's ioctls in-line here; there's no 11877408SSebastien.Roy@Sun.COM * need for it to call dld_ioc_register() itself. 11887408SSebastien.Roy@Sun.COM */ 11897408SSebastien.Roy@Sun.COM static dld_ioc_modentry_t dld_ioc_modtable[] = { 11907408SSebastien.Roy@Sun.COM {DLD_IOC, "dld", drv_ioc_list, DLDIOCCNT(drv_ioc_list)}, 11917408SSebastien.Roy@Sun.COM {AGGR_IOC, "aggr", NULL, 0}, 11927408SSebastien.Roy@Sun.COM {VNIC_IOC, "vnic", NULL, 0} 11937408SSebastien.Roy@Sun.COM }; 11947408SSebastien.Roy@Sun.COM #define DLDIOC_CNT \ 11957408SSebastien.Roy@Sun.COM (sizeof (dld_ioc_modtable) / sizeof (dld_ioc_modentry_t)) 11967408SSebastien.Roy@Sun.COM 11977408SSebastien.Roy@Sun.COM static dld_ioc_modentry_t * 11987408SSebastien.Roy@Sun.COM dld_ioc_findmod(uint16_t modid) 11997408SSebastien.Roy@Sun.COM { 12007408SSebastien.Roy@Sun.COM int i; 12017408SSebastien.Roy@Sun.COM 12027408SSebastien.Roy@Sun.COM for (i = 0; i < DLDIOC_CNT; i++) { 12037408SSebastien.Roy@Sun.COM if (modid == dld_ioc_modtable[i].dim_modid) 12047408SSebastien.Roy@Sun.COM return (&dld_ioc_modtable[i]); 12057408SSebastien.Roy@Sun.COM } 12067408SSebastien.Roy@Sun.COM return (NULL); 12077408SSebastien.Roy@Sun.COM } 12087408SSebastien.Roy@Sun.COM 12097408SSebastien.Roy@Sun.COM int 12107408SSebastien.Roy@Sun.COM dld_ioc_register(uint16_t modid, dld_ioc_info_t *list, uint_t count) 12117408SSebastien.Roy@Sun.COM { 12127408SSebastien.Roy@Sun.COM dld_ioc_modentry_t *dim = dld_ioc_findmod(modid); 12137408SSebastien.Roy@Sun.COM 12147408SSebastien.Roy@Sun.COM if (dim == NULL) 12157408SSebastien.Roy@Sun.COM return (ENOENT); 12167408SSebastien.Roy@Sun.COM 12177408SSebastien.Roy@Sun.COM dim->dim_list = list; 12187408SSebastien.Roy@Sun.COM dim->dim_count = count; 12197408SSebastien.Roy@Sun.COM return (0); 12207408SSebastien.Roy@Sun.COM } 12217408SSebastien.Roy@Sun.COM 12227408SSebastien.Roy@Sun.COM void 12237408SSebastien.Roy@Sun.COM dld_ioc_unregister(uint16_t modid) 12247408SSebastien.Roy@Sun.COM { 12257408SSebastien.Roy@Sun.COM VERIFY(dld_ioc_register(modid, NULL, 0) == 0); 12267408SSebastien.Roy@Sun.COM } 12273147Sxc151355 12287408SSebastien.Roy@Sun.COM /* 12297408SSebastien.Roy@Sun.COM * The general design with GLDv3 ioctls is that all ioctls issued 12307408SSebastien.Roy@Sun.COM * through /dev/dld go through this drv_ioctl() function. This 12317408SSebastien.Roy@Sun.COM * function handles all ioctls on behalf of modules listed in 12327408SSebastien.Roy@Sun.COM * dld_ioc_modtable. 12337408SSebastien.Roy@Sun.COM * 12347408SSebastien.Roy@Sun.COM * When an ioctl is received, this function looks for the associated 12357408SSebastien.Roy@Sun.COM * module-id-specific ioctl information using dld_ioc_findmod(). The 12367408SSebastien.Roy@Sun.COM * call to ddi_hold_devi_by_instance() on the associated device will 12377408SSebastien.Roy@Sun.COM * cause the kernel module responsible for the ioctl to be loaded if 12387408SSebastien.Roy@Sun.COM * it's not already loaded, which should result in that module calling 12397408SSebastien.Roy@Sun.COM * dld_ioc_register(), thereby filling in the dim_list containing the 12407408SSebastien.Roy@Sun.COM * details for the ioctl being processed. 12417408SSebastien.Roy@Sun.COM * 12427408SSebastien.Roy@Sun.COM * This function can then perform operations such as copyin() data and 12437408SSebastien.Roy@Sun.COM * do credential checks based on the registered ioctl information, 12447408SSebastien.Roy@Sun.COM * then issue the callback function di_func() registered by the 12457408SSebastien.Roy@Sun.COM * responsible module. Upon return, the appropriate copyout() 12467408SSebastien.Roy@Sun.COM * operation can be performed and the operation completes. 12477408SSebastien.Roy@Sun.COM */ 12487408SSebastien.Roy@Sun.COM /* ARGSUSED */ 12497408SSebastien.Roy@Sun.COM static int 12507408SSebastien.Roy@Sun.COM drv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred, int *rvalp) 12517408SSebastien.Roy@Sun.COM { 12527408SSebastien.Roy@Sun.COM dld_ioc_modentry_t *dim; 12537408SSebastien.Roy@Sun.COM dld_ioc_info_t *info; 12547408SSebastien.Roy@Sun.COM dev_info_t *dip = NULL; 12557408SSebastien.Roy@Sun.COM void *buf = NULL; 12567408SSebastien.Roy@Sun.COM size_t sz; 12577408SSebastien.Roy@Sun.COM int i, err; 12587408SSebastien.Roy@Sun.COM 12597408SSebastien.Roy@Sun.COM if ((dim = dld_ioc_findmod(DLD_IOC_MODID(cmd))) == NULL) 12607408SSebastien.Roy@Sun.COM return (ENOTSUP); 12617408SSebastien.Roy@Sun.COM 12627408SSebastien.Roy@Sun.COM dip = ddi_hold_devi_by_instance(ddi_name_to_major(dim->dim_modname), 12637408SSebastien.Roy@Sun.COM 0, 0); 12647408SSebastien.Roy@Sun.COM if (dip == NULL || dim->dim_list == NULL) { 12657408SSebastien.Roy@Sun.COM err = ENODEV; 12667408SSebastien.Roy@Sun.COM goto done; 12677408SSebastien.Roy@Sun.COM } 12687408SSebastien.Roy@Sun.COM 12697408SSebastien.Roy@Sun.COM for (i = 0; i < dim->dim_count; i++) { 12707408SSebastien.Roy@Sun.COM if (cmd == dim->dim_list[i].di_cmd) 12717408SSebastien.Roy@Sun.COM break; 12727408SSebastien.Roy@Sun.COM } 12737408SSebastien.Roy@Sun.COM if (i == dim->dim_count) { 12747408SSebastien.Roy@Sun.COM err = ENOTSUP; 12757408SSebastien.Roy@Sun.COM goto done; 12767408SSebastien.Roy@Sun.COM } 12777408SSebastien.Roy@Sun.COM 12787408SSebastien.Roy@Sun.COM info = &dim->dim_list[i]; 12798275SEric Cheng if ((err = drv_check_policy(info, cred)) != 0) 12807408SSebastien.Roy@Sun.COM goto done; 12817408SSebastien.Roy@Sun.COM 12827408SSebastien.Roy@Sun.COM sz = info->di_argsize; 12837408SSebastien.Roy@Sun.COM if ((buf = kmem_zalloc(sz, KM_NOSLEEP)) == NULL) { 12847408SSebastien.Roy@Sun.COM err = ENOMEM; 12857408SSebastien.Roy@Sun.COM goto done; 12867408SSebastien.Roy@Sun.COM } 12877408SSebastien.Roy@Sun.COM 12887408SSebastien.Roy@Sun.COM if ((info->di_flags & DLDCOPYIN) && 12897408SSebastien.Roy@Sun.COM ddi_copyin((void *)arg, buf, sz, mode) != 0) { 12907408SSebastien.Roy@Sun.COM err = EFAULT; 12917408SSebastien.Roy@Sun.COM goto done; 12927408SSebastien.Roy@Sun.COM } 12937408SSebastien.Roy@Sun.COM 12948275SEric Cheng err = info->di_func(buf, arg, mode, cred, rvalp); 12957408SSebastien.Roy@Sun.COM 12967408SSebastien.Roy@Sun.COM if ((info->di_flags & DLDCOPYOUT) && 12977408SSebastien.Roy@Sun.COM ddi_copyout(buf, (void *)arg, sz, mode) != 0 && err == 0) 12987408SSebastien.Roy@Sun.COM err = EFAULT; 12997408SSebastien.Roy@Sun.COM 13007408SSebastien.Roy@Sun.COM done: 13017408SSebastien.Roy@Sun.COM if (buf != NULL) 13027408SSebastien.Roy@Sun.COM kmem_free(buf, sz); 13037408SSebastien.Roy@Sun.COM if (dip != NULL) 13047408SSebastien.Roy@Sun.COM ddi_release_devi(dip); 13057408SSebastien.Roy@Sun.COM return (err); 13063147Sxc151355 } 1307