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 /* 221cfa752fSRamaswamy Tummala * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 2359596c01SRobert Mustacchi * Copyright (c) 2017, Joyent, Inc. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * Data-Link Driver 287c478bd9Sstevel@tonic-gate */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <sys/conf.h> 31210db224Sericheng #include <sys/mkdev.h> 327c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 33210db224Sericheng #include <sys/stat.h> 347c478bd9Sstevel@tonic-gate #include <sys/dld_impl.h> 3582a2fc47SJames Carlson #include <sys/dld_ioc.h> 36210db224Sericheng #include <sys/dls_impl.h> 37d62bc4baSyz147064 #include <sys/softmac.h> 38da14cebeSEric Cheng #include <sys/mac.h> 39da14cebeSEric Cheng #include <sys/mac_ether.h> 40da14cebeSEric Cheng #include <sys/mac_client.h> 41da14cebeSEric Cheng #include <sys/mac_client_impl.h> 42da14cebeSEric Cheng #include <sys/mac_client_priv.h> 43210db224Sericheng #include <inet/common.h> 44da14cebeSEric Cheng #include <sys/policy.h> 45da14cebeSEric Cheng #include <sys/priv_names.h> 462b24ab6bSSebastien Roy #include <sys/zone.h> 470591ddd0SPrakash Jalan #include <sys/sysmacros.h> 48210db224Sericheng 497c478bd9Sstevel@tonic-gate static void drv_init(void); 507c478bd9Sstevel@tonic-gate static int drv_fini(void); 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate static int drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 537c478bd9Sstevel@tonic-gate static int drv_attach(dev_info_t *, ddi_attach_cmd_t); 547c478bd9Sstevel@tonic-gate static int drv_detach(dev_info_t *, ddi_detach_cmd_t); 557c478bd9Sstevel@tonic-gate 56210db224Sericheng /* 570ba2cbe9Sxc151355 * Secure objects declarations 580ba2cbe9Sxc151355 */ 590ba2cbe9Sxc151355 #define SECOBJ_WEP_HASHSZ 67 600ba2cbe9Sxc151355 static krwlock_t drv_secobj_lock; 610ba2cbe9Sxc151355 static kmem_cache_t *drv_secobj_cachep; 620ba2cbe9Sxc151355 static mod_hash_t *drv_secobj_hash; 630ba2cbe9Sxc151355 static void drv_secobj_init(void); 640ba2cbe9Sxc151355 static void drv_secobj_fini(void); 653bc21d0aSAruna Ramakrishna - Sun Microsystems static int drv_ioc_setap(datalink_id_t, struct dlautopush *); 663bc21d0aSAruna Ramakrishna - Sun Microsystems static int drv_ioc_getap(datalink_id_t, struct dlautopush *); 673bc21d0aSAruna Ramakrishna - Sun Microsystems static int drv_ioc_clrap(datalink_id_t); 680ba2cbe9Sxc151355 69eae72b5bSSebastien Roy 700ba2cbe9Sxc151355 /* 71210db224Sericheng * The following entry points are private to dld and are used for control 72210db224Sericheng * operations only. The entry points exported to mac drivers are defined 73210db224Sericheng * in dld_str.c. Refer to the comment on top of dld_str.c for details. 74210db224Sericheng */ 75eae72b5bSSebastien Roy static int drv_open(dev_t *, int, int, cred_t *); 76eae72b5bSSebastien Roy static int drv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 777c478bd9Sstevel@tonic-gate 78eae72b5bSSebastien Roy static dev_info_t *dld_dip; /* dev_info_t for the driver */ 79210db224Sericheng uint32_t dld_opt = 0; /* Global options */ 807c478bd9Sstevel@tonic-gate 81d62bc4baSyz147064 #define NAUTOPUSH 32 82d62bc4baSyz147064 static mod_hash_t *dld_ap_hashp; 83d62bc4baSyz147064 static krwlock_t dld_ap_hash_lock; 84d62bc4baSyz147064 85eae72b5bSSebastien Roy static struct cb_ops drv_cb_ops = { 86eae72b5bSSebastien Roy drv_open, /* open */ 87eae72b5bSSebastien Roy nulldev, /* close */ 88eae72b5bSSebastien Roy nulldev, /* strategy */ 89eae72b5bSSebastien Roy nulldev, /* print */ 90eae72b5bSSebastien Roy nodev, /* dump */ 91eae72b5bSSebastien Roy nodev, /* read */ 92eae72b5bSSebastien Roy nodev, /* write */ 93eae72b5bSSebastien Roy drv_ioctl, /* ioctl */ 94eae72b5bSSebastien Roy nodev, /* devmap */ 95eae72b5bSSebastien Roy nodev, /* mmap */ 96eae72b5bSSebastien Roy nodev, /* segmap */ 97eae72b5bSSebastien Roy nochpoll, /* poll */ 98eae72b5bSSebastien Roy ddi_prop_op, /* cb_prop_op */ 99eae72b5bSSebastien Roy 0, /* streamtab */ 100eae72b5bSSebastien Roy D_MP /* Driver compatibility flag */ 1017c478bd9Sstevel@tonic-gate }; 1027c478bd9Sstevel@tonic-gate 103eae72b5bSSebastien Roy static struct dev_ops drv_ops = { 104eae72b5bSSebastien Roy DEVO_REV, /* devo_rev */ 105eae72b5bSSebastien Roy 0, /* refcnt */ 106eae72b5bSSebastien Roy drv_getinfo, /* get_dev_info */ 107eae72b5bSSebastien Roy nulldev, /* identify */ 108eae72b5bSSebastien Roy nulldev, /* probe */ 109eae72b5bSSebastien Roy drv_attach, /* attach */ 110eae72b5bSSebastien Roy drv_detach, /* detach */ 111eae72b5bSSebastien Roy nodev, /* reset */ 112eae72b5bSSebastien Roy &drv_cb_ops, /* driver operations */ 113eae72b5bSSebastien Roy NULL, /* bus operations */ 11419397407SSherry Moore nodev, /* dev power */ 11519397407SSherry Moore ddi_quiesce_not_supported, /* dev quiesce */ 1167c478bd9Sstevel@tonic-gate }; 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate /* 1197c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 1207c478bd9Sstevel@tonic-gate */ 1217c478bd9Sstevel@tonic-gate static struct modldrv drv_modldrv = { 1227c478bd9Sstevel@tonic-gate &mod_driverops, 1237c478bd9Sstevel@tonic-gate DLD_INFO, 1247c478bd9Sstevel@tonic-gate &drv_ops 1257c478bd9Sstevel@tonic-gate }; 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate static struct modlinkage drv_modlinkage = { 1287c478bd9Sstevel@tonic-gate MODREV_1, 1297c478bd9Sstevel@tonic-gate &drv_modldrv, 1307c478bd9Sstevel@tonic-gate NULL 1317c478bd9Sstevel@tonic-gate }; 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate int 1347c478bd9Sstevel@tonic-gate _init(void) 1357c478bd9Sstevel@tonic-gate { 136eae72b5bSSebastien Roy return (mod_install(&drv_modlinkage)); 1377c478bd9Sstevel@tonic-gate } 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate int 1407c478bd9Sstevel@tonic-gate _fini(void) 1417c478bd9Sstevel@tonic-gate { 142eae72b5bSSebastien Roy return (mod_remove(&drv_modlinkage)); 1437c478bd9Sstevel@tonic-gate } 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate int 1467c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 1477c478bd9Sstevel@tonic-gate { 1487c478bd9Sstevel@tonic-gate return (mod_info(&drv_modlinkage, modinfop)); 1497c478bd9Sstevel@tonic-gate } 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate /* 152210db224Sericheng * Initialize component modules. 1537c478bd9Sstevel@tonic-gate */ 1547c478bd9Sstevel@tonic-gate static void 1557c478bd9Sstevel@tonic-gate drv_init(void) 1567c478bd9Sstevel@tonic-gate { 1570ba2cbe9Sxc151355 drv_secobj_init(); 1587c478bd9Sstevel@tonic-gate dld_str_init(); 159da14cebeSEric Cheng 160d62bc4baSyz147064 /* 161d62bc4baSyz147064 * Create a hash table for autopush configuration. 162d62bc4baSyz147064 */ 163d62bc4baSyz147064 dld_ap_hashp = mod_hash_create_idhash("dld_autopush_hash", 164d62bc4baSyz147064 NAUTOPUSH, mod_hash_null_valdtor); 165d62bc4baSyz147064 166d62bc4baSyz147064 ASSERT(dld_ap_hashp != NULL); 167d62bc4baSyz147064 rw_init(&dld_ap_hash_lock, NULL, RW_DRIVER, NULL); 168d62bc4baSyz147064 } 169d62bc4baSyz147064 170d62bc4baSyz147064 /* ARGSUSED */ 171d62bc4baSyz147064 static uint_t 172d62bc4baSyz147064 drv_ap_exist(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 173d62bc4baSyz147064 { 174d62bc4baSyz147064 boolean_t *pexist = arg; 175d62bc4baSyz147064 176d62bc4baSyz147064 *pexist = B_TRUE; 177d62bc4baSyz147064 return (MH_WALK_TERMINATE); 1787c478bd9Sstevel@tonic-gate } 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate static int 1817c478bd9Sstevel@tonic-gate drv_fini(void) 1827c478bd9Sstevel@tonic-gate { 1837c478bd9Sstevel@tonic-gate int err; 184d62bc4baSyz147064 boolean_t exist = B_FALSE; 185d62bc4baSyz147064 186d62bc4baSyz147064 rw_enter(&dld_ap_hash_lock, RW_READER); 187d62bc4baSyz147064 mod_hash_walk(dld_ap_hashp, drv_ap_exist, &exist); 188d62bc4baSyz147064 rw_exit(&dld_ap_hash_lock); 189d62bc4baSyz147064 if (exist) 190d62bc4baSyz147064 return (EBUSY); 1917c478bd9Sstevel@tonic-gate 192210db224Sericheng if ((err = dld_str_fini()) != 0) 1937c478bd9Sstevel@tonic-gate return (err); 1947c478bd9Sstevel@tonic-gate 1950ba2cbe9Sxc151355 drv_secobj_fini(); 196d62bc4baSyz147064 mod_hash_destroy_idhash(dld_ap_hashp); 197d62bc4baSyz147064 rw_destroy(&dld_ap_hash_lock); 1987c478bd9Sstevel@tonic-gate return (0); 1997c478bd9Sstevel@tonic-gate } 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate /* 2027c478bd9Sstevel@tonic-gate * devo_getinfo: getinfo(9e) 2037c478bd9Sstevel@tonic-gate */ 2047c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2057c478bd9Sstevel@tonic-gate static int 2067c478bd9Sstevel@tonic-gate drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resp) 2077c478bd9Sstevel@tonic-gate { 2087c478bd9Sstevel@tonic-gate if (dld_dip == NULL) 2097c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate switch (cmd) { 2127c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 213eae72b5bSSebastien Roy *resp = 0; 2147c478bd9Sstevel@tonic-gate break; 2157c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 216eae72b5bSSebastien Roy *resp = dld_dip; 2177c478bd9Sstevel@tonic-gate break; 2187c478bd9Sstevel@tonic-gate default: 2197c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2207c478bd9Sstevel@tonic-gate } 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2237c478bd9Sstevel@tonic-gate } 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate /* 2267c478bd9Sstevel@tonic-gate * Check properties to set options. (See dld.h for property definitions). 2277c478bd9Sstevel@tonic-gate */ 2287c478bd9Sstevel@tonic-gate static void 2297c478bd9Sstevel@tonic-gate drv_set_opt(dev_info_t *dip) 2307c478bd9Sstevel@tonic-gate { 2317c478bd9Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 2327c478bd9Sstevel@tonic-gate DLD_PROP_NO_FASTPATH, 0) != 0) { 2337c478bd9Sstevel@tonic-gate dld_opt |= DLD_OPT_NO_FASTPATH; 2347c478bd9Sstevel@tonic-gate } 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 2377c478bd9Sstevel@tonic-gate DLD_PROP_NO_POLL, 0) != 0) { 2387c478bd9Sstevel@tonic-gate dld_opt |= DLD_OPT_NO_POLL; 2397c478bd9Sstevel@tonic-gate } 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 2427c478bd9Sstevel@tonic-gate DLD_PROP_NO_ZEROCOPY, 0) != 0) { 2437c478bd9Sstevel@tonic-gate dld_opt |= DLD_OPT_NO_ZEROCOPY; 2447c478bd9Sstevel@tonic-gate } 2459c175129Sja97890 2469c175129Sja97890 if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 2479c175129Sja97890 DLD_PROP_NO_SOFTRING, 0) != 0) { 2489c175129Sja97890 dld_opt |= DLD_OPT_NO_SOFTRING; 2499c175129Sja97890 } 2507c478bd9Sstevel@tonic-gate } 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate /* 2537c478bd9Sstevel@tonic-gate * devo_attach: attach(9e) 2547c478bd9Sstevel@tonic-gate */ 2557c478bd9Sstevel@tonic-gate static int 2567c478bd9Sstevel@tonic-gate drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2577c478bd9Sstevel@tonic-gate { 2587c478bd9Sstevel@tonic-gate if (cmd != DDI_ATTACH) 2597c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate ASSERT(ddi_get_instance(dip) == 0); 262eae72b5bSSebastien Roy drv_init(); 2637c478bd9Sstevel@tonic-gate drv_set_opt(dip); 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate /* 2667c478bd9Sstevel@tonic-gate * Create control node. DLPI provider nodes will be created on demand. 2677c478bd9Sstevel@tonic-gate */ 2687c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(dip, DLD_CONTROL_MINOR_NAME, S_IFCHR, 2697c478bd9Sstevel@tonic-gate DLD_CONTROL_MINOR, DDI_PSEUDO, 0) != DDI_SUCCESS) 2707c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate dld_dip = dip; 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate /* 2757c478bd9Sstevel@tonic-gate * Log the fact that the driver is now attached. 2767c478bd9Sstevel@tonic-gate */ 2777c478bd9Sstevel@tonic-gate ddi_report_dev(dip); 2787c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2797c478bd9Sstevel@tonic-gate } 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate /* 2827c478bd9Sstevel@tonic-gate * devo_detach: detach(9e) 2837c478bd9Sstevel@tonic-gate */ 2847c478bd9Sstevel@tonic-gate static int 2857c478bd9Sstevel@tonic-gate drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2867c478bd9Sstevel@tonic-gate { 2877c478bd9Sstevel@tonic-gate if (cmd != DDI_DETACH) 2887c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate ASSERT(dld_dip == dip); 291eae72b5bSSebastien Roy if (drv_fini() != 0) 292eae72b5bSSebastien Roy return (DDI_FAILURE); 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate /* 2957c478bd9Sstevel@tonic-gate * Remove the control node. 2967c478bd9Sstevel@tonic-gate */ 2977c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, DLD_CONTROL_MINOR_NAME); 2987c478bd9Sstevel@tonic-gate dld_dip = NULL; 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3017c478bd9Sstevel@tonic-gate } 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate /* 304210db224Sericheng * dld control node open procedure. 3057c478bd9Sstevel@tonic-gate */ 3067c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3077c478bd9Sstevel@tonic-gate static int 308eae72b5bSSebastien Roy drv_open(dev_t *devp, int flag, int sflag, cred_t *credp) 3097c478bd9Sstevel@tonic-gate { 3107c478bd9Sstevel@tonic-gate /* 311eae72b5bSSebastien Roy * Only the control node can be opened. 3127c478bd9Sstevel@tonic-gate */ 313eae72b5bSSebastien Roy if (getminor(*devp) != DLD_CONTROL_MINOR) 314eae72b5bSSebastien Roy return (ENODEV); 3157c478bd9Sstevel@tonic-gate return (0); 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate /* 3192b24ab6bSSebastien Roy * Verify if the caller is allowed to modify a link of the given class. 3202b24ab6bSSebastien Roy */ 3212b24ab6bSSebastien Roy static int 3222b24ab6bSSebastien Roy drv_ioc_checkprivs(datalink_class_t class, cred_t *cred) 3232b24ab6bSSebastien Roy { 3242b24ab6bSSebastien Roy if (class == DATALINK_CLASS_IPTUN) 3252b24ab6bSSebastien Roy return (secpolicy_iptun_config(cred)); 3262b24ab6bSSebastien Roy return (secpolicy_dl_config(cred)); 3272b24ab6bSSebastien Roy } 3282b24ab6bSSebastien Roy 3292b24ab6bSSebastien Roy /* 330d62bc4baSyz147064 * DLDIOC_ATTR 3317c478bd9Sstevel@tonic-gate */ 332eae72b5bSSebastien Roy /* ARGSUSED */ 333eae72b5bSSebastien Roy static int 334da14cebeSEric Cheng drv_ioc_attr(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 3357c478bd9Sstevel@tonic-gate { 336eae72b5bSSebastien Roy dld_ioc_attr_t *diap = karg; 337d62bc4baSyz147064 dls_dl_handle_t dlh; 338da14cebeSEric Cheng dls_link_t *dlp; 3392b24ab6bSSebastien Roy zoneid_t zoneid = crgetzoneid(cred); 340210db224Sericheng int err; 341da14cebeSEric Cheng mac_perim_handle_t mph; 342210db224Sericheng 3432b24ab6bSSebastien Roy if (zoneid != GLOBAL_ZONEID && 3442b24ab6bSSebastien Roy zone_check_datalink(&zoneid, diap->dia_linkid) != 0) 3452b24ab6bSSebastien Roy return (ENOENT); 3462b24ab6bSSebastien Roy 347d62bc4baSyz147064 if ((err = dls_devnet_hold_tmp(diap->dia_linkid, &dlh)) != 0) 348eae72b5bSSebastien Roy return (err); 349d62bc4baSyz147064 350da14cebeSEric Cheng if ((err = mac_perim_enter_by_macname( 351da14cebeSEric Cheng dls_devnet_mac(dlh), &mph)) != 0) { 352d62bc4baSyz147064 dls_devnet_rele_tmp(dlh); 353eae72b5bSSebastien Roy return (err); 354210db224Sericheng } 355210db224Sericheng 356da14cebeSEric Cheng if ((err = dls_link_hold(dls_devnet_mac(dlh), &dlp)) != 0) { 357da14cebeSEric Cheng mac_perim_exit(mph); 358da14cebeSEric Cheng dls_devnet_rele_tmp(dlh); 359da14cebeSEric Cheng return (err); 360da14cebeSEric Cheng } 361da14cebeSEric Cheng 362da14cebeSEric Cheng mac_sdu_get(dlp->dl_mh, NULL, &diap->dia_max_sdu); 363da14cebeSEric Cheng 364da14cebeSEric Cheng dls_link_rele(dlp); 365da14cebeSEric Cheng mac_perim_exit(mph); 366d62bc4baSyz147064 dls_devnet_rele_tmp(dlh); 367d62bc4baSyz147064 368eae72b5bSSebastien Roy return (0); 369210db224Sericheng } 370210db224Sericheng 371f4b3ec61Sdh155122 /* 372d62bc4baSyz147064 * DLDIOC_PHYS_ATTR 373f4b3ec61Sdh155122 */ 374eae72b5bSSebastien Roy /* ARGSUSED */ 375eae72b5bSSebastien Roy static int 376da14cebeSEric Cheng drv_ioc_phys_attr(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 377f4b3ec61Sdh155122 { 378eae72b5bSSebastien Roy dld_ioc_phys_attr_t *dipp = karg; 379d62bc4baSyz147064 int err; 380d62bc4baSyz147064 dls_dl_handle_t dlh; 381d62bc4baSyz147064 dls_dev_handle_t ddh; 382d62bc4baSyz147064 dev_t phydev; 3832b24ab6bSSebastien Roy zoneid_t zoneid = crgetzoneid(cred); 3842b24ab6bSSebastien Roy 3852b24ab6bSSebastien Roy if (zoneid != GLOBAL_ZONEID && 3862b24ab6bSSebastien Roy zone_check_datalink(&zoneid, dipp->dip_linkid) != 0) 3872b24ab6bSSebastien Roy return (ENOENT); 388f4b3ec61Sdh155122 389789e0dbbSdh155122 /* 390d62bc4baSyz147064 * Every physical link should have its physical dev_t kept in the 391d62bc4baSyz147064 * daemon. If not, it is not a valid physical link. 392789e0dbbSdh155122 */ 393eae72b5bSSebastien Roy if (dls_mgmt_get_phydev(dipp->dip_linkid, &phydev) != 0) 394eae72b5bSSebastien Roy return (EINVAL); 395f4b3ec61Sdh155122 396d62bc4baSyz147064 /* 397d62bc4baSyz147064 * Although this is a valid physical link, it might already be removed 398d62bc4baSyz147064 * by DR or during system shutdown. softmac_hold_device() would return 399d62bc4baSyz147064 * ENOENT in this case. 400d62bc4baSyz147064 */ 401d62bc4baSyz147064 if ((err = softmac_hold_device(phydev, &ddh)) != 0) 402eae72b5bSSebastien Roy return (err); 403789e0dbbSdh155122 404d62bc4baSyz147064 if (dls_devnet_hold_tmp(dipp->dip_linkid, &dlh) != 0) { 405d62bc4baSyz147064 /* 406d62bc4baSyz147064 * Although this is an active physical link, its link type is 407d62bc4baSyz147064 * not supported by GLDv3, and therefore it does not have 408d62bc4baSyz147064 * vanity naming support. 409d62bc4baSyz147064 */ 410d62bc4baSyz147064 dipp->dip_novanity = B_TRUE; 411f595a68aSyz147064 } else { 412d62bc4baSyz147064 dipp->dip_novanity = B_FALSE; 413d62bc4baSyz147064 dls_devnet_rele_tmp(dlh); 414f4b3ec61Sdh155122 } 415d62bc4baSyz147064 /* 416d62bc4baSyz147064 * Get the physical device name from the major number and the instance 417d62bc4baSyz147064 * number derived from phydev. 418d62bc4baSyz147064 */ 419d62bc4baSyz147064 (void) snprintf(dipp->dip_dev, MAXLINKNAMELEN, "%s%d", 420d62bc4baSyz147064 ddi_major_to_name(getmajor(phydev)), getminor(phydev) - 1); 421d62bc4baSyz147064 422d62bc4baSyz147064 softmac_rele_device(ddh); 423eae72b5bSSebastien Roy return (0); 424f595a68aSyz147064 } 425f4b3ec61Sdh155122 426da14cebeSEric Cheng /* ARGSUSED */ 427da14cebeSEric Cheng static int 428da14cebeSEric Cheng drv_ioc_hwgrpget(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 429da14cebeSEric Cheng { 430da14cebeSEric Cheng dld_ioc_hwgrpget_t *hwgrpp = karg; 431da14cebeSEric Cheng dld_hwgrpinfo_t hwgrp, *hip; 432da14cebeSEric Cheng mac_handle_t mh = NULL; 4330dc2366fSVenugopal Iyer int i, err, rgrpnum, tgrpnum; 434da14cebeSEric Cheng uint_t bytes_left; 4350dc2366fSVenugopal Iyer int totgrps = 0; 4362b24ab6bSSebastien Roy zoneid_t zoneid = crgetzoneid(cred); 4372b24ab6bSSebastien Roy 4382b24ab6bSSebastien Roy if (zoneid != GLOBAL_ZONEID && 4392b24ab6bSSebastien Roy zone_check_datalink(&zoneid, hwgrpp->dih_linkid) != 0) 4402b24ab6bSSebastien Roy return (ENOENT); 441da14cebeSEric Cheng 442da14cebeSEric Cheng hwgrpp->dih_n_groups = 0; 443da14cebeSEric Cheng err = mac_open_by_linkid(hwgrpp->dih_linkid, &mh); 444da14cebeSEric Cheng if (err != 0) 445da14cebeSEric Cheng goto done; 446da14cebeSEric Cheng 447da14cebeSEric Cheng hip = (dld_hwgrpinfo_t *) 448da14cebeSEric Cheng ((uchar_t *)arg + sizeof (dld_ioc_hwgrpget_t)); 449da14cebeSEric Cheng bytes_left = hwgrpp->dih_size; 4500dc2366fSVenugopal Iyer 4510dc2366fSVenugopal Iyer rgrpnum = mac_hwgrp_num(mh, MAC_RING_TYPE_RX); 4520dc2366fSVenugopal Iyer /* display the default group information first */ 4530dc2366fSVenugopal Iyer if (rgrpnum > 0) { 454da14cebeSEric Cheng if (sizeof (dld_hwgrpinfo_t) > bytes_left) { 455da14cebeSEric Cheng err = ENOSPC; 456da14cebeSEric Cheng goto done; 457da14cebeSEric Cheng } 458da14cebeSEric Cheng 459da14cebeSEric Cheng bzero(&hwgrp, sizeof (hwgrp)); 460da14cebeSEric Cheng bcopy(mac_name(mh), hwgrp.dhi_link_name, 461da14cebeSEric Cheng sizeof (hwgrp.dhi_link_name)); 4620dc2366fSVenugopal Iyer mac_get_hwrxgrp_info(mh, 0, &hwgrp.dhi_grp_num, 4630dc2366fSVenugopal Iyer &hwgrp.dhi_n_rings, hwgrp.dhi_rings, &hwgrp.dhi_grp_type, 464da14cebeSEric Cheng &hwgrp.dhi_n_clnts, hwgrp.dhi_clnts); 4650dc2366fSVenugopal Iyer if (hwgrp.dhi_n_rings != 0) { 4660dc2366fSVenugopal Iyer if (copyout(&hwgrp, hip, sizeof (hwgrp)) != 0) { 4670dc2366fSVenugopal Iyer err = EFAULT; 4680dc2366fSVenugopal Iyer goto done; 4690dc2366fSVenugopal Iyer } 4700dc2366fSVenugopal Iyer } 4710dc2366fSVenugopal Iyer hip++; 4720dc2366fSVenugopal Iyer totgrps++; 4730dc2366fSVenugopal Iyer bytes_left -= sizeof (dld_hwgrpinfo_t); 4740dc2366fSVenugopal Iyer } 4750dc2366fSVenugopal Iyer 4760dc2366fSVenugopal Iyer tgrpnum = mac_hwgrp_num(mh, MAC_RING_TYPE_TX); 4770dc2366fSVenugopal Iyer /* display the default group information first */ 4780dc2366fSVenugopal Iyer if (tgrpnum > 0) { 4790dc2366fSVenugopal Iyer if (sizeof (dld_hwgrpinfo_t) > bytes_left) { 4800dc2366fSVenugopal Iyer err = ENOSPC; 4810dc2366fSVenugopal Iyer goto done; 4820dc2366fSVenugopal Iyer } 4830dc2366fSVenugopal Iyer 4840dc2366fSVenugopal Iyer bzero(&hwgrp, sizeof (hwgrp)); 4850dc2366fSVenugopal Iyer bcopy(mac_name(mh), hwgrp.dhi_link_name, 4860dc2366fSVenugopal Iyer sizeof (hwgrp.dhi_link_name)); 4870dc2366fSVenugopal Iyer mac_get_hwtxgrp_info(mh, tgrpnum - 1, &hwgrp.dhi_grp_num, 4880dc2366fSVenugopal Iyer &hwgrp.dhi_n_rings, hwgrp.dhi_rings, &hwgrp.dhi_grp_type, 4890dc2366fSVenugopal Iyer &hwgrp.dhi_n_clnts, hwgrp.dhi_clnts); 4900dc2366fSVenugopal Iyer if (hwgrp.dhi_n_rings != 0) { 4910dc2366fSVenugopal Iyer if (copyout(&hwgrp, hip, sizeof (hwgrp)) != 0) { 4920dc2366fSVenugopal Iyer err = EFAULT; 4930dc2366fSVenugopal Iyer goto done; 4940dc2366fSVenugopal Iyer } 4950dc2366fSVenugopal Iyer } 4960dc2366fSVenugopal Iyer hip++; 4970dc2366fSVenugopal Iyer totgrps++; 4980dc2366fSVenugopal Iyer bytes_left -= sizeof (dld_hwgrpinfo_t); 4990dc2366fSVenugopal Iyer } 5000dc2366fSVenugopal Iyer 5010dc2366fSVenugopal Iyer /* Rest of the rx groups */ 5020dc2366fSVenugopal Iyer for (i = 1; i < rgrpnum; i++) { 5030dc2366fSVenugopal Iyer if (sizeof (dld_hwgrpinfo_t) > bytes_left) { 5040dc2366fSVenugopal Iyer err = ENOSPC; 5050dc2366fSVenugopal Iyer goto done; 5060dc2366fSVenugopal Iyer } 5070dc2366fSVenugopal Iyer 5080dc2366fSVenugopal Iyer bzero(&hwgrp, sizeof (hwgrp)); 5090dc2366fSVenugopal Iyer bcopy(mac_name(mh), hwgrp.dhi_link_name, 5100dc2366fSVenugopal Iyer sizeof (hwgrp.dhi_link_name)); 5110dc2366fSVenugopal Iyer mac_get_hwrxgrp_info(mh, i, &hwgrp.dhi_grp_num, 5120dc2366fSVenugopal Iyer &hwgrp.dhi_n_rings, hwgrp.dhi_rings, &hwgrp.dhi_grp_type, 5130dc2366fSVenugopal Iyer &hwgrp.dhi_n_clnts, hwgrp.dhi_clnts); 5140dc2366fSVenugopal Iyer if (hwgrp.dhi_n_rings == 0) 5150dc2366fSVenugopal Iyer continue; 516da14cebeSEric Cheng if (copyout(&hwgrp, hip, sizeof (hwgrp)) != 0) { 517da14cebeSEric Cheng err = EFAULT; 518da14cebeSEric Cheng goto done; 519da14cebeSEric Cheng } 520da14cebeSEric Cheng 521da14cebeSEric Cheng hip++; 5220dc2366fSVenugopal Iyer totgrps++; 5230dc2366fSVenugopal Iyer bytes_left -= sizeof (dld_hwgrpinfo_t); 5240dc2366fSVenugopal Iyer } 5250dc2366fSVenugopal Iyer 5260dc2366fSVenugopal Iyer /* Rest of the tx group */ 5270dc2366fSVenugopal Iyer tgrpnum = mac_hwgrp_num(mh, MAC_RING_TYPE_TX); 5280dc2366fSVenugopal Iyer for (i = 0; i < tgrpnum - 1; i++) { 5290dc2366fSVenugopal Iyer if (sizeof (dld_hwgrpinfo_t) > bytes_left) { 5300dc2366fSVenugopal Iyer err = ENOSPC; 5310dc2366fSVenugopal Iyer goto done; 5320dc2366fSVenugopal Iyer } 5330dc2366fSVenugopal Iyer 5340dc2366fSVenugopal Iyer bzero(&hwgrp, sizeof (hwgrp)); 5350dc2366fSVenugopal Iyer bcopy(mac_name(mh), hwgrp.dhi_link_name, 5360dc2366fSVenugopal Iyer sizeof (hwgrp.dhi_link_name)); 5370dc2366fSVenugopal Iyer mac_get_hwtxgrp_info(mh, i, &hwgrp.dhi_grp_num, 5380dc2366fSVenugopal Iyer &hwgrp.dhi_n_rings, hwgrp.dhi_rings, &hwgrp.dhi_grp_type, 5390dc2366fSVenugopal Iyer &hwgrp.dhi_n_clnts, hwgrp.dhi_clnts); 5400dc2366fSVenugopal Iyer if (hwgrp.dhi_n_rings == 0) 5410dc2366fSVenugopal Iyer continue; 5420dc2366fSVenugopal Iyer if (copyout(&hwgrp, hip, sizeof (hwgrp)) != 0) { 5430dc2366fSVenugopal Iyer err = EFAULT; 5440dc2366fSVenugopal Iyer goto done; 5450dc2366fSVenugopal Iyer } 5460dc2366fSVenugopal Iyer 5470dc2366fSVenugopal Iyer hip++; 5480dc2366fSVenugopal Iyer totgrps++; 549da14cebeSEric Cheng bytes_left -= sizeof (dld_hwgrpinfo_t); 550da14cebeSEric Cheng } 551da14cebeSEric Cheng 552da14cebeSEric Cheng done: 553da14cebeSEric Cheng if (mh != NULL) 554da14cebeSEric Cheng dld_mac_close(mh); 555da14cebeSEric Cheng if (err == 0) 5560dc2366fSVenugopal Iyer hwgrpp->dih_n_groups = totgrps; 557da14cebeSEric Cheng return (err); 558da14cebeSEric Cheng } 559da14cebeSEric Cheng 560da14cebeSEric Cheng /* ARGSUSED */ 561da14cebeSEric Cheng static int 562da14cebeSEric Cheng drv_ioc_macaddrget(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 563da14cebeSEric Cheng { 564da14cebeSEric Cheng dld_ioc_macaddrget_t *magp = karg; 565da14cebeSEric Cheng dld_macaddrinfo_t mai, *maip; 566da14cebeSEric Cheng mac_handle_t mh = NULL; 567da14cebeSEric Cheng int i, err; 568da14cebeSEric Cheng uint_t bytes_left; 569da14cebeSEric Cheng boolean_t is_used; 5702b24ab6bSSebastien Roy zoneid_t zoneid = crgetzoneid(cred); 5712b24ab6bSSebastien Roy 5722b24ab6bSSebastien Roy if (zoneid != GLOBAL_ZONEID && 5732b24ab6bSSebastien Roy zone_check_datalink(&zoneid, magp->dig_linkid) != 0) 5742b24ab6bSSebastien Roy return (ENOENT); 575da14cebeSEric Cheng 576da14cebeSEric Cheng magp->dig_count = 0; 577da14cebeSEric Cheng err = mac_open_by_linkid(magp->dig_linkid, &mh); 578da14cebeSEric Cheng if (err != 0) 579da14cebeSEric Cheng goto done; 580da14cebeSEric Cheng 581da14cebeSEric Cheng maip = (dld_macaddrinfo_t *) 582da14cebeSEric Cheng ((uchar_t *)arg + sizeof (dld_ioc_macaddrget_t)); 583da14cebeSEric Cheng bytes_left = magp->dig_size; 584da14cebeSEric Cheng 585da14cebeSEric Cheng for (i = 0; i < mac_addr_factory_num(mh) + 1; i++) { 586da14cebeSEric Cheng if (sizeof (dld_macaddrinfo_t) > bytes_left) { 587da14cebeSEric Cheng err = ENOSPC; 588da14cebeSEric Cheng goto done; 589da14cebeSEric Cheng } 590da14cebeSEric Cheng 591da14cebeSEric Cheng bzero(&mai, sizeof (mai)); 592da14cebeSEric Cheng 593da14cebeSEric Cheng if (i == 0) { 594da14cebeSEric Cheng /* primary MAC address */ 595da14cebeSEric Cheng mac_unicast_primary_get(mh, mai.dmi_addr); 596da14cebeSEric Cheng mai.dmi_addrlen = mac_addr_len(mh); 597da14cebeSEric Cheng mac_unicast_primary_info(mh, mai.dmi_client_name, 598da14cebeSEric Cheng &is_used); 599da14cebeSEric Cheng } else { 600da14cebeSEric Cheng /* factory MAC address slot */ 601da14cebeSEric Cheng mac_addr_factory_value(mh, i, mai.dmi_addr, 602da14cebeSEric Cheng &mai.dmi_addrlen, mai.dmi_client_name, &is_used); 603da14cebeSEric Cheng } 604da14cebeSEric Cheng 605da14cebeSEric Cheng mai.dmi_slot = i; 606da14cebeSEric Cheng if (is_used) 607da14cebeSEric Cheng mai.dmi_flags |= DLDIOCMACADDR_USED; 608da14cebeSEric Cheng 609da14cebeSEric Cheng if (copyout(&mai, maip, sizeof (mai)) != 0) { 610da14cebeSEric Cheng err = EFAULT; 611da14cebeSEric Cheng goto done; 612da14cebeSEric Cheng } 613da14cebeSEric Cheng 614da14cebeSEric Cheng maip++; 615da14cebeSEric Cheng bytes_left -= sizeof (dld_macaddrinfo_t); 616da14cebeSEric Cheng } 617da14cebeSEric Cheng 618da14cebeSEric Cheng done: 619da14cebeSEric Cheng if (mh != NULL) 620da14cebeSEric Cheng dld_mac_close(mh); 621da14cebeSEric Cheng if (err == 0) 622da14cebeSEric Cheng magp->dig_count = mac_addr_factory_num(mh) + 1; 623da14cebeSEric Cheng return (err); 624da14cebeSEric Cheng } 625da14cebeSEric Cheng 626f4b3ec61Sdh155122 /* 6270dc2366fSVenugopal Iyer * DLDIOC_SET/GETMACPROP 628e7801d59Ssowmini */ 629eae72b5bSSebastien Roy static int 630da14cebeSEric Cheng drv_ioc_prop_common(dld_ioc_macprop_t *prop, intptr_t arg, boolean_t set, 6312b24ab6bSSebastien Roy cred_t *cred, int mode) 632e7801d59Ssowmini { 633eae72b5bSSebastien Roy int err = EINVAL; 634da14cebeSEric Cheng dls_dl_handle_t dlh = NULL; 635da14cebeSEric Cheng dls_link_t *dlp = NULL; 636da14cebeSEric Cheng mac_perim_handle_t mph = NULL; 637da14cebeSEric Cheng dld_ioc_macprop_t *kprop; 638da14cebeSEric Cheng datalink_id_t linkid; 6392b24ab6bSSebastien Roy datalink_class_t class; 6402b24ab6bSSebastien Roy zoneid_t zoneid = crgetzoneid(cred); 641da14cebeSEric Cheng uint_t dsize; 642da14cebeSEric Cheng 643eae72b5bSSebastien Roy /* 644da14cebeSEric Cheng * We only use pr_valsize from prop, as the caller only did a 645eae72b5bSSebastien Roy * copyin() for sizeof (dld_ioc_prop_t), which doesn't cover 646eae72b5bSSebastien Roy * the property data. We copyin the full dld_ioc_prop_t 647da14cebeSEric Cheng * including the data into kprop down below. 648eae72b5bSSebastien Roy */ 649da14cebeSEric Cheng dsize = sizeof (dld_ioc_macprop_t) + prop->pr_valsize - 1; 650da14cebeSEric Cheng if (dsize < prop->pr_valsize) 651eae72b5bSSebastien Roy return (EINVAL); 652e7801d59Ssowmini 653eae72b5bSSebastien Roy /* 654eae72b5bSSebastien Roy * The property data is variable size, so we need to allocate 655eae72b5bSSebastien Roy * a buffer for kernel use as this data was not part of the 656da14cebeSEric Cheng * prop allocation and copyin() done by the framework. 657eae72b5bSSebastien Roy */ 658da14cebeSEric Cheng if ((kprop = kmem_alloc(dsize, KM_NOSLEEP)) == NULL) 659eae72b5bSSebastien Roy return (ENOMEM); 660da14cebeSEric Cheng 661da14cebeSEric Cheng if (ddi_copyin((void *)arg, kprop, dsize, mode) != 0) { 662eae72b5bSSebastien Roy err = EFAULT; 663eae72b5bSSebastien Roy goto done; 664eae72b5bSSebastien Roy } 665eae72b5bSSebastien Roy 666da14cebeSEric Cheng linkid = kprop->pr_linkid; 667e7801d59Ssowmini 6682b24ab6bSSebastien Roy if (set) { 6692b24ab6bSSebastien Roy if ((err = dls_mgmt_get_linkinfo(linkid, NULL, &class, NULL, 6702b24ab6bSSebastien Roy NULL)) != 0 || (err = drv_ioc_checkprivs(class, cred)) != 0) 671da14cebeSEric Cheng goto done; 672da14cebeSEric Cheng } 673da14cebeSEric Cheng 6742b24ab6bSSebastien Roy if ((err = dls_devnet_hold_tmp(linkid, &dlh)) != 0) 6752b24ab6bSSebastien Roy goto done; 6762b24ab6bSSebastien Roy if ((err = mac_perim_enter_by_macname(dls_devnet_mac(dlh), &mph)) != 0) 6772b24ab6bSSebastien Roy goto done; 678e75f0919SSebastien Roy if ((err = dls_link_hold(dls_devnet_mac(dlh), &dlp)) != 0) 679e75f0919SSebastien Roy goto done; 680e75f0919SSebastien Roy 6812b24ab6bSSebastien Roy /* 6822b24ab6bSSebastien Roy * Don't allow a process to get or set properties of a link if that 6832b24ab6bSSebastien Roy * link doesn't belong to that zone. 6842b24ab6bSSebastien Roy */ 6852b24ab6bSSebastien Roy if (zoneid != dls_devnet_getownerzid(dlh)) { 6862b24ab6bSSebastien Roy err = ENOENT; 6872b24ab6bSSebastien Roy goto done; 6882b24ab6bSSebastien Roy } 6892b24ab6bSSebastien Roy 6900dc2366fSVenugopal Iyer if (!mac_prop_check_size(kprop->pr_num, kprop->pr_valsize, 6910dc2366fSVenugopal Iyer kprop->pr_flags & DLD_PROP_POSSIBLE)) { 6920dc2366fSVenugopal Iyer err = ENOBUFS; 6930dc2366fSVenugopal Iyer goto done; 6940dc2366fSVenugopal Iyer } 6950dc2366fSVenugopal Iyer 696da14cebeSEric Cheng switch (kprop->pr_num) { 697e75f0919SSebastien Roy case MAC_PROP_ZONE: 6983bc21d0aSAruna Ramakrishna - Sun Microsystems if (set) { 699da14cebeSEric Cheng dld_ioc_zid_t *dzp = (dld_ioc_zid_t *)kprop->pr_val; 700da14cebeSEric Cheng 7012b24ab6bSSebastien Roy if (zoneid != GLOBAL_ZONEID) { 7022b24ab6bSSebastien Roy err = EACCES; 7032b24ab6bSSebastien Roy goto done; 7042b24ab6bSSebastien Roy } 7052b24ab6bSSebastien Roy err = dls_devnet_setzid(dlh, dzp->diz_zid); 7063bc21d0aSAruna Ramakrishna - Sun Microsystems } else { 707da14cebeSEric Cheng kprop->pr_perm_flags = MAC_PROP_PERM_RW; 7082b24ab6bSSebastien Roy (*(zoneid_t *)kprop->pr_val) = dls_devnet_getzid(dlh); 7093bc21d0aSAruna Ramakrishna - Sun Microsystems } 710e75f0919SSebastien Roy break; 711da14cebeSEric Cheng case MAC_PROP_AUTOPUSH: { 712e75f0919SSebastien Roy struct dlautopush *dlap = (struct dlautopush *)kprop->pr_val; 713da14cebeSEric Cheng 7143bc21d0aSAruna Ramakrishna - Sun Microsystems if (set) { 715e75f0919SSebastien Roy if (kprop->pr_valsize != 0) 7163bc21d0aSAruna Ramakrishna - Sun Microsystems err = drv_ioc_setap(linkid, dlap); 717e75f0919SSebastien Roy else 7183bc21d0aSAruna Ramakrishna - Sun Microsystems err = drv_ioc_clrap(linkid); 7193bc21d0aSAruna Ramakrishna - Sun Microsystems } else { 7200dc2366fSVenugopal Iyer if (kprop->pr_valsize == 0) 7210dc2366fSVenugopal Iyer return (ENOBUFS); 7220dc2366fSVenugopal Iyer 723da14cebeSEric Cheng kprop->pr_perm_flags = MAC_PROP_PERM_RW; 7243bc21d0aSAruna Ramakrishna - Sun Microsystems err = drv_ioc_getap(linkid, dlap); 7253bc21d0aSAruna Ramakrishna - Sun Microsystems } 7263bc21d0aSAruna Ramakrishna - Sun Microsystems break; 7273bc21d0aSAruna Ramakrishna - Sun Microsystems } 728e75f0919SSebastien Roy case MAC_PROP_TAGMODE: 729e75f0919SSebastien Roy if (set) { 730e75f0919SSebastien Roy link_tagmode_t mode = *(link_tagmode_t *)kprop->pr_val; 7313bc21d0aSAruna Ramakrishna - Sun Microsystems 732e75f0919SSebastien Roy if (mode != LINK_TAGMODE_VLANONLY && 733e75f0919SSebastien Roy mode != LINK_TAGMODE_NORMAL) { 734e75f0919SSebastien Roy err = EINVAL; 735e75f0919SSebastien Roy } else { 736e75f0919SSebastien Roy dlp->dl_tagmode = mode; 737e75f0919SSebastien Roy err = 0; 738e75f0919SSebastien Roy } 739e75f0919SSebastien Roy } else { 740e75f0919SSebastien Roy *(link_tagmode_t *)kprop->pr_val = dlp->dl_tagmode; 741e75f0919SSebastien Roy kprop->pr_perm_flags = MAC_PROP_PERM_RW; 742e75f0919SSebastien Roy err = 0; 743e75f0919SSebastien Roy } 744e75f0919SSebastien Roy break; 7450dc2366fSVenugopal Iyer default: { 7460591ddd0SPrakash Jalan mac_propval_range_t *rangep = NULL; 7470dc2366fSVenugopal Iyer void *default_val = NULL; 7480dc2366fSVenugopal Iyer uint_t default_size = 0; 749e7801d59Ssowmini 7500dc2366fSVenugopal Iyer /* set a property value */ 751eae72b5bSSebastien Roy if (set) { 7520dc2366fSVenugopal Iyer err = mac_set_prop(dlp->dl_mh, kprop->pr_num, 7530dc2366fSVenugopal Iyer kprop->pr_name, kprop->pr_val, kprop->pr_valsize); 7540dc2366fSVenugopal Iyer break; 7550dc2366fSVenugopal Iyer } 7560dc2366fSVenugopal Iyer 7570dc2366fSVenugopal Iyer /* 7580dc2366fSVenugopal Iyer * Get the property value, default, or possible value 7590dc2366fSVenugopal Iyer * depending on flags passed from the user. 7600dc2366fSVenugopal Iyer */ 7610dc2366fSVenugopal Iyer 7620dc2366fSVenugopal Iyer /* a property has RW permissions by default */ 763da14cebeSEric Cheng kprop->pr_perm_flags = MAC_PROP_PERM_RW; 7640dc2366fSVenugopal Iyer 7650dc2366fSVenugopal Iyer if (kprop->pr_flags & DLD_PROP_POSSIBLE) { 7660591ddd0SPrakash Jalan rangep = (mac_propval_range_t *)kprop->pr_val; 7670591ddd0SPrakash Jalan 7680591ddd0SPrakash Jalan /* 7690591ddd0SPrakash Jalan * fail if rangep is not aligned to first 7700591ddd0SPrakash Jalan * member of mac_propval_range_t. 7710591ddd0SPrakash Jalan */ 7720591ddd0SPrakash Jalan ASSERT(IS_P2ALIGNED(rangep, sizeof (uint_t))); 7730dc2366fSVenugopal Iyer } else if (kprop->pr_flags & DLD_PROP_DEFAULT) { 7740591ddd0SPrakash Jalan default_val = kprop->pr_val; 7750591ddd0SPrakash Jalan default_size = kprop->pr_valsize; 7760dc2366fSVenugopal Iyer } 7770dc2366fSVenugopal Iyer 7780dc2366fSVenugopal Iyer /* 7790dc2366fSVenugopal Iyer * Always return the permissions, and optionally return 7800dc2366fSVenugopal Iyer * the default value or possible values range. 7810dc2366fSVenugopal Iyer */ 7820591ddd0SPrakash Jalan err = mac_prop_info(dlp->dl_mh, kprop->pr_num, kprop->pr_name, 7830dc2366fSVenugopal Iyer default_val, default_size, rangep, &kprop->pr_perm_flags); 7840591ddd0SPrakash Jalan if (err != 0) 7850591ddd0SPrakash Jalan goto done; 7860dc2366fSVenugopal Iyer 7870dc2366fSVenugopal Iyer if (default_val == NULL && rangep == NULL) { 7880dc2366fSVenugopal Iyer err = mac_get_prop(dlp->dl_mh, kprop->pr_num, 7890dc2366fSVenugopal Iyer kprop->pr_name, kprop->pr_val, kprop->pr_valsize); 7900dc2366fSVenugopal Iyer } 791eae72b5bSSebastien Roy } 792e75f0919SSebastien Roy } 793e7801d59Ssowmini 794e7801d59Ssowmini done: 795f0f2c3a5SGirish Moodalbail if (!set && ddi_copyout(kprop, (void *)arg, dsize, mode) != 0) 796eae72b5bSSebastien Roy err = EFAULT; 797da14cebeSEric Cheng 798da14cebeSEric Cheng if (dlp != NULL) 799da14cebeSEric Cheng dls_link_rele(dlp); 8000dc2366fSVenugopal Iyer 801da14cebeSEric Cheng if (mph != NULL) { 802da14cebeSEric Cheng int32_t cpuid; 803da14cebeSEric Cheng void *mdip = NULL; 804da14cebeSEric Cheng 805da14cebeSEric Cheng if (dlp != NULL && set && err == 0) { 806da14cebeSEric Cheng cpuid = mac_client_intr_cpu(dlp->dl_mch); 807da14cebeSEric Cheng mdip = mac_get_devinfo(dlp->dl_mh); 808da14cebeSEric Cheng } 809da14cebeSEric Cheng 810da14cebeSEric Cheng mac_perim_exit(mph); 811da14cebeSEric Cheng 8120dc2366fSVenugopal Iyer if (mdip != NULL && cpuid != -1) 813da14cebeSEric Cheng mac_client_set_intr_cpu(mdip, dlp->dl_mch, cpuid); 814da14cebeSEric Cheng } 8150dc2366fSVenugopal Iyer 816da14cebeSEric Cheng if (dlh != NULL) 817da14cebeSEric Cheng dls_devnet_rele_tmp(dlh); 818da14cebeSEric Cheng 819da14cebeSEric Cheng if (kprop != NULL) 820da14cebeSEric Cheng kmem_free(kprop, dsize); 821eae72b5bSSebastien Roy return (err); 822e7801d59Ssowmini } 823e7801d59Ssowmini 824eae72b5bSSebastien Roy /* ARGSUSED */ 825eae72b5bSSebastien Roy static int 826da14cebeSEric Cheng drv_ioc_setprop(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 827e7801d59Ssowmini { 8282b24ab6bSSebastien Roy return (drv_ioc_prop_common(karg, arg, B_TRUE, cred, mode)); 829e7801d59Ssowmini } 830e7801d59Ssowmini 831eae72b5bSSebastien Roy /* ARGSUSED */ 832eae72b5bSSebastien Roy static int 833da14cebeSEric Cheng drv_ioc_getprop(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 834e7801d59Ssowmini { 8352b24ab6bSSebastien Roy return (drv_ioc_prop_common(karg, arg, B_FALSE, cred, mode)); 836e7801d59Ssowmini } 837e7801d59Ssowmini 838e7801d59Ssowmini /* 839d62bc4baSyz147064 * DLDIOC_RENAME. 840d62bc4baSyz147064 * 841d62bc4baSyz147064 * This function handles two cases of link renaming. See more in comments above 842d62bc4baSyz147064 * dls_datalink_rename(). 843d62bc4baSyz147064 */ 844eae72b5bSSebastien Roy /* ARGSUSED */ 845eae72b5bSSebastien Roy static int 846da14cebeSEric Cheng drv_ioc_rename(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 847d62bc4baSyz147064 { 848eae72b5bSSebastien Roy dld_ioc_rename_t *dir = karg; 849d62bc4baSyz147064 mod_hash_key_t key; 850d62bc4baSyz147064 mod_hash_val_t val; 8512b24ab6bSSebastien Roy zoneid_t zoneid = crgetzoneid(cred); 8522b24ab6bSSebastien Roy datalink_class_t class; 853d62bc4baSyz147064 int err; 854d62bc4baSyz147064 8552b24ab6bSSebastien Roy if (zoneid != GLOBAL_ZONEID && 8562b24ab6bSSebastien Roy (zone_check_datalink(&zoneid, dir->dir_linkid1) != 0 || 8572b24ab6bSSebastien Roy dir->dir_linkid2 != DATALINK_INVALID_LINKID && 8582b24ab6bSSebastien Roy zone_check_datalink(&zoneid, dir->dir_linkid2) != 0)) 8592b24ab6bSSebastien Roy return (ENOENT); 8602b24ab6bSSebastien Roy 8612b24ab6bSSebastien Roy if ((err = dls_mgmt_get_linkinfo(dir->dir_linkid1, NULL, &class, NULL, 8622b24ab6bSSebastien Roy NULL)) != 0) 8632b24ab6bSSebastien Roy return (err); 8642b24ab6bSSebastien Roy 8652b24ab6bSSebastien Roy if ((err = drv_ioc_checkprivs(class, cred)) != 0) 8662b24ab6bSSebastien Roy return (err); 8672b24ab6bSSebastien Roy 868d62bc4baSyz147064 if ((err = dls_devnet_rename(dir->dir_linkid1, dir->dir_linkid2, 869eae72b5bSSebastien Roy dir->dir_link)) != 0) 870eae72b5bSSebastien Roy return (err); 871d62bc4baSyz147064 872d62bc4baSyz147064 if (dir->dir_linkid2 == DATALINK_INVALID_LINKID) 873eae72b5bSSebastien Roy return (0); 874d62bc4baSyz147064 875d62bc4baSyz147064 /* 876d62bc4baSyz147064 * if dir_linkid2 is not DATALINK_INVALID_LINKID, it means this 877d62bc4baSyz147064 * renaming request is to rename a valid physical link (dir_linkid1) 878d62bc4baSyz147064 * to a "removed" physical link (dir_linkid2, which is removed by DR 879d62bc4baSyz147064 * or during system shutdown). In this case, the link (specified by 880d62bc4baSyz147064 * dir_linkid1) would inherit all the configuration of dir_linkid2, 881d62bc4baSyz147064 * and dir_linkid1 and its configuration would be lost. 882d62bc4baSyz147064 * 883d62bc4baSyz147064 * Remove per-link autopush configuration of dir_linkid1 in this case. 884d62bc4baSyz147064 */ 885d62bc4baSyz147064 key = (mod_hash_key_t)(uintptr_t)dir->dir_linkid1; 886d62bc4baSyz147064 rw_enter(&dld_ap_hash_lock, RW_WRITER); 887d62bc4baSyz147064 if (mod_hash_find(dld_ap_hashp, key, &val) != 0) { 888d62bc4baSyz147064 rw_exit(&dld_ap_hash_lock); 889eae72b5bSSebastien Roy return (0); 890d62bc4baSyz147064 } 891d62bc4baSyz147064 892d62bc4baSyz147064 VERIFY(mod_hash_remove(dld_ap_hashp, key, &val) == 0); 893d62bc4baSyz147064 kmem_free(val, sizeof (dld_ap_t)); 894d62bc4baSyz147064 rw_exit(&dld_ap_hash_lock); 895eae72b5bSSebastien Roy return (0); 896d62bc4baSyz147064 } 897d62bc4baSyz147064 8983bc21d0aSAruna Ramakrishna - Sun Microsystems static int 8993bc21d0aSAruna Ramakrishna - Sun Microsystems drv_ioc_setap(datalink_id_t linkid, struct dlautopush *dlap) 900d62bc4baSyz147064 { 901d62bc4baSyz147064 dld_ap_t *dap; 902eae72b5bSSebastien Roy int i; 903d62bc4baSyz147064 mod_hash_key_t key; 904d62bc4baSyz147064 905eae72b5bSSebastien Roy if (dlap->dap_npush == 0 || dlap->dap_npush > MAXAPUSH) 906eae72b5bSSebastien Roy return (EINVAL); 907d62bc4baSyz147064 908d62bc4baSyz147064 /* 909d62bc4baSyz147064 * Validate that the specified list of modules exist. 910d62bc4baSyz147064 */ 9113bc21d0aSAruna Ramakrishna - Sun Microsystems for (i = 0; i < dlap->dap_npush; i++) { 912eae72b5bSSebastien Roy if (fmodsw_find(dlap->dap_aplist[i], FMODSW_LOAD) == NULL) 913eae72b5bSSebastien Roy return (EINVAL); 914d62bc4baSyz147064 } 915eae72b5bSSebastien Roy 916d62bc4baSyz147064 9173bc21d0aSAruna Ramakrishna - Sun Microsystems key = (mod_hash_key_t)(uintptr_t)linkid; 918d62bc4baSyz147064 919d62bc4baSyz147064 rw_enter(&dld_ap_hash_lock, RW_WRITER); 920d62bc4baSyz147064 if (mod_hash_find(dld_ap_hashp, key, (mod_hash_val_t *)&dap) != 0) { 921d62bc4baSyz147064 dap = kmem_zalloc(sizeof (dld_ap_t), KM_NOSLEEP); 922d62bc4baSyz147064 if (dap == NULL) { 923d62bc4baSyz147064 rw_exit(&dld_ap_hash_lock); 924eae72b5bSSebastien Roy return (ENOMEM); 925d62bc4baSyz147064 } 926d62bc4baSyz147064 9273bc21d0aSAruna Ramakrishna - Sun Microsystems dap->da_linkid = linkid; 928eae72b5bSSebastien Roy VERIFY(mod_hash_insert(dld_ap_hashp, key, 929eae72b5bSSebastien Roy (mod_hash_val_t)dap) == 0); 930d62bc4baSyz147064 } 931d62bc4baSyz147064 932d62bc4baSyz147064 /* 933d62bc4baSyz147064 * Update the configuration. 934d62bc4baSyz147064 */ 9353bc21d0aSAruna Ramakrishna - Sun Microsystems dap->da_anchor = dlap->dap_anchor; 9363bc21d0aSAruna Ramakrishna - Sun Microsystems dap->da_npush = dlap->dap_npush; 9373bc21d0aSAruna Ramakrishna - Sun Microsystems for (i = 0; i < dlap->dap_npush; i++) { 9383bc21d0aSAruna Ramakrishna - Sun Microsystems (void) strlcpy(dap->da_aplist[i], dlap->dap_aplist[i], 939d62bc4baSyz147064 FMNAMESZ + 1); 940d62bc4baSyz147064 } 941d62bc4baSyz147064 rw_exit(&dld_ap_hash_lock); 942d62bc4baSyz147064 9433bc21d0aSAruna Ramakrishna - Sun Microsystems return (0); 944d62bc4baSyz147064 } 945d62bc4baSyz147064 9463bc21d0aSAruna Ramakrishna - Sun Microsystems static int 9473bc21d0aSAruna Ramakrishna - Sun Microsystems drv_ioc_getap(datalink_id_t linkid, struct dlautopush *dlap) 948d62bc4baSyz147064 { 949d62bc4baSyz147064 dld_ap_t *dap; 950eae72b5bSSebastien Roy int i; 951d62bc4baSyz147064 952d62bc4baSyz147064 rw_enter(&dld_ap_hash_lock, RW_READER); 953d62bc4baSyz147064 if (mod_hash_find(dld_ap_hashp, 9543bc21d0aSAruna Ramakrishna - Sun Microsystems (mod_hash_key_t)(uintptr_t)linkid, 955d62bc4baSyz147064 (mod_hash_val_t *)&dap) != 0) { 956d62bc4baSyz147064 rw_exit(&dld_ap_hash_lock); 9570dc2366fSVenugopal Iyer dlap->dap_npush = 0; 9580dc2366fSVenugopal Iyer return (0); 959d62bc4baSyz147064 } 960d62bc4baSyz147064 961d62bc4baSyz147064 /* 962d62bc4baSyz147064 * Retrieve the configuration. 963d62bc4baSyz147064 */ 9643bc21d0aSAruna Ramakrishna - Sun Microsystems dlap->dap_anchor = dap->da_anchor; 9653bc21d0aSAruna Ramakrishna - Sun Microsystems dlap->dap_npush = dap->da_npush; 966d62bc4baSyz147064 for (i = 0; i < dap->da_npush; i++) { 9673bc21d0aSAruna Ramakrishna - Sun Microsystems (void) strlcpy(dlap->dap_aplist[i], dap->da_aplist[i], 968d62bc4baSyz147064 FMNAMESZ + 1); 969d62bc4baSyz147064 } 970d62bc4baSyz147064 rw_exit(&dld_ap_hash_lock); 971d62bc4baSyz147064 9723bc21d0aSAruna Ramakrishna - Sun Microsystems return (0); 973d62bc4baSyz147064 } 974d62bc4baSyz147064 9753bc21d0aSAruna Ramakrishna - Sun Microsystems static int 9763bc21d0aSAruna Ramakrishna - Sun Microsystems drv_ioc_clrap(datalink_id_t linkid) 977d62bc4baSyz147064 { 978d62bc4baSyz147064 mod_hash_val_t val; 979d62bc4baSyz147064 mod_hash_key_t key; 980d62bc4baSyz147064 9813bc21d0aSAruna Ramakrishna - Sun Microsystems key = (mod_hash_key_t)(uintptr_t)linkid; 982d62bc4baSyz147064 983d62bc4baSyz147064 rw_enter(&dld_ap_hash_lock, RW_WRITER); 984d62bc4baSyz147064 if (mod_hash_find(dld_ap_hashp, key, &val) != 0) { 985d62bc4baSyz147064 rw_exit(&dld_ap_hash_lock); 9863bc21d0aSAruna Ramakrishna - Sun Microsystems return (0); 987d62bc4baSyz147064 } 988d62bc4baSyz147064 989d62bc4baSyz147064 VERIFY(mod_hash_remove(dld_ap_hashp, key, &val) == 0); 990d62bc4baSyz147064 kmem_free(val, sizeof (dld_ap_t)); 991d62bc4baSyz147064 rw_exit(&dld_ap_hash_lock); 9923bc21d0aSAruna Ramakrishna - Sun Microsystems return (0); 993d62bc4baSyz147064 } 994d62bc4baSyz147064 995d62bc4baSyz147064 /* 996d62bc4baSyz147064 * DLDIOC_DOORSERVER 997d62bc4baSyz147064 */ 998eae72b5bSSebastien Roy /* ARGSUSED */ 999eae72b5bSSebastien Roy static int 1000da14cebeSEric Cheng drv_ioc_doorserver(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 1001f4b3ec61Sdh155122 { 1002eae72b5bSSebastien Roy dld_ioc_door_t *did = karg; 1003f4b3ec61Sdh155122 1004eae72b5bSSebastien Roy return (dls_mgmt_door_set(did->did_start_door)); 10057c478bd9Sstevel@tonic-gate } 10060ba2cbe9Sxc151355 10070ba2cbe9Sxc151355 /* 1008da14cebeSEric Cheng * DLDIOC_USAGELOG 1009da14cebeSEric Cheng */ 1010da14cebeSEric Cheng /* ARGSUSED */ 1011da14cebeSEric Cheng static int 1012da14cebeSEric Cheng drv_ioc_usagelog(void *karg, intptr_t arg, int mode, cred_t *cred, 1013da14cebeSEric Cheng int *rvalp) 1014da14cebeSEric Cheng { 1015da14cebeSEric Cheng dld_ioc_usagelog_t *log_info = (dld_ioc_usagelog_t *)karg; 10165d460eafSCathy Zhou int err = 0; 1017da14cebeSEric Cheng 1018da14cebeSEric Cheng if (log_info->ul_type < MAC_LOGTYPE_LINK || 1019da14cebeSEric Cheng log_info->ul_type > MAC_LOGTYPE_FLOW) 1020da14cebeSEric Cheng return (EINVAL); 1021da14cebeSEric Cheng 10225d460eafSCathy Zhou if (log_info->ul_onoff) { 10235d460eafSCathy Zhou err = mac_start_logusage(log_info->ul_type, 10245d460eafSCathy Zhou log_info->ul_interval); 10255d460eafSCathy Zhou } else { 1026da14cebeSEric Cheng mac_stop_logusage(log_info->ul_type); 10275d460eafSCathy Zhou } 10285d460eafSCathy Zhou return (err); 1029da14cebeSEric Cheng } 1030da14cebeSEric Cheng 1031da14cebeSEric Cheng /* 1032da14cebeSEric Cheng * Process a DLDIOC_ADDFLOW request. 1033da14cebeSEric Cheng */ 1034da14cebeSEric Cheng /* ARGSUSED */ 1035da14cebeSEric Cheng static int 1036da14cebeSEric Cheng drv_ioc_addflow(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 1037da14cebeSEric Cheng { 1038da14cebeSEric Cheng dld_ioc_addflow_t *afp = karg; 1039da14cebeSEric Cheng 1040da14cebeSEric Cheng return (dld_add_flow(afp->af_linkid, afp->af_name, 1041da14cebeSEric Cheng &afp->af_flow_desc, &afp->af_resource_props)); 1042da14cebeSEric Cheng } 1043da14cebeSEric Cheng 1044da14cebeSEric Cheng /* 1045da14cebeSEric Cheng * Process a DLDIOC_REMOVEFLOW request. 1046da14cebeSEric Cheng */ 1047da14cebeSEric Cheng /* ARGSUSED */ 1048da14cebeSEric Cheng static int 1049da14cebeSEric Cheng drv_ioc_removeflow(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 1050da14cebeSEric Cheng { 1051da14cebeSEric Cheng dld_ioc_removeflow_t *rfp = karg; 1052da14cebeSEric Cheng 1053da14cebeSEric Cheng return (dld_remove_flow(rfp->rf_name)); 1054da14cebeSEric Cheng } 1055da14cebeSEric Cheng 1056da14cebeSEric Cheng /* 1057da14cebeSEric Cheng * Process a DLDIOC_MODIFYFLOW request. 1058da14cebeSEric Cheng */ 1059da14cebeSEric Cheng /* ARGSUSED */ 1060da14cebeSEric Cheng static int 1061da14cebeSEric Cheng drv_ioc_modifyflow(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 1062da14cebeSEric Cheng { 1063da14cebeSEric Cheng dld_ioc_modifyflow_t *mfp = karg; 1064da14cebeSEric Cheng 1065da14cebeSEric Cheng return (dld_modify_flow(mfp->mf_name, &mfp->mf_resource_props)); 1066da14cebeSEric Cheng } 1067da14cebeSEric Cheng 1068da14cebeSEric Cheng /* 1069da14cebeSEric Cheng * Process a DLDIOC_WALKFLOW request. 1070da14cebeSEric Cheng */ 1071da14cebeSEric Cheng /* ARGSUSED */ 1072da14cebeSEric Cheng static int 1073da14cebeSEric Cheng drv_ioc_walkflow(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 1074da14cebeSEric Cheng { 1075da14cebeSEric Cheng dld_ioc_walkflow_t *wfp = karg; 1076da14cebeSEric Cheng 10772b24ab6bSSebastien Roy return (dld_walk_flow(wfp, arg, cred)); 1078da14cebeSEric Cheng } 1079da14cebeSEric Cheng 1080da14cebeSEric Cheng /* 1081d62bc4baSyz147064 * Check for GLDv3 autopush information. There are three cases: 1082d62bc4baSyz147064 * 1083d62bc4baSyz147064 * 1. If devp points to a GLDv3 datalink and it has autopush configuration, 1084d62bc4baSyz147064 * fill dlap in with that information and return 0. 1085d62bc4baSyz147064 * 1086d62bc4baSyz147064 * 2. If devp points to a GLDv3 datalink but it doesn't have autopush 1087d62bc4baSyz147064 * configuration, then replace devp with the physical device (if one 1088d62bc4baSyz147064 * exists) and return 1. This allows stropen() to find the old-school 1089d62bc4baSyz147064 * per-driver autopush configuration. (For softmac, the result is that 1090d62bc4baSyz147064 * the softmac dev_t is replaced with the legacy device's dev_t). 1091d62bc4baSyz147064 * 1092d62bc4baSyz147064 * 3. If neither of the above apply, don't touch the args and return -1. 1093d62bc4baSyz147064 */ 1094d62bc4baSyz147064 int 1095d62bc4baSyz147064 dld_autopush(dev_t *devp, struct dlautopush *dlap) 1096d62bc4baSyz147064 { 1097d62bc4baSyz147064 dld_ap_t *dap; 1098d62bc4baSyz147064 datalink_id_t linkid; 1099d62bc4baSyz147064 dev_t phydev; 1100d62bc4baSyz147064 1101d62bc4baSyz147064 if (!GLDV3_DRV(getmajor(*devp))) 1102d62bc4baSyz147064 return (-1); 1103d62bc4baSyz147064 1104d62bc4baSyz147064 /* 1105d62bc4baSyz147064 * Find the linkid by the link's dev_t. 1106d62bc4baSyz147064 */ 1107d62bc4baSyz147064 if (dls_devnet_dev2linkid(*devp, &linkid) != 0) 1108d62bc4baSyz147064 return (-1); 1109d62bc4baSyz147064 1110d62bc4baSyz147064 /* 1111d62bc4baSyz147064 * Find the autopush configuration associated with the linkid. 1112d62bc4baSyz147064 */ 1113d62bc4baSyz147064 rw_enter(&dld_ap_hash_lock, RW_READER); 1114d62bc4baSyz147064 if (mod_hash_find(dld_ap_hashp, (mod_hash_key_t)(uintptr_t)linkid, 1115d62bc4baSyz147064 (mod_hash_val_t *)&dap) == 0) { 1116d62bc4baSyz147064 *dlap = dap->da_ap; 1117d62bc4baSyz147064 rw_exit(&dld_ap_hash_lock); 1118d62bc4baSyz147064 return (0); 1119d62bc4baSyz147064 } 1120d62bc4baSyz147064 rw_exit(&dld_ap_hash_lock); 1121d62bc4baSyz147064 1122d62bc4baSyz147064 if (dls_devnet_phydev(linkid, &phydev) != 0) 1123d62bc4baSyz147064 return (-1); 1124d62bc4baSyz147064 1125d62bc4baSyz147064 *devp = phydev; 1126d62bc4baSyz147064 return (1); 1127d62bc4baSyz147064 } 1128d62bc4baSyz147064 1129d62bc4baSyz147064 /* 11300ba2cbe9Sxc151355 * Secure objects implementation 11310ba2cbe9Sxc151355 */ 11320ba2cbe9Sxc151355 11330ba2cbe9Sxc151355 /* ARGSUSED */ 11340ba2cbe9Sxc151355 static int 11350ba2cbe9Sxc151355 drv_secobj_ctor(void *buf, void *arg, int kmflag) 11360ba2cbe9Sxc151355 { 11370ba2cbe9Sxc151355 bzero(buf, sizeof (dld_secobj_t)); 11380ba2cbe9Sxc151355 return (0); 11390ba2cbe9Sxc151355 } 11400ba2cbe9Sxc151355 11410ba2cbe9Sxc151355 static void 11420ba2cbe9Sxc151355 drv_secobj_init(void) 11430ba2cbe9Sxc151355 { 11440ba2cbe9Sxc151355 rw_init(&drv_secobj_lock, NULL, RW_DEFAULT, NULL); 11450ba2cbe9Sxc151355 drv_secobj_cachep = kmem_cache_create("drv_secobj_cache", 11460ba2cbe9Sxc151355 sizeof (dld_secobj_t), 0, drv_secobj_ctor, NULL, 11470ba2cbe9Sxc151355 NULL, NULL, NULL, 0); 11480ba2cbe9Sxc151355 drv_secobj_hash = mod_hash_create_extended("drv_secobj_hash", 11490ba2cbe9Sxc151355 SECOBJ_WEP_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, 11500ba2cbe9Sxc151355 mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 11510ba2cbe9Sxc151355 } 11520ba2cbe9Sxc151355 11530ba2cbe9Sxc151355 static void 11540ba2cbe9Sxc151355 drv_secobj_fini(void) 11550ba2cbe9Sxc151355 { 11560ba2cbe9Sxc151355 mod_hash_destroy_hash(drv_secobj_hash); 11570ba2cbe9Sxc151355 kmem_cache_destroy(drv_secobj_cachep); 11580ba2cbe9Sxc151355 rw_destroy(&drv_secobj_lock); 11590ba2cbe9Sxc151355 } 11600ba2cbe9Sxc151355 1161eae72b5bSSebastien Roy /* ARGSUSED */ 1162eae72b5bSSebastien Roy static int 1163da14cebeSEric Cheng drv_ioc_secobj_set(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 11640ba2cbe9Sxc151355 { 1165eae72b5bSSebastien Roy dld_ioc_secobj_set_t *ssp = karg; 11660ba2cbe9Sxc151355 dld_secobj_t *sobjp, *objp; 1167eae72b5bSSebastien Roy int err; 11680ba2cbe9Sxc151355 11690ba2cbe9Sxc151355 sobjp = &ssp->ss_obj; 11700ba2cbe9Sxc151355 1171a399b765Szf162725 if (sobjp->so_class != DLD_SECOBJ_CLASS_WEP && 1172a399b765Szf162725 sobjp->so_class != DLD_SECOBJ_CLASS_WPA) 1173eae72b5bSSebastien Roy return (EINVAL); 11740ba2cbe9Sxc151355 11750ba2cbe9Sxc151355 if (sobjp->so_name[DLD_SECOBJ_NAME_MAX - 1] != '\0' || 11760ba2cbe9Sxc151355 sobjp->so_len > DLD_SECOBJ_VAL_MAX) 1177eae72b5bSSebastien Roy return (EINVAL); 11780ba2cbe9Sxc151355 11790ba2cbe9Sxc151355 rw_enter(&drv_secobj_lock, RW_WRITER); 11800ba2cbe9Sxc151355 err = mod_hash_find(drv_secobj_hash, (mod_hash_key_t)sobjp->so_name, 11810ba2cbe9Sxc151355 (mod_hash_val_t *)&objp); 11820ba2cbe9Sxc151355 if (err == 0) { 11830ba2cbe9Sxc151355 if ((ssp->ss_flags & DLD_SECOBJ_OPT_CREATE) != 0) { 11840ba2cbe9Sxc151355 rw_exit(&drv_secobj_lock); 1185eae72b5bSSebastien Roy return (EEXIST); 11860ba2cbe9Sxc151355 } 11870ba2cbe9Sxc151355 } else { 11880ba2cbe9Sxc151355 ASSERT(err == MH_ERR_NOTFOUND); 11890ba2cbe9Sxc151355 if ((ssp->ss_flags & DLD_SECOBJ_OPT_CREATE) == 0) { 11900ba2cbe9Sxc151355 rw_exit(&drv_secobj_lock); 1191eae72b5bSSebastien Roy return (ENOENT); 11920ba2cbe9Sxc151355 } 11930ba2cbe9Sxc151355 objp = kmem_cache_alloc(drv_secobj_cachep, KM_SLEEP); 11940ba2cbe9Sxc151355 (void) strlcpy(objp->so_name, sobjp->so_name, 11950ba2cbe9Sxc151355 DLD_SECOBJ_NAME_MAX); 11960ba2cbe9Sxc151355 1197eae72b5bSSebastien Roy VERIFY(mod_hash_insert(drv_secobj_hash, 1198eae72b5bSSebastien Roy (mod_hash_key_t)objp->so_name, (mod_hash_val_t)objp) == 0); 11990ba2cbe9Sxc151355 } 12000ba2cbe9Sxc151355 bcopy(sobjp->so_val, objp->so_val, sobjp->so_len); 12010ba2cbe9Sxc151355 objp->so_len = sobjp->so_len; 12020ba2cbe9Sxc151355 objp->so_class = sobjp->so_class; 12030ba2cbe9Sxc151355 rw_exit(&drv_secobj_lock); 1204eae72b5bSSebastien Roy return (0); 12050ba2cbe9Sxc151355 } 12060ba2cbe9Sxc151355 12070ba2cbe9Sxc151355 typedef struct dld_secobj_state { 12080ba2cbe9Sxc151355 uint_t ss_free; 12090ba2cbe9Sxc151355 uint_t ss_count; 12100ba2cbe9Sxc151355 int ss_rc; 1211eae72b5bSSebastien Roy int ss_mode; 12120ba2cbe9Sxc151355 dld_secobj_t *ss_objp; 12130ba2cbe9Sxc151355 } dld_secobj_state_t; 12140ba2cbe9Sxc151355 12150ba2cbe9Sxc151355 /* ARGSUSED */ 12160ba2cbe9Sxc151355 static uint_t 12170ba2cbe9Sxc151355 drv_secobj_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 12180ba2cbe9Sxc151355 { 12190ba2cbe9Sxc151355 dld_secobj_state_t *statep = arg; 12200ba2cbe9Sxc151355 dld_secobj_t *sobjp = (dld_secobj_t *)val; 12210ba2cbe9Sxc151355 12220ba2cbe9Sxc151355 if (statep->ss_free < sizeof (dld_secobj_t)) { 12230ba2cbe9Sxc151355 statep->ss_rc = ENOSPC; 12240ba2cbe9Sxc151355 return (MH_WALK_TERMINATE); 12250ba2cbe9Sxc151355 } 1226eae72b5bSSebastien Roy if (ddi_copyout(sobjp, statep->ss_objp, sizeof (*sobjp), 1227eae72b5bSSebastien Roy statep->ss_mode) != 0) { 1228eae72b5bSSebastien Roy statep->ss_rc = EFAULT; 1229eae72b5bSSebastien Roy return (MH_WALK_TERMINATE); 1230eae72b5bSSebastien Roy } 12310ba2cbe9Sxc151355 statep->ss_objp++; 12320ba2cbe9Sxc151355 statep->ss_free -= sizeof (dld_secobj_t); 12330ba2cbe9Sxc151355 statep->ss_count++; 12340ba2cbe9Sxc151355 return (MH_WALK_CONTINUE); 12350ba2cbe9Sxc151355 } 12360ba2cbe9Sxc151355 1237eae72b5bSSebastien Roy /* ARGSUSED */ 1238eae72b5bSSebastien Roy static int 1239da14cebeSEric Cheng drv_ioc_secobj_get(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 12400ba2cbe9Sxc151355 { 1241eae72b5bSSebastien Roy dld_ioc_secobj_get_t *sgp = karg; 12420ba2cbe9Sxc151355 dld_secobj_t *sobjp, *objp; 1243eae72b5bSSebastien Roy int err; 12440ba2cbe9Sxc151355 12450ba2cbe9Sxc151355 sobjp = &sgp->sg_obj; 12460ba2cbe9Sxc151355 if (sobjp->so_name[DLD_SECOBJ_NAME_MAX - 1] != '\0') 1247eae72b5bSSebastien Roy return (EINVAL); 12480ba2cbe9Sxc151355 12490ba2cbe9Sxc151355 rw_enter(&drv_secobj_lock, RW_READER); 12500ba2cbe9Sxc151355 if (sobjp->so_name[0] != '\0') { 12510ba2cbe9Sxc151355 err = mod_hash_find(drv_secobj_hash, 12520ba2cbe9Sxc151355 (mod_hash_key_t)sobjp->so_name, (mod_hash_val_t *)&objp); 12530ba2cbe9Sxc151355 if (err != 0) { 12540ba2cbe9Sxc151355 ASSERT(err == MH_ERR_NOTFOUND); 12550ba2cbe9Sxc151355 rw_exit(&drv_secobj_lock); 1256eae72b5bSSebastien Roy return (ENOENT); 12570ba2cbe9Sxc151355 } 12580ba2cbe9Sxc151355 bcopy(objp->so_val, sobjp->so_val, objp->so_len); 12590ba2cbe9Sxc151355 sobjp->so_len = objp->so_len; 12600ba2cbe9Sxc151355 sobjp->so_class = objp->so_class; 12610ba2cbe9Sxc151355 sgp->sg_count = 1; 12620ba2cbe9Sxc151355 } else { 12630ba2cbe9Sxc151355 dld_secobj_state_t state; 12640ba2cbe9Sxc151355 1265eae72b5bSSebastien Roy state.ss_free = sgp->sg_size - sizeof (dld_ioc_secobj_get_t); 12660ba2cbe9Sxc151355 state.ss_count = 0; 12670ba2cbe9Sxc151355 state.ss_rc = 0; 1268eae72b5bSSebastien Roy state.ss_mode = mode; 1269eae72b5bSSebastien Roy state.ss_objp = (dld_secobj_t *)((uchar_t *)arg + 1270eae72b5bSSebastien Roy sizeof (dld_ioc_secobj_get_t)); 1271eae72b5bSSebastien Roy 12720ba2cbe9Sxc151355 mod_hash_walk(drv_secobj_hash, drv_secobj_walker, &state); 12730ba2cbe9Sxc151355 if (state.ss_rc != 0) { 12740ba2cbe9Sxc151355 rw_exit(&drv_secobj_lock); 1275eae72b5bSSebastien Roy return (state.ss_rc); 12760ba2cbe9Sxc151355 } 12770ba2cbe9Sxc151355 sgp->sg_count = state.ss_count; 12780ba2cbe9Sxc151355 } 12790ba2cbe9Sxc151355 rw_exit(&drv_secobj_lock); 1280eae72b5bSSebastien Roy return (0); 12810ba2cbe9Sxc151355 } 12820ba2cbe9Sxc151355 1283eae72b5bSSebastien Roy /* ARGSUSED */ 1284eae72b5bSSebastien Roy static int 1285da14cebeSEric Cheng drv_ioc_secobj_unset(void *karg, intptr_t arg, int mode, cred_t *cred, 1286da14cebeSEric Cheng int *rvalp) 12870ba2cbe9Sxc151355 { 1288eae72b5bSSebastien Roy dld_ioc_secobj_unset_t *sup = karg; 12890ba2cbe9Sxc151355 dld_secobj_t *objp; 12900ba2cbe9Sxc151355 mod_hash_val_t val; 1291eae72b5bSSebastien Roy int err; 12920ba2cbe9Sxc151355 12930ba2cbe9Sxc151355 if (sup->su_name[DLD_SECOBJ_NAME_MAX - 1] != '\0') 1294eae72b5bSSebastien Roy return (EINVAL); 12950ba2cbe9Sxc151355 12960ba2cbe9Sxc151355 rw_enter(&drv_secobj_lock, RW_WRITER); 12970ba2cbe9Sxc151355 err = mod_hash_find(drv_secobj_hash, (mod_hash_key_t)sup->su_name, 12980ba2cbe9Sxc151355 (mod_hash_val_t *)&objp); 12990ba2cbe9Sxc151355 if (err != 0) { 13000ba2cbe9Sxc151355 ASSERT(err == MH_ERR_NOTFOUND); 13010ba2cbe9Sxc151355 rw_exit(&drv_secobj_lock); 1302eae72b5bSSebastien Roy return (ENOENT); 13030ba2cbe9Sxc151355 } 1304eae72b5bSSebastien Roy VERIFY(mod_hash_remove(drv_secobj_hash, (mod_hash_key_t)sup->su_name, 1305eae72b5bSSebastien Roy (mod_hash_val_t *)&val) == 0); 13060ba2cbe9Sxc151355 ASSERT(objp == (dld_secobj_t *)val); 13070ba2cbe9Sxc151355 13080ba2cbe9Sxc151355 kmem_cache_free(drv_secobj_cachep, objp); 13090ba2cbe9Sxc151355 rw_exit(&drv_secobj_lock); 1310eae72b5bSSebastien Roy return (0); 1311eae72b5bSSebastien Roy } 13120ba2cbe9Sxc151355 131359596c01SRobert Mustacchi /* ARGSUSED */ 131459596c01SRobert Mustacchi static int 131559596c01SRobert Mustacchi drv_ioc_gettran(void *karg, intptr_t arg, int mode, cred_t *cred, 131659596c01SRobert Mustacchi int *rvalp) 131759596c01SRobert Mustacchi { 131859596c01SRobert Mustacchi int ret = 0; 131959596c01SRobert Mustacchi mac_perim_handle_t mph = NULL; 132059596c01SRobert Mustacchi dls_dl_handle_t dlh = NULL; 132159596c01SRobert Mustacchi dls_link_t *dlp = NULL; 132259596c01SRobert Mustacchi dld_ioc_gettran_t *dgt = karg; 132359596c01SRobert Mustacchi 132459596c01SRobert Mustacchi if ((ret = mac_perim_enter_by_linkid(dgt->dgt_linkid, &mph)) != 0) 132559596c01SRobert Mustacchi goto done; 132659596c01SRobert Mustacchi 132759596c01SRobert Mustacchi if ((ret = dls_devnet_hold_link(dgt->dgt_linkid, &dlh, &dlp)) != 0) 132859596c01SRobert Mustacchi goto done; 132959596c01SRobert Mustacchi 133059596c01SRobert Mustacchi /* 133159596c01SRobert Mustacchi * Make sure that this link belongs to the zone. 133259596c01SRobert Mustacchi */ 133359596c01SRobert Mustacchi if (crgetzoneid(cred) != dls_devnet_getownerzid(dlh)) { 133459596c01SRobert Mustacchi ret = ENOENT; 133559596c01SRobert Mustacchi goto done; 133659596c01SRobert Mustacchi } 133759596c01SRobert Mustacchi 133859596c01SRobert Mustacchi if (dgt->dgt_tran_id == DLDIOC_GETTRAN_GETNTRAN) { 133959596c01SRobert Mustacchi ret = mac_transceiver_count(dlp->dl_mh, &dgt->dgt_tran_id); 134059596c01SRobert Mustacchi } else { 134159596c01SRobert Mustacchi ret = mac_transceiver_info(dlp->dl_mh, dgt->dgt_tran_id, 134259596c01SRobert Mustacchi &dgt->dgt_present, &dgt->dgt_usable); 134359596c01SRobert Mustacchi } 134459596c01SRobert Mustacchi 134559596c01SRobert Mustacchi done: 134659596c01SRobert Mustacchi if (dlh != NULL && dlp != NULL) { 134759596c01SRobert Mustacchi dls_devnet_rele_link(dlh, dlp); 134859596c01SRobert Mustacchi } 134959596c01SRobert Mustacchi 135059596c01SRobert Mustacchi if (mph != NULL) { 135159596c01SRobert Mustacchi mac_perim_exit(mph); 135259596c01SRobert Mustacchi } 135359596c01SRobert Mustacchi 135459596c01SRobert Mustacchi return (ret); 135559596c01SRobert Mustacchi } 135659596c01SRobert Mustacchi 135759596c01SRobert Mustacchi /* ARGSUSED */ 135859596c01SRobert Mustacchi static int 135959596c01SRobert Mustacchi drv_ioc_readtran(void *karg, intptr_t arg, int mode, cred_t *cred, 136059596c01SRobert Mustacchi int *rvalp) 136159596c01SRobert Mustacchi { 136259596c01SRobert Mustacchi int ret = 0; 136359596c01SRobert Mustacchi mac_perim_handle_t mph = NULL; 136459596c01SRobert Mustacchi dls_dl_handle_t dlh = NULL; 136559596c01SRobert Mustacchi dls_link_t *dlp = NULL; 136659596c01SRobert Mustacchi dld_ioc_tranio_t *dti = karg; 136759596c01SRobert Mustacchi uint8_t buf[256]; 136859596c01SRobert Mustacchi size_t nr; 136959596c01SRobert Mustacchi 137059596c01SRobert Mustacchi /* 137159596c01SRobert Mustacchi * Be strict for the moment 137259596c01SRobert Mustacchi */ 137359596c01SRobert Mustacchi if (dti->dti_nbytes != 256 || dti->dti_off != 0) 137459596c01SRobert Mustacchi return (EINVAL); 137559596c01SRobert Mustacchi 137659596c01SRobert Mustacchi if ((ret = mac_perim_enter_by_linkid(dti->dti_linkid, &mph)) != 0) 137759596c01SRobert Mustacchi goto done; 137859596c01SRobert Mustacchi 137959596c01SRobert Mustacchi if ((ret = dls_devnet_hold_link(dti->dti_linkid, &dlh, &dlp)) != 0) 138059596c01SRobert Mustacchi goto done; 138159596c01SRobert Mustacchi 138259596c01SRobert Mustacchi /* 138359596c01SRobert Mustacchi * Make sure that this link belongs to the zone. 138459596c01SRobert Mustacchi */ 138559596c01SRobert Mustacchi if (crgetzoneid(cred) != dls_devnet_getownerzid(dlh)) { 138659596c01SRobert Mustacchi ret = ENOENT; 138759596c01SRobert Mustacchi goto done; 138859596c01SRobert Mustacchi } 138959596c01SRobert Mustacchi 139059596c01SRobert Mustacchi bzero(buf, sizeof (buf)); 139159596c01SRobert Mustacchi if ((ret = mac_transceiver_read(dlp->dl_mh, dti->dti_tran_id, 139259596c01SRobert Mustacchi dti->dti_page, buf, dti->dti_nbytes, dti->dti_off, &nr)) == 0) { 139359596c01SRobert Mustacchi dti->dti_nbytes = nr; 139459596c01SRobert Mustacchi ret = ddi_copyout(buf, (void *)(uintptr_t)dti->dti_buf, 139559596c01SRobert Mustacchi sizeof (buf), mode); 139659596c01SRobert Mustacchi } 139759596c01SRobert Mustacchi 139859596c01SRobert Mustacchi done: 139959596c01SRobert Mustacchi if (dlh != NULL && dlp != NULL) { 140059596c01SRobert Mustacchi dls_devnet_rele_link(dlh, dlp); 140159596c01SRobert Mustacchi } 140259596c01SRobert Mustacchi 140359596c01SRobert Mustacchi if (mph != NULL) { 140459596c01SRobert Mustacchi mac_perim_exit(mph); 140559596c01SRobert Mustacchi } 140659596c01SRobert Mustacchi 140759596c01SRobert Mustacchi return (ret); 140859596c01SRobert Mustacchi } 140959596c01SRobert Mustacchi 1410*b142f83dSRobert Mustacchi /* ARGSUSED */ 1411*b142f83dSRobert Mustacchi static int 1412*b142f83dSRobert Mustacchi drv_ioc_getled(void *karg, intptr_t arg, int mode, cred_t *cred, 1413*b142f83dSRobert Mustacchi int *rvalp) 1414*b142f83dSRobert Mustacchi { 1415*b142f83dSRobert Mustacchi int ret = 0; 1416*b142f83dSRobert Mustacchi mac_perim_handle_t mph = NULL; 1417*b142f83dSRobert Mustacchi dls_dl_handle_t dlh = NULL; 1418*b142f83dSRobert Mustacchi dls_link_t *dlp = NULL; 1419*b142f83dSRobert Mustacchi dld_ioc_led_t *dil = karg; 1420*b142f83dSRobert Mustacchi 1421*b142f83dSRobert Mustacchi if ((mode & FREAD) == 0) 1422*b142f83dSRobert Mustacchi return (EBADF); 1423*b142f83dSRobert Mustacchi 1424*b142f83dSRobert Mustacchi if ((ret = dls_devnet_hold_tmp(dil->dil_linkid, &dlh)) != 0) 1425*b142f83dSRobert Mustacchi goto done; 1426*b142f83dSRobert Mustacchi 1427*b142f83dSRobert Mustacchi if ((ret = mac_perim_enter_by_macname(dls_devnet_mac(dlh), &mph)) != 0) 1428*b142f83dSRobert Mustacchi goto done; 1429*b142f83dSRobert Mustacchi 1430*b142f83dSRobert Mustacchi if ((ret = dls_link_hold(dls_devnet_mac(dlh), &dlp)) != 0) 1431*b142f83dSRobert Mustacchi goto done; 1432*b142f83dSRobert Mustacchi 1433*b142f83dSRobert Mustacchi /* 1434*b142f83dSRobert Mustacchi * Make sure that this link belongs to the zone. 1435*b142f83dSRobert Mustacchi */ 1436*b142f83dSRobert Mustacchi if (crgetzoneid(cred) != dls_devnet_getownerzid(dlh)) { 1437*b142f83dSRobert Mustacchi ret = ENOENT; 1438*b142f83dSRobert Mustacchi goto done; 1439*b142f83dSRobert Mustacchi } 1440*b142f83dSRobert Mustacchi 1441*b142f83dSRobert Mustacchi ret = mac_led_get(dlp->dl_mh, &dil->dil_supported, &dil->dil_active); 1442*b142f83dSRobert Mustacchi 1443*b142f83dSRobert Mustacchi done: 1444*b142f83dSRobert Mustacchi if (dlp != NULL) 1445*b142f83dSRobert Mustacchi dls_link_rele(dlp); 1446*b142f83dSRobert Mustacchi 1447*b142f83dSRobert Mustacchi if (mph != NULL) 1448*b142f83dSRobert Mustacchi mac_perim_exit(mph); 1449*b142f83dSRobert Mustacchi 1450*b142f83dSRobert Mustacchi if (dlh != NULL) 1451*b142f83dSRobert Mustacchi dls_devnet_rele_tmp(dlh); 1452*b142f83dSRobert Mustacchi 1453*b142f83dSRobert Mustacchi return (ret); 1454*b142f83dSRobert Mustacchi } 1455*b142f83dSRobert Mustacchi 1456*b142f83dSRobert Mustacchi /* ARGSUSED */ 1457*b142f83dSRobert Mustacchi static int 1458*b142f83dSRobert Mustacchi drv_ioc_setled(void *karg, intptr_t arg, int mode, cred_t *cred, 1459*b142f83dSRobert Mustacchi int *rvalp) 1460*b142f83dSRobert Mustacchi { 1461*b142f83dSRobert Mustacchi int ret = 0; 1462*b142f83dSRobert Mustacchi mac_perim_handle_t mph = NULL; 1463*b142f83dSRobert Mustacchi dls_dl_handle_t dlh = NULL; 1464*b142f83dSRobert Mustacchi dls_link_t *dlp = NULL; 1465*b142f83dSRobert Mustacchi dld_ioc_led_t *dil = karg; 1466*b142f83dSRobert Mustacchi 1467*b142f83dSRobert Mustacchi if ((mode & FWRITE) == 0) 1468*b142f83dSRobert Mustacchi return (EBADF); 1469*b142f83dSRobert Mustacchi 1470*b142f83dSRobert Mustacchi if ((ret = dls_devnet_hold_tmp(dil->dil_linkid, &dlh)) != 0) 1471*b142f83dSRobert Mustacchi goto done; 1472*b142f83dSRobert Mustacchi 1473*b142f83dSRobert Mustacchi if ((ret = mac_perim_enter_by_macname(dls_devnet_mac(dlh), &mph)) != 0) 1474*b142f83dSRobert Mustacchi goto done; 1475*b142f83dSRobert Mustacchi 1476*b142f83dSRobert Mustacchi if ((ret = dls_link_hold(dls_devnet_mac(dlh), &dlp)) != 0) 1477*b142f83dSRobert Mustacchi goto done; 1478*b142f83dSRobert Mustacchi 1479*b142f83dSRobert Mustacchi /* 1480*b142f83dSRobert Mustacchi * Make sure that this link belongs to the zone. 1481*b142f83dSRobert Mustacchi */ 1482*b142f83dSRobert Mustacchi if (crgetzoneid(cred) != dls_devnet_getownerzid(dlh)) { 1483*b142f83dSRobert Mustacchi ret = ENOENT; 1484*b142f83dSRobert Mustacchi goto done; 1485*b142f83dSRobert Mustacchi } 1486*b142f83dSRobert Mustacchi 1487*b142f83dSRobert Mustacchi ret = mac_led_set(dlp->dl_mh, dil->dil_active); 1488*b142f83dSRobert Mustacchi 1489*b142f83dSRobert Mustacchi done: 1490*b142f83dSRobert Mustacchi if (dlp != NULL) 1491*b142f83dSRobert Mustacchi dls_link_rele(dlp); 1492*b142f83dSRobert Mustacchi 1493*b142f83dSRobert Mustacchi if (mph != NULL) 1494*b142f83dSRobert Mustacchi mac_perim_exit(mph); 1495*b142f83dSRobert Mustacchi 1496*b142f83dSRobert Mustacchi if (dlh != NULL) 1497*b142f83dSRobert Mustacchi dls_devnet_rele_tmp(dlh); 1498*b142f83dSRobert Mustacchi 1499*b142f83dSRobert Mustacchi return (ret); 1500*b142f83dSRobert Mustacchi } 1501*b142f83dSRobert Mustacchi 1502*b142f83dSRobert Mustacchi 15032b24ab6bSSebastien Roy /* 15042b24ab6bSSebastien Roy * Note that ioctls that modify links have a NULL di_priv_func(), as 15052b24ab6bSSebastien Roy * privileges can only be checked after we know the class of the link being 15062b24ab6bSSebastien Roy * modified (due to class-specific fine-grained privileges such as 15072b24ab6bSSebastien Roy * sys_iptun_config). 15082b24ab6bSSebastien Roy */ 1509eae72b5bSSebastien Roy static dld_ioc_info_t drv_ioc_list[] = { 1510eae72b5bSSebastien Roy {DLDIOC_ATTR, DLDCOPYINOUT, sizeof (dld_ioc_attr_t), 15112b24ab6bSSebastien Roy drv_ioc_attr, NULL}, 1512eae72b5bSSebastien Roy {DLDIOC_PHYS_ATTR, DLDCOPYINOUT, sizeof (dld_ioc_phys_attr_t), 15132b24ab6bSSebastien Roy drv_ioc_phys_attr, NULL}, 1514da14cebeSEric Cheng {DLDIOC_SECOBJ_SET, DLDCOPYIN, sizeof (dld_ioc_secobj_set_t), 15152b24ab6bSSebastien Roy drv_ioc_secobj_set, secpolicy_dl_config}, 1516da14cebeSEric Cheng {DLDIOC_SECOBJ_GET, DLDCOPYINOUT, sizeof (dld_ioc_secobj_get_t), 15172b24ab6bSSebastien Roy drv_ioc_secobj_get, secpolicy_dl_config}, 1518da14cebeSEric Cheng {DLDIOC_SECOBJ_UNSET, DLDCOPYIN, sizeof (dld_ioc_secobj_unset_t), 15192b24ab6bSSebastien Roy drv_ioc_secobj_unset, secpolicy_dl_config}, 1520da14cebeSEric Cheng {DLDIOC_DOORSERVER, DLDCOPYIN, sizeof (dld_ioc_door_t), 15212b24ab6bSSebastien Roy drv_ioc_doorserver, secpolicy_dl_config}, 1522da14cebeSEric Cheng {DLDIOC_RENAME, DLDCOPYIN, sizeof (dld_ioc_rename_t), 15232b24ab6bSSebastien Roy drv_ioc_rename, NULL}, 1524da14cebeSEric Cheng {DLDIOC_MACADDRGET, DLDCOPYINOUT, sizeof (dld_ioc_macaddrget_t), 15252b24ab6bSSebastien Roy drv_ioc_macaddrget, NULL}, 1526da14cebeSEric Cheng {DLDIOC_ADDFLOW, DLDCOPYIN, sizeof (dld_ioc_addflow_t), 15272b24ab6bSSebastien Roy drv_ioc_addflow, secpolicy_dl_config}, 1528da14cebeSEric Cheng {DLDIOC_REMOVEFLOW, DLDCOPYIN, sizeof (dld_ioc_removeflow_t), 15292b24ab6bSSebastien Roy drv_ioc_removeflow, secpolicy_dl_config}, 1530da14cebeSEric Cheng {DLDIOC_MODIFYFLOW, DLDCOPYIN, sizeof (dld_ioc_modifyflow_t), 15312b24ab6bSSebastien Roy drv_ioc_modifyflow, secpolicy_dl_config}, 1532da14cebeSEric Cheng {DLDIOC_WALKFLOW, DLDCOPYINOUT, sizeof (dld_ioc_walkflow_t), 15332b24ab6bSSebastien Roy drv_ioc_walkflow, NULL}, 1534da14cebeSEric Cheng {DLDIOC_USAGELOG, DLDCOPYIN, sizeof (dld_ioc_usagelog_t), 15352b24ab6bSSebastien Roy drv_ioc_usagelog, secpolicy_dl_config}, 1536da14cebeSEric Cheng {DLDIOC_SETMACPROP, DLDCOPYIN, sizeof (dld_ioc_macprop_t), 15372b24ab6bSSebastien Roy drv_ioc_setprop, NULL}, 1538eae72b5bSSebastien Roy {DLDIOC_GETMACPROP, DLDCOPYIN, sizeof (dld_ioc_macprop_t), 15392b24ab6bSSebastien Roy drv_ioc_getprop, NULL}, 1540da14cebeSEric Cheng {DLDIOC_GETHWGRP, DLDCOPYINOUT, sizeof (dld_ioc_hwgrpget_t), 15410dc2366fSVenugopal Iyer drv_ioc_hwgrpget, NULL}, 154259596c01SRobert Mustacchi {DLDIOC_GETTRAN, DLDCOPYINOUT, sizeof (dld_ioc_gettran_t), 154359596c01SRobert Mustacchi drv_ioc_gettran, NULL }, 154459596c01SRobert Mustacchi {DLDIOC_READTRAN, DLDCOPYINOUT, sizeof (dld_ioc_tranio_t), 1545*b142f83dSRobert Mustacchi drv_ioc_readtran, NULL }, 1546*b142f83dSRobert Mustacchi {DLDIOC_GETLED, DLDCOPYINOUT, sizeof (dld_ioc_led_t), 1547*b142f83dSRobert Mustacchi drv_ioc_getled, NULL }, 1548*b142f83dSRobert Mustacchi {DLDIOC_SETLED, DLDCOPYIN, sizeof (dld_ioc_led_t), 1549*b142f83dSRobert Mustacchi drv_ioc_setled, secpolicy_dl_config} 1550eae72b5bSSebastien Roy }; 1551eae72b5bSSebastien Roy 1552eae72b5bSSebastien Roy typedef struct dld_ioc_modentry { 1553eae72b5bSSebastien Roy uint16_t dim_modid; /* Top 16 bits of ioctl command */ 1554eae72b5bSSebastien Roy char *dim_modname; /* Module to be loaded */ 155515766bceSPrakash Jalan int ctrl_node_inst; /* Ctrl node instance */ 1556eae72b5bSSebastien Roy dld_ioc_info_t *dim_list; /* array of ioctl structures */ 1557eae72b5bSSebastien Roy uint_t dim_count; /* number of elements in dim_list */ 1558eae72b5bSSebastien Roy } dld_ioc_modentry_t; 1559eae72b5bSSebastien Roy 1560eae72b5bSSebastien Roy /* 1561eae72b5bSSebastien Roy * For all modules except for dld, dim_list and dim_count are assigned 1562eae72b5bSSebastien Roy * when the modules register their ioctls in dld_ioc_register(). We 1563eae72b5bSSebastien Roy * can statically initialize dld's ioctls in-line here; there's no 156415766bceSPrakash Jalan * need for it to call dld_ioc_register() itself. ctrl_node_inst controls 156515766bceSPrakash Jalan * whether an instance of the device will be held or the driver. If set to 156615766bceSPrakash Jalan * a non-negative integer, device instance specified in ctrl_node_inst will 156715766bceSPrakash Jalan * be held; so dld_ioc_register() _must_ be called in xxx_attach() routine of 156815766bceSPrakash Jalan * the driver. If set to -1, driver will be held; so dld_ioc_register() _must_ 156915766bceSPrakash Jalan * be called in xxx_init() routine of the driver. 1570eae72b5bSSebastien Roy */ 1571eae72b5bSSebastien Roy static dld_ioc_modentry_t dld_ioc_modtable[] = { 157215766bceSPrakash Jalan {DLD_IOC, "dld", 0, drv_ioc_list, DLDIOCCNT(drv_ioc_list)}, 157315766bceSPrakash Jalan {AGGR_IOC, "aggr", 0, NULL, 0}, 157415766bceSPrakash Jalan {VNIC_IOC, "vnic", 0, NULL, 0}, 157515766bceSPrakash Jalan {SIMNET_IOC, "simnet", 0, NULL, 0}, 157615766bceSPrakash Jalan {BRIDGE_IOC, "bridge", 0, NULL, 0}, 15771cfa752fSRamaswamy Tummala {IPTUN_IOC, "iptun", 0, NULL, 0}, 15781cfa752fSRamaswamy Tummala {IBPART_IOC, "ibp", -1, NULL, 0} 1579eae72b5bSSebastien Roy }; 1580eae72b5bSSebastien Roy #define DLDIOC_CNT \ 1581eae72b5bSSebastien Roy (sizeof (dld_ioc_modtable) / sizeof (dld_ioc_modentry_t)) 1582eae72b5bSSebastien Roy 1583eae72b5bSSebastien Roy static dld_ioc_modentry_t * 1584eae72b5bSSebastien Roy dld_ioc_findmod(uint16_t modid) 1585eae72b5bSSebastien Roy { 1586eae72b5bSSebastien Roy int i; 1587eae72b5bSSebastien Roy 1588eae72b5bSSebastien Roy for (i = 0; i < DLDIOC_CNT; i++) { 1589eae72b5bSSebastien Roy if (modid == dld_ioc_modtable[i].dim_modid) 1590eae72b5bSSebastien Roy return (&dld_ioc_modtable[i]); 1591eae72b5bSSebastien Roy } 1592eae72b5bSSebastien Roy return (NULL); 1593eae72b5bSSebastien Roy } 1594eae72b5bSSebastien Roy 1595eae72b5bSSebastien Roy int 1596eae72b5bSSebastien Roy dld_ioc_register(uint16_t modid, dld_ioc_info_t *list, uint_t count) 1597eae72b5bSSebastien Roy { 1598eae72b5bSSebastien Roy dld_ioc_modentry_t *dim = dld_ioc_findmod(modid); 1599eae72b5bSSebastien Roy 1600eae72b5bSSebastien Roy if (dim == NULL) 1601eae72b5bSSebastien Roy return (ENOENT); 1602eae72b5bSSebastien Roy 1603eae72b5bSSebastien Roy dim->dim_list = list; 1604eae72b5bSSebastien Roy dim->dim_count = count; 1605eae72b5bSSebastien Roy return (0); 1606eae72b5bSSebastien Roy } 1607eae72b5bSSebastien Roy 1608eae72b5bSSebastien Roy void 1609eae72b5bSSebastien Roy dld_ioc_unregister(uint16_t modid) 1610eae72b5bSSebastien Roy { 1611eae72b5bSSebastien Roy VERIFY(dld_ioc_register(modid, NULL, 0) == 0); 1612eae72b5bSSebastien Roy } 1613eae72b5bSSebastien Roy 1614eae72b5bSSebastien Roy /* 1615eae72b5bSSebastien Roy * The general design with GLDv3 ioctls is that all ioctls issued 1616eae72b5bSSebastien Roy * through /dev/dld go through this drv_ioctl() function. This 1617eae72b5bSSebastien Roy * function handles all ioctls on behalf of modules listed in 1618eae72b5bSSebastien Roy * dld_ioc_modtable. 1619eae72b5bSSebastien Roy * 1620eae72b5bSSebastien Roy * When an ioctl is received, this function looks for the associated 1621eae72b5bSSebastien Roy * module-id-specific ioctl information using dld_ioc_findmod(). The 162215766bceSPrakash Jalan * call to ddi_hold_driver() or ddi_hold_devi_by_instance() on the 162315766bceSPrakash Jalan * associated device will cause the kernel module responsible for the 162415766bceSPrakash Jalan * ioctl to be loaded if it's not already loaded, which should result 162515766bceSPrakash Jalan * in that module calling dld_ioc_register(), thereby filling in the 162615766bceSPrakash Jalan * dim_list containing the details for the ioctl being processed. 1627eae72b5bSSebastien Roy * 1628eae72b5bSSebastien Roy * This function can then perform operations such as copyin() data and 1629eae72b5bSSebastien Roy * do credential checks based on the registered ioctl information, 1630eae72b5bSSebastien Roy * then issue the callback function di_func() registered by the 1631eae72b5bSSebastien Roy * responsible module. Upon return, the appropriate copyout() 1632eae72b5bSSebastien Roy * operation can be performed and the operation completes. 1633eae72b5bSSebastien Roy */ 1634eae72b5bSSebastien Roy /* ARGSUSED */ 1635eae72b5bSSebastien Roy static int 1636eae72b5bSSebastien Roy drv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred, int *rvalp) 1637eae72b5bSSebastien Roy { 1638eae72b5bSSebastien Roy dld_ioc_modentry_t *dim; 1639eae72b5bSSebastien Roy dld_ioc_info_t *info; 1640eae72b5bSSebastien Roy dev_info_t *dip = NULL; 164115766bceSPrakash Jalan struct dev_ops *dops = NULL; 164215766bceSPrakash Jalan major_t major; 1643eae72b5bSSebastien Roy void *buf = NULL; 1644eae72b5bSSebastien Roy size_t sz; 1645eae72b5bSSebastien Roy int i, err; 1646eae72b5bSSebastien Roy 1647eae72b5bSSebastien Roy if ((dim = dld_ioc_findmod(DLD_IOC_MODID(cmd))) == NULL) 1648eae72b5bSSebastien Roy return (ENOTSUP); 1649eae72b5bSSebastien Roy 165015766bceSPrakash Jalan major = ddi_name_to_major(dim->dim_modname); 165115766bceSPrakash Jalan 165215766bceSPrakash Jalan if (dim->ctrl_node_inst == -1) { 165315766bceSPrakash Jalan /* 165415766bceSPrakash Jalan * No dedicated instance to process ioctls. 165515766bceSPrakash Jalan * dld_ioc_register() is called in xxx_init(). 165615766bceSPrakash Jalan */ 165715766bceSPrakash Jalan dops = ddi_hold_driver(major); 165815766bceSPrakash Jalan } else { 165915766bceSPrakash Jalan /* 166015766bceSPrakash Jalan * Dedicated instance to handle ioctl. 166115766bceSPrakash Jalan * dld_ioc_register() is called in xxx_attach(). 166215766bceSPrakash Jalan */ 166315766bceSPrakash Jalan dip = ddi_hold_devi_by_instance(major, dim->ctrl_node_inst, 0); 166415766bceSPrakash Jalan } 166515766bceSPrakash Jalan 166615766bceSPrakash Jalan if ((dip == NULL && dops == NULL) || dim->dim_list == NULL) { 1667eae72b5bSSebastien Roy err = ENODEV; 1668eae72b5bSSebastien Roy goto done; 1669eae72b5bSSebastien Roy } 1670eae72b5bSSebastien Roy 1671eae72b5bSSebastien Roy for (i = 0; i < dim->dim_count; i++) { 1672eae72b5bSSebastien Roy if (cmd == dim->dim_list[i].di_cmd) 1673eae72b5bSSebastien Roy break; 1674eae72b5bSSebastien Roy } 1675eae72b5bSSebastien Roy if (i == dim->dim_count) { 1676eae72b5bSSebastien Roy err = ENOTSUP; 1677eae72b5bSSebastien Roy goto done; 1678eae72b5bSSebastien Roy } 1679eae72b5bSSebastien Roy 1680eae72b5bSSebastien Roy info = &dim->dim_list[i]; 16812b24ab6bSSebastien Roy 16822b24ab6bSSebastien Roy if (info->di_priv_func != NULL && 16832b24ab6bSSebastien Roy (err = info->di_priv_func(cred)) != 0) 1684eae72b5bSSebastien Roy goto done; 1685eae72b5bSSebastien Roy 1686eae72b5bSSebastien Roy sz = info->di_argsize; 1687eae72b5bSSebastien Roy if ((buf = kmem_zalloc(sz, KM_NOSLEEP)) == NULL) { 1688eae72b5bSSebastien Roy err = ENOMEM; 1689eae72b5bSSebastien Roy goto done; 1690eae72b5bSSebastien Roy } 1691eae72b5bSSebastien Roy 1692eae72b5bSSebastien Roy if ((info->di_flags & DLDCOPYIN) && 1693eae72b5bSSebastien Roy ddi_copyin((void *)arg, buf, sz, mode) != 0) { 1694eae72b5bSSebastien Roy err = EFAULT; 1695eae72b5bSSebastien Roy goto done; 1696eae72b5bSSebastien Roy } 1697eae72b5bSSebastien Roy 1698da14cebeSEric Cheng err = info->di_func(buf, arg, mode, cred, rvalp); 1699eae72b5bSSebastien Roy 1700eae72b5bSSebastien Roy if ((info->di_flags & DLDCOPYOUT) && 1701eae72b5bSSebastien Roy ddi_copyout(buf, (void *)arg, sz, mode) != 0 && err == 0) 1702eae72b5bSSebastien Roy err = EFAULT; 1703eae72b5bSSebastien Roy 1704eae72b5bSSebastien Roy done: 1705eae72b5bSSebastien Roy if (buf != NULL) 1706eae72b5bSSebastien Roy kmem_free(buf, sz); 1707eae72b5bSSebastien Roy if (dip != NULL) 1708eae72b5bSSebastien Roy ddi_release_devi(dip); 170915766bceSPrakash Jalan if (dops != NULL) 171015766bceSPrakash Jalan ddi_rele_driver(major); 1711eae72b5bSSebastien Roy return (err); 17120ba2cbe9Sxc151355 } 1713