17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5ba2e4443Sseb * Common Development and Distribution License (the "License"). 6ba2e4443Sseb * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*d62bc4baSyz * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * Data-Link Driver 307c478bd9Sstevel@tonic-gate */ 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #include <sys/conf.h> 33210db224Sericheng #include <sys/mkdev.h> 347c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 35210db224Sericheng #include <sys/stat.h> 36210db224Sericheng #include <sys/strsun.h> 37*d62bc4baSyz #include <sys/vlan.h> 387c478bd9Sstevel@tonic-gate #include <sys/dld.h> 397c478bd9Sstevel@tonic-gate #include <sys/dld_impl.h> 40210db224Sericheng #include <sys/dls_impl.h> 41*d62bc4baSyz #include <sys/softmac.h> 42f4b3ec61Sdh #include <sys/vlan.h> 43210db224Sericheng #include <inet/common.h> 44210db224Sericheng 45210db224Sericheng /* 46210db224Sericheng * dld control node state, one per open control node session. 47210db224Sericheng */ 48210db224Sericheng typedef struct dld_ctl_str_s { 49210db224Sericheng minor_t cs_minor; 50210db224Sericheng queue_t *cs_wq; 51210db224Sericheng } dld_ctl_str_t; 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate static void drv_init(void); 547c478bd9Sstevel@tonic-gate static int drv_fini(void); 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate static int drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 577c478bd9Sstevel@tonic-gate static int drv_attach(dev_info_t *, ddi_attach_cmd_t); 587c478bd9Sstevel@tonic-gate static int drv_detach(dev_info_t *, ddi_detach_cmd_t); 597c478bd9Sstevel@tonic-gate 600ba2cbe9Sxc /* 610ba2cbe9Sxc * Secure objects declarations 620ba2cbe9Sxc */ 630ba2cbe9Sxc #define SECOBJ_WEP_HASHSZ 67 640ba2cbe9Sxc static krwlock_t drv_secobj_lock; 650ba2cbe9Sxc static kmem_cache_t *drv_secobj_cachep; 660ba2cbe9Sxc static mod_hash_t *drv_secobj_hash; 670ba2cbe9Sxc static void drv_secobj_init(void); 680ba2cbe9Sxc static void drv_secobj_fini(void); 690ba2cbe9Sxc static void drv_ioc_secobj_set(dld_ctl_str_t *, mblk_t *); 700ba2cbe9Sxc static void drv_ioc_secobj_get(dld_ctl_str_t *, mblk_t *); 710ba2cbe9Sxc static void drv_ioc_secobj_unset(dld_ctl_str_t *, mblk_t *); 720ba2cbe9Sxc 73210db224Sericheng /* 74210db224Sericheng * The following entry points are private to dld and are used for control 75210db224Sericheng * operations only. The entry points exported to mac drivers are defined 76210db224Sericheng * in dld_str.c. Refer to the comment on top of dld_str.c for details. 77210db224Sericheng */ 787c478bd9Sstevel@tonic-gate static int drv_open(queue_t *, dev_t *, int, int, cred_t *); 797c478bd9Sstevel@tonic-gate static int drv_close(queue_t *); 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate static void drv_uw_put(queue_t *, mblk_t *); 827c478bd9Sstevel@tonic-gate static void drv_uw_srv(queue_t *); 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate dev_info_t *dld_dip; /* dev_info_t for the driver */ 85210db224Sericheng uint32_t dld_opt = 0; /* Global options */ 86210db224Sericheng static vmem_t *dld_ctl_vmem; /* for control minor numbers */ 877c478bd9Sstevel@tonic-gate 88*d62bc4baSyz #define NAUTOPUSH 32 89*d62bc4baSyz static mod_hash_t *dld_ap_hashp; 90*d62bc4baSyz static krwlock_t dld_ap_hash_lock; 91*d62bc4baSyz 927c478bd9Sstevel@tonic-gate static struct module_info drv_info = { 937c478bd9Sstevel@tonic-gate 0, /* mi_idnum */ 947c478bd9Sstevel@tonic-gate DLD_DRIVER_NAME, /* mi_idname */ 957c478bd9Sstevel@tonic-gate 0, /* mi_minpsz */ 967c478bd9Sstevel@tonic-gate (64 * 1024), /* mi_maxpsz */ 977c478bd9Sstevel@tonic-gate 1, /* mi_hiwat */ 987c478bd9Sstevel@tonic-gate 0 /* mi_lowat */ 997c478bd9Sstevel@tonic-gate }; 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate static struct qinit drv_ur_init = { 1027c478bd9Sstevel@tonic-gate NULL, /* qi_putp */ 1037c478bd9Sstevel@tonic-gate NULL, /* qi_srvp */ 1047c478bd9Sstevel@tonic-gate drv_open, /* qi_qopen */ 1057c478bd9Sstevel@tonic-gate drv_close, /* qi_qclose */ 1067c478bd9Sstevel@tonic-gate NULL, /* qi_qadmin */ 1077c478bd9Sstevel@tonic-gate &drv_info, /* qi_minfo */ 1087c478bd9Sstevel@tonic-gate NULL /* qi_mstat */ 1097c478bd9Sstevel@tonic-gate }; 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate static struct qinit drv_uw_init = { 1127c478bd9Sstevel@tonic-gate (pfi_t)drv_uw_put, /* qi_putp */ 1137c478bd9Sstevel@tonic-gate (pfi_t)drv_uw_srv, /* qi_srvp */ 1147c478bd9Sstevel@tonic-gate NULL, /* qi_qopen */ 1157c478bd9Sstevel@tonic-gate NULL, /* qi_qclose */ 1167c478bd9Sstevel@tonic-gate NULL, /* qi_qadmin */ 1177c478bd9Sstevel@tonic-gate &drv_info, /* qi_minfo */ 1187c478bd9Sstevel@tonic-gate NULL /* qi_mstat */ 1197c478bd9Sstevel@tonic-gate }; 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate static struct streamtab drv_stream = { 1227c478bd9Sstevel@tonic-gate &drv_ur_init, /* st_rdinit */ 1237c478bd9Sstevel@tonic-gate &drv_uw_init, /* st_wrinit */ 1247c478bd9Sstevel@tonic-gate NULL, /* st_muxrinit */ 1257c478bd9Sstevel@tonic-gate NULL /* st_muxwinit */ 1267c478bd9Sstevel@tonic-gate }; 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(drv_ops, nulldev, nulldev, drv_attach, drv_detach, 129210db224Sericheng nodev, drv_getinfo, D_MP, &drv_stream); 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate /* 1327c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 1337c478bd9Sstevel@tonic-gate */ 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops; 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate static struct modldrv drv_modldrv = { 1387c478bd9Sstevel@tonic-gate &mod_driverops, 1397c478bd9Sstevel@tonic-gate DLD_INFO, 1407c478bd9Sstevel@tonic-gate &drv_ops 1417c478bd9Sstevel@tonic-gate }; 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate static struct modlinkage drv_modlinkage = { 1447c478bd9Sstevel@tonic-gate MODREV_1, 1457c478bd9Sstevel@tonic-gate &drv_modldrv, 1467c478bd9Sstevel@tonic-gate NULL 1477c478bd9Sstevel@tonic-gate }; 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate int 1507c478bd9Sstevel@tonic-gate _init(void) 1517c478bd9Sstevel@tonic-gate { 1527c478bd9Sstevel@tonic-gate int err; 1537c478bd9Sstevel@tonic-gate 154210db224Sericheng drv_init(); 155210db224Sericheng 1567c478bd9Sstevel@tonic-gate if ((err = mod_install(&drv_modlinkage)) != 0) 1577c478bd9Sstevel@tonic-gate return (err); 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate return (0); 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate int 1637c478bd9Sstevel@tonic-gate _fini(void) 1647c478bd9Sstevel@tonic-gate { 1657c478bd9Sstevel@tonic-gate int err; 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate if ((err = mod_remove(&drv_modlinkage)) != 0) 1687c478bd9Sstevel@tonic-gate return (err); 1697c478bd9Sstevel@tonic-gate 170210db224Sericheng if (drv_fini() != 0) { 171210db224Sericheng (void) mod_install(&drv_modlinkage); 172210db224Sericheng return (DDI_FAILURE); 173210db224Sericheng } 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate return (err); 1767c478bd9Sstevel@tonic-gate } 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate int 1797c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 1807c478bd9Sstevel@tonic-gate { 1817c478bd9Sstevel@tonic-gate return (mod_info(&drv_modlinkage, modinfop)); 1827c478bd9Sstevel@tonic-gate } 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate /* 185210db224Sericheng * Initialize component modules. 1867c478bd9Sstevel@tonic-gate */ 1877c478bd9Sstevel@tonic-gate static void 1887c478bd9Sstevel@tonic-gate drv_init(void) 1897c478bd9Sstevel@tonic-gate { 190210db224Sericheng dld_ctl_vmem = vmem_create("dld_ctl", (void *)1, MAXMIN, 1, 191210db224Sericheng NULL, NULL, NULL, 1, VM_SLEEP | VMC_IDENTIFIER); 1920ba2cbe9Sxc drv_secobj_init(); 1937c478bd9Sstevel@tonic-gate dld_str_init(); 194*d62bc4baSyz /* 195*d62bc4baSyz * Create a hash table for autopush configuration. 196*d62bc4baSyz */ 197*d62bc4baSyz dld_ap_hashp = mod_hash_create_idhash("dld_autopush_hash", 198*d62bc4baSyz NAUTOPUSH, mod_hash_null_valdtor); 199*d62bc4baSyz 200*d62bc4baSyz ASSERT(dld_ap_hashp != NULL); 201*d62bc4baSyz rw_init(&dld_ap_hash_lock, NULL, RW_DRIVER, NULL); 202*d62bc4baSyz } 203*d62bc4baSyz 204*d62bc4baSyz /* ARGSUSED */ 205*d62bc4baSyz static uint_t 206*d62bc4baSyz drv_ap_exist(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 207*d62bc4baSyz { 208*d62bc4baSyz boolean_t *pexist = arg; 209*d62bc4baSyz 210*d62bc4baSyz *pexist = B_TRUE; 211*d62bc4baSyz return (MH_WALK_TERMINATE); 2127c478bd9Sstevel@tonic-gate } 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate static int 2157c478bd9Sstevel@tonic-gate drv_fini(void) 2167c478bd9Sstevel@tonic-gate { 217*d62bc4baSyz int err; 218*d62bc4baSyz boolean_t exist = B_FALSE; 219*d62bc4baSyz 220*d62bc4baSyz rw_enter(&dld_ap_hash_lock, RW_READER); 221*d62bc4baSyz mod_hash_walk(dld_ap_hashp, drv_ap_exist, &exist); 222*d62bc4baSyz rw_exit(&dld_ap_hash_lock); 223*d62bc4baSyz 224*d62bc4baSyz if (exist) 225*d62bc4baSyz return (EBUSY); 2267c478bd9Sstevel@tonic-gate 227210db224Sericheng if ((err = dld_str_fini()) != 0) 2287c478bd9Sstevel@tonic-gate return (err); 2297c478bd9Sstevel@tonic-gate 2300ba2cbe9Sxc drv_secobj_fini(); 231210db224Sericheng vmem_destroy(dld_ctl_vmem); 232*d62bc4baSyz mod_hash_destroy_idhash(dld_ap_hashp); 233*d62bc4baSyz rw_destroy(&dld_ap_hash_lock); 2347c478bd9Sstevel@tonic-gate return (0); 2357c478bd9Sstevel@tonic-gate } 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate /* 2387c478bd9Sstevel@tonic-gate * devo_getinfo: getinfo(9e) 2397c478bd9Sstevel@tonic-gate */ 2407c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2417c478bd9Sstevel@tonic-gate static int 2427c478bd9Sstevel@tonic-gate drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resp) 2437c478bd9Sstevel@tonic-gate { 2447c478bd9Sstevel@tonic-gate if (dld_dip == NULL) 2457c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate switch (cmd) { 2487c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 2497c478bd9Sstevel@tonic-gate *resp = (void *)0; 2507c478bd9Sstevel@tonic-gate break; 2517c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 2527c478bd9Sstevel@tonic-gate *resp = (void *)dld_dip; 2537c478bd9Sstevel@tonic-gate break; 2547c478bd9Sstevel@tonic-gate default: 2557c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2567c478bd9Sstevel@tonic-gate } 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2597c478bd9Sstevel@tonic-gate } 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate /* 2627c478bd9Sstevel@tonic-gate * Check properties to set options. (See dld.h for property definitions). 2637c478bd9Sstevel@tonic-gate */ 2647c478bd9Sstevel@tonic-gate static void 2657c478bd9Sstevel@tonic-gate drv_set_opt(dev_info_t *dip) 2667c478bd9Sstevel@tonic-gate { 2677c478bd9Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 2687c478bd9Sstevel@tonic-gate DLD_PROP_NO_FASTPATH, 0) != 0) { 2697c478bd9Sstevel@tonic-gate dld_opt |= DLD_OPT_NO_FASTPATH; 2707c478bd9Sstevel@tonic-gate } 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 2737c478bd9Sstevel@tonic-gate DLD_PROP_NO_POLL, 0) != 0) { 2747c478bd9Sstevel@tonic-gate dld_opt |= DLD_OPT_NO_POLL; 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 2787c478bd9Sstevel@tonic-gate DLD_PROP_NO_ZEROCOPY, 0) != 0) { 2797c478bd9Sstevel@tonic-gate dld_opt |= DLD_OPT_NO_ZEROCOPY; 2807c478bd9Sstevel@tonic-gate } 2819c175129Sja 2829c175129Sja if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 2839c175129Sja DLD_PROP_NO_SOFTRING, 0) != 0) { 2849c175129Sja dld_opt |= DLD_OPT_NO_SOFTRING; 2859c175129Sja } 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate /* 2897c478bd9Sstevel@tonic-gate * devo_attach: attach(9e) 2907c478bd9Sstevel@tonic-gate */ 2917c478bd9Sstevel@tonic-gate static int 2927c478bd9Sstevel@tonic-gate drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2937c478bd9Sstevel@tonic-gate { 2947c478bd9Sstevel@tonic-gate if (cmd != DDI_ATTACH) 2957c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate ASSERT(ddi_get_instance(dip) == 0); 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate drv_set_opt(dip); 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate /* 3027c478bd9Sstevel@tonic-gate * Create control node. DLPI provider nodes will be created on demand. 3037c478bd9Sstevel@tonic-gate */ 3047c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(dip, DLD_CONTROL_MINOR_NAME, S_IFCHR, 3057c478bd9Sstevel@tonic-gate DLD_CONTROL_MINOR, DDI_PSEUDO, 0) != DDI_SUCCESS) 3067c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate dld_dip = dip; 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate /* 3117c478bd9Sstevel@tonic-gate * Log the fact that the driver is now attached. 3127c478bd9Sstevel@tonic-gate */ 3137c478bd9Sstevel@tonic-gate ddi_report_dev(dip); 3147c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3157c478bd9Sstevel@tonic-gate } 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate /* 3187c478bd9Sstevel@tonic-gate * devo_detach: detach(9e) 3197c478bd9Sstevel@tonic-gate */ 3207c478bd9Sstevel@tonic-gate static int 3217c478bd9Sstevel@tonic-gate drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3227c478bd9Sstevel@tonic-gate { 3237c478bd9Sstevel@tonic-gate if (cmd != DDI_DETACH) 3247c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate ASSERT(dld_dip == dip); 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate /* 3297c478bd9Sstevel@tonic-gate * Remove the control node. 3307c478bd9Sstevel@tonic-gate */ 3317c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, DLD_CONTROL_MINOR_NAME); 3327c478bd9Sstevel@tonic-gate dld_dip = NULL; 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate /* 338210db224Sericheng * dld control node open procedure. 3397c478bd9Sstevel@tonic-gate */ 3407c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3417c478bd9Sstevel@tonic-gate static int 3427c478bd9Sstevel@tonic-gate drv_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp) 3437c478bd9Sstevel@tonic-gate { 344210db224Sericheng dld_ctl_str_t *ctls; 3457c478bd9Sstevel@tonic-gate minor_t minor; 346210db224Sericheng queue_t *oq = OTHERQ(rq); 3477c478bd9Sstevel@tonic-gate 348210db224Sericheng if (sflag == MODOPEN) 349210db224Sericheng return (ENOTSUP); 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate /* 3527c478bd9Sstevel@tonic-gate * This is a cloning driver and therefore each queue should only 3537c478bd9Sstevel@tonic-gate * ever get opened once. 3547c478bd9Sstevel@tonic-gate */ 3557c478bd9Sstevel@tonic-gate if (rq->q_ptr != NULL) 3567c478bd9Sstevel@tonic-gate return (EBUSY); 3577c478bd9Sstevel@tonic-gate 358210db224Sericheng minor = (minor_t)(uintptr_t)vmem_alloc(dld_ctl_vmem, 1, VM_NOSLEEP); 359210db224Sericheng if (minor == 0) 360210db224Sericheng return (ENOMEM); 3617c478bd9Sstevel@tonic-gate 362210db224Sericheng ctls = kmem_zalloc(sizeof (dld_ctl_str_t), KM_NOSLEEP); 363210db224Sericheng if (ctls == NULL) { 364210db224Sericheng vmem_free(dld_ctl_vmem, (void *)(uintptr_t)minor, 1); 365210db224Sericheng return (ENOMEM); 366210db224Sericheng } 3677c478bd9Sstevel@tonic-gate 368210db224Sericheng ctls->cs_minor = minor; 369210db224Sericheng ctls->cs_wq = WR(rq); 3707c478bd9Sstevel@tonic-gate 371210db224Sericheng rq->q_ptr = ctls; 372210db224Sericheng oq->q_ptr = ctls; 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate /* 3757c478bd9Sstevel@tonic-gate * Enable the queue srv(9e) routine. 3767c478bd9Sstevel@tonic-gate */ 3777c478bd9Sstevel@tonic-gate qprocson(rq); 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate /* 3807c478bd9Sstevel@tonic-gate * Construct a cloned dev_t to hand back. 3817c478bd9Sstevel@tonic-gate */ 382210db224Sericheng *devp = makedevice(getmajor(*devp), ctls->cs_minor); 3837c478bd9Sstevel@tonic-gate return (0); 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate /* 387210db224Sericheng * dld control node close procedure. 3887c478bd9Sstevel@tonic-gate */ 3897c478bd9Sstevel@tonic-gate static int 3907c478bd9Sstevel@tonic-gate drv_close(queue_t *rq) 3917c478bd9Sstevel@tonic-gate { 392210db224Sericheng dld_ctl_str_t *ctls; 3937c478bd9Sstevel@tonic-gate 394210db224Sericheng ctls = rq->q_ptr; 395210db224Sericheng ASSERT(ctls != NULL); 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate /* 3987c478bd9Sstevel@tonic-gate * Disable the queue srv(9e) routine. 3997c478bd9Sstevel@tonic-gate */ 4007c478bd9Sstevel@tonic-gate qprocsoff(rq); 4017c478bd9Sstevel@tonic-gate 402210db224Sericheng vmem_free(dld_ctl_vmem, (void *)(uintptr_t)ctls->cs_minor, 1); 403210db224Sericheng 404210db224Sericheng kmem_free(ctls, sizeof (dld_ctl_str_t)); 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate return (0); 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate /* 410*d62bc4baSyz * DLDIOC_ATTR 4117c478bd9Sstevel@tonic-gate */ 4127c478bd9Sstevel@tonic-gate static void 413210db224Sericheng drv_ioc_attr(dld_ctl_str_t *ctls, mblk_t *mp) 4147c478bd9Sstevel@tonic-gate { 415*d62bc4baSyz dld_ioc_attr_t *diap; 416*d62bc4baSyz dls_dl_handle_t dlh; 417*d62bc4baSyz dls_vlan_t *dvp; 418*d62bc4baSyz int err; 419*d62bc4baSyz queue_t *q = ctls->cs_wq; 4207c478bd9Sstevel@tonic-gate 421210db224Sericheng if ((err = miocpullup(mp, sizeof (dld_ioc_attr_t))) != 0) 422210db224Sericheng goto failed; 4237c478bd9Sstevel@tonic-gate 424210db224Sericheng diap = (dld_ioc_attr_t *)mp->b_cont->b_rptr; 425210db224Sericheng 426*d62bc4baSyz if ((err = dls_devnet_hold_tmp(diap->dia_linkid, &dlh)) != 0) 427210db224Sericheng goto failed; 428210db224Sericheng 429*d62bc4baSyz if ((err = dls_vlan_hold(dls_devnet_mac(dlh), 430*d62bc4baSyz dls_devnet_vid(dlh), &dvp, B_FALSE, B_FALSE)) != 0) { 431*d62bc4baSyz dls_devnet_rele_tmp(dlh); 432*d62bc4baSyz goto failed; 433*d62bc4baSyz } 434210db224Sericheng 435*d62bc4baSyz diap->dia_max_sdu = dvp->dv_dlp->dl_mip->mi_sdu_max; 436210db224Sericheng dls_vlan_rele(dvp); 437*d62bc4baSyz dls_devnet_rele_tmp(dlh); 438*d62bc4baSyz 439210db224Sericheng miocack(q, mp, sizeof (dld_ioc_attr_t), 0); 440210db224Sericheng return; 441210db224Sericheng 442210db224Sericheng failed: 443210db224Sericheng ASSERT(err != 0); 444*d62bc4baSyz miocnak(q, mp, 0, err); 445*d62bc4baSyz } 446210db224Sericheng 447*d62bc4baSyz /* 448*d62bc4baSyz * DLDIOC_PHYS_ATTR 449*d62bc4baSyz */ 450*d62bc4baSyz static void 451*d62bc4baSyz drv_ioc_phys_attr(dld_ctl_str_t *ctls, mblk_t *mp) 452*d62bc4baSyz { 453*d62bc4baSyz dld_ioc_phys_attr_t *dipp; 454*d62bc4baSyz int err; 455*d62bc4baSyz dls_dl_handle_t dlh; 456*d62bc4baSyz dls_dev_handle_t ddh; 457*d62bc4baSyz dev_t phydev; 458*d62bc4baSyz queue_t *q = ctls->cs_wq; 459*d62bc4baSyz 460*d62bc4baSyz if ((err = miocpullup(mp, sizeof (dld_ioc_phys_attr_t))) != 0) 461*d62bc4baSyz goto failed; 462*d62bc4baSyz 463*d62bc4baSyz dipp = (dld_ioc_phys_attr_t *)mp->b_cont->b_rptr; 464*d62bc4baSyz 465*d62bc4baSyz /* 466*d62bc4baSyz * Every physical link should have its physical dev_t kept in the 467*d62bc4baSyz * daemon. If not, it is not a valid physical link. 468*d62bc4baSyz */ 469*d62bc4baSyz if (dls_mgmt_get_phydev(dipp->dip_linkid, &phydev) != 0) { 470*d62bc4baSyz err = EINVAL; 471*d62bc4baSyz goto failed; 472*d62bc4baSyz } 473*d62bc4baSyz 474*d62bc4baSyz /* 475*d62bc4baSyz * Although this is a valid physical link, it might already be removed 476*d62bc4baSyz * by DR or during system shutdown. softmac_hold_device() would return 477*d62bc4baSyz * ENOENT in this case. 478*d62bc4baSyz */ 479*d62bc4baSyz if ((err = softmac_hold_device(phydev, &ddh)) != 0) 480*d62bc4baSyz goto failed; 481*d62bc4baSyz 482*d62bc4baSyz if (dls_devnet_hold_tmp(dipp->dip_linkid, &dlh) != 0) { 483210db224Sericheng /* 484*d62bc4baSyz * Although this is an active physical link, its link type is 485*d62bc4baSyz * not supported by GLDv3, and therefore it does not have 486*d62bc4baSyz * vanity naming support. 487210db224Sericheng */ 488*d62bc4baSyz dipp->dip_novanity = B_TRUE; 489*d62bc4baSyz } else { 490*d62bc4baSyz dipp->dip_novanity = B_FALSE; 491*d62bc4baSyz dls_devnet_rele_tmp(dlh); 492210db224Sericheng } 493*d62bc4baSyz /* 494*d62bc4baSyz * Get the physical device name from the major number and the instance 495*d62bc4baSyz * number derived from phydev. 496*d62bc4baSyz */ 497*d62bc4baSyz (void) snprintf(dipp->dip_dev, MAXLINKNAMELEN, "%s%d", 498*d62bc4baSyz ddi_major_to_name(getmajor(phydev)), getminor(phydev) - 1); 499*d62bc4baSyz 500*d62bc4baSyz softmac_rele_device(ddh); 501*d62bc4baSyz 502*d62bc4baSyz miocack(q, mp, sizeof (dld_ioc_phys_attr_t), 0); 503*d62bc4baSyz return; 504*d62bc4baSyz 505*d62bc4baSyz failed: 506210db224Sericheng miocnak(q, mp, 0, err); 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate /* 510*d62bc4baSyz * DLDIOC_CREATE_VLAN 5117c478bd9Sstevel@tonic-gate */ 512*d62bc4baSyz static void 513*d62bc4baSyz drv_ioc_create_vlan(dld_ctl_str_t *ctls, mblk_t *mp) 514210db224Sericheng { 515*d62bc4baSyz dld_ioc_create_vlan_t *dicp; 516*d62bc4baSyz int err; 517*d62bc4baSyz queue_t *q = ctls->cs_wq; 518210db224Sericheng 519*d62bc4baSyz if ((err = miocpullup(mp, sizeof (dld_ioc_create_vlan_t))) != 0) 520*d62bc4baSyz goto failed; 521*d62bc4baSyz 522*d62bc4baSyz dicp = (dld_ioc_create_vlan_t *)mp->b_cont->b_rptr; 523*d62bc4baSyz 524*d62bc4baSyz if ((err = dls_devnet_create_vlan(dicp->dic_vlanid, 525*d62bc4baSyz dicp->dic_linkid, dicp->dic_vid, dicp->dic_force)) != 0) { 526*d62bc4baSyz goto failed; 527aae21359Skrgopi } 528*d62bc4baSyz 529*d62bc4baSyz miocack(q, mp, 0, 0); 530*d62bc4baSyz return; 531*d62bc4baSyz 532*d62bc4baSyz failed: 533*d62bc4baSyz miocnak(q, mp, 0, err); 534210db224Sericheng } 535210db224Sericheng 536*d62bc4baSyz /* 537*d62bc4baSyz * DLDIOC_DELETE_VLAN 538*d62bc4baSyz */ 5397c478bd9Sstevel@tonic-gate static void 540*d62bc4baSyz drv_ioc_delete_vlan(dld_ctl_str_t *ctls, mblk_t *mp) 5417c478bd9Sstevel@tonic-gate { 542*d62bc4baSyz dld_ioc_delete_vlan_t *didp; 543*d62bc4baSyz int err; 544210db224Sericheng queue_t *q = ctls->cs_wq; 5457c478bd9Sstevel@tonic-gate 546*d62bc4baSyz if ((err = miocpullup(mp, sizeof (dld_ioc_delete_vlan_t))) != 0) 547*d62bc4baSyz goto done; 5487c478bd9Sstevel@tonic-gate 549*d62bc4baSyz didp = (dld_ioc_delete_vlan_t *)mp->b_cont->b_rptr; 550*d62bc4baSyz err = dls_devnet_destroy_vlan(didp->did_linkid); 551*d62bc4baSyz 552*d62bc4baSyz done: 553*d62bc4baSyz if (err == 0) 554*d62bc4baSyz miocack(q, mp, 0, 0); 555*d62bc4baSyz else 556*d62bc4baSyz miocnak(q, mp, 0, err); 557*d62bc4baSyz } 558*d62bc4baSyz 559*d62bc4baSyz /* 560*d62bc4baSyz * DLDIOC_VLAN_ATTR 561*d62bc4baSyz */ 562*d62bc4baSyz static void 563*d62bc4baSyz drv_ioc_vlan_attr(dld_ctl_str_t *ctls, mblk_t *mp) 564*d62bc4baSyz { 565*d62bc4baSyz dld_ioc_vlan_attr_t *divp; 566*d62bc4baSyz dls_dl_handle_t dlh; 567*d62bc4baSyz uint16_t vid; 568*d62bc4baSyz dls_vlan_t *dvp; 569*d62bc4baSyz int err; 570*d62bc4baSyz queue_t *q = ctls->cs_wq; 571*d62bc4baSyz 572*d62bc4baSyz if ((err = miocpullup(mp, sizeof (dld_ioc_vlan_attr_t))) != 0) 573aae21359Skrgopi goto failed; 574aae21359Skrgopi 575*d62bc4baSyz divp = (dld_ioc_vlan_attr_t *)mp->b_cont->b_rptr; 5767c478bd9Sstevel@tonic-gate 577*d62bc4baSyz /* 578*d62bc4baSyz * Hold this link to prevent it from being deleted. 579*d62bc4baSyz */ 580*d62bc4baSyz err = dls_devnet_hold_tmp(divp->div_vlanid, &dlh); 581210db224Sericheng if (err != 0) 582210db224Sericheng goto failed; 583210db224Sericheng 584*d62bc4baSyz if ((vid = dls_devnet_vid(dlh)) == VLAN_ID_NONE) { 585*d62bc4baSyz dls_devnet_rele_tmp(dlh); 586*d62bc4baSyz err = EINVAL; 587*d62bc4baSyz goto failed; 588*d62bc4baSyz } 589*d62bc4baSyz 590*d62bc4baSyz err = dls_vlan_hold(dls_devnet_mac(dlh), vid, &dvp, B_FALSE, B_FALSE); 591*d62bc4baSyz if (err != 0) { 592*d62bc4baSyz dls_devnet_rele_tmp(dlh); 593*d62bc4baSyz err = EINVAL; 594*d62bc4baSyz goto failed; 595*d62bc4baSyz } 596*d62bc4baSyz 597*d62bc4baSyz divp->div_linkid = dls_devnet_linkid(dlh); 598*d62bc4baSyz divp->div_implicit = !dls_devnet_is_explicit(dlh); 599*d62bc4baSyz divp->div_vid = vid; 600*d62bc4baSyz divp->div_force = dvp->dv_force; 601*d62bc4baSyz 602*d62bc4baSyz dls_vlan_rele(dvp); 603*d62bc4baSyz dls_devnet_rele_tmp(dlh); 604*d62bc4baSyz miocack(q, mp, sizeof (dld_ioc_vlan_attr_t), 0); 605210db224Sericheng return; 606210db224Sericheng 607210db224Sericheng failed: 608210db224Sericheng miocnak(q, mp, 0, err); 609210db224Sericheng } 610210db224Sericheng 611f4b3ec61Sdh /* 612*d62bc4baSyz * DLDIOC_RENAME. 613*d62bc4baSyz * 614*d62bc4baSyz * This function handles two cases of link renaming. See more in comments above 615*d62bc4baSyz * dls_datalink_rename(). 616f4b3ec61Sdh */ 617f4b3ec61Sdh static void 618*d62bc4baSyz drv_ioc_rename(dld_ctl_str_t *ctls, mblk_t *mp) 619f4b3ec61Sdh { 620*d62bc4baSyz dld_ioc_rename_t *dir; 621*d62bc4baSyz mod_hash_key_t key; 622*d62bc4baSyz mod_hash_val_t val; 623*d62bc4baSyz int err; 624*d62bc4baSyz queue_t *q = ctls->cs_wq; 625*d62bc4baSyz 626*d62bc4baSyz if ((err = miocpullup(mp, sizeof (dld_ioc_rename_t))) != 0) 627*d62bc4baSyz goto done; 628*d62bc4baSyz 629*d62bc4baSyz dir = (dld_ioc_rename_t *)mp->b_cont->b_rptr; 630*d62bc4baSyz if ((err = dls_devnet_rename(dir->dir_linkid1, dir->dir_linkid2, 631*d62bc4baSyz dir->dir_link)) != 0) { 632*d62bc4baSyz goto done; 633*d62bc4baSyz } 634*d62bc4baSyz 635*d62bc4baSyz if (dir->dir_linkid2 == DATALINK_INVALID_LINKID) 636*d62bc4baSyz goto done; 637*d62bc4baSyz 638*d62bc4baSyz /* 639*d62bc4baSyz * if dir_linkid2 is not DATALINK_INVALID_LINKID, it means this 640*d62bc4baSyz * renaming request is to rename a valid physical link (dir_linkid1) 641*d62bc4baSyz * to a "removed" physical link (dir_linkid2, which is removed by DR 642*d62bc4baSyz * or during system shutdown). In this case, the link (specified by 643*d62bc4baSyz * dir_linkid1) would inherit all the configuration of dir_linkid2, 644*d62bc4baSyz * and dir_linkid1 and its configuration would be lost. 645*d62bc4baSyz * 646*d62bc4baSyz * Remove per-link autopush configuration of dir_linkid1 in this case. 647*d62bc4baSyz */ 648*d62bc4baSyz key = (mod_hash_key_t)(uintptr_t)dir->dir_linkid1; 649*d62bc4baSyz rw_enter(&dld_ap_hash_lock, RW_WRITER); 650*d62bc4baSyz if (mod_hash_find(dld_ap_hashp, key, &val) != 0) { 651*d62bc4baSyz rw_exit(&dld_ap_hash_lock); 652*d62bc4baSyz goto done; 653*d62bc4baSyz } 654*d62bc4baSyz 655*d62bc4baSyz VERIFY(mod_hash_remove(dld_ap_hashp, key, &val) == 0); 656*d62bc4baSyz kmem_free(val, sizeof (dld_ap_t)); 657*d62bc4baSyz rw_exit(&dld_ap_hash_lock); 658*d62bc4baSyz 659*d62bc4baSyz done: 660*d62bc4baSyz if (err == 0) 661*d62bc4baSyz miocack(q, mp, 0, 0); 662*d62bc4baSyz else 663*d62bc4baSyz miocnak(q, mp, 0, err); 664*d62bc4baSyz } 665*d62bc4baSyz 666*d62bc4baSyz /* 667*d62bc4baSyz * DLDIOC_SETAUTOPUSH 668*d62bc4baSyz */ 669*d62bc4baSyz static void 670*d62bc4baSyz drv_ioc_setap(dld_ctl_str_t *ctls, mblk_t *mp) 671*d62bc4baSyz { 672*d62bc4baSyz dld_ioc_ap_t *diap; 673*d62bc4baSyz dld_ap_t *dap; 674*d62bc4baSyz int i, err; 675f4b3ec61Sdh queue_t *q = ctls->cs_wq; 676*d62bc4baSyz mod_hash_key_t key; 677*d62bc4baSyz 678*d62bc4baSyz if ((err = miocpullup(mp, sizeof (dld_ioc_ap_t))) != 0) 679789e0dbbSdh goto failed; 680789e0dbbSdh 681*d62bc4baSyz diap = (dld_ioc_ap_t *)mp->b_cont->b_rptr; 682*d62bc4baSyz if (diap->dia_npush == 0 || diap->dia_npush > MAXAPUSH) { 683*d62bc4baSyz err = EINVAL; 684*d62bc4baSyz goto failed; 685*d62bc4baSyz } 686f4b3ec61Sdh 687789e0dbbSdh /* 688*d62bc4baSyz * Validate that the specified list of modules exist. 689789e0dbbSdh */ 690*d62bc4baSyz for (i = 0; i < diap->dia_npush; i++) { 691*d62bc4baSyz if (fmodsw_find(diap->dia_aplist[i], FMODSW_LOAD) == NULL) { 692*d62bc4baSyz err = EINVAL; 693*d62bc4baSyz goto failed; 694*d62bc4baSyz } 695*d62bc4baSyz } 696*d62bc4baSyz 697*d62bc4baSyz key = (mod_hash_key_t)(uintptr_t)diap->dia_linkid; 698789e0dbbSdh 699*d62bc4baSyz rw_enter(&dld_ap_hash_lock, RW_WRITER); 700*d62bc4baSyz if (mod_hash_find(dld_ap_hashp, key, (mod_hash_val_t *)&dap) != 0) { 701*d62bc4baSyz dap = kmem_zalloc(sizeof (dld_ap_t), KM_NOSLEEP); 702*d62bc4baSyz if (dap == NULL) { 703*d62bc4baSyz rw_exit(&dld_ap_hash_lock); 704*d62bc4baSyz err = ENOMEM; 705789e0dbbSdh goto failed; 706*d62bc4baSyz } 707*d62bc4baSyz 708*d62bc4baSyz dap->da_linkid = diap->dia_linkid; 709*d62bc4baSyz err = mod_hash_insert(dld_ap_hashp, key, (mod_hash_val_t)dap); 710*d62bc4baSyz ASSERT(err == 0); 711f4b3ec61Sdh } 712f4b3ec61Sdh 713*d62bc4baSyz /* 714*d62bc4baSyz * Update the configuration. 715*d62bc4baSyz */ 716*d62bc4baSyz dap->da_anchor = diap->dia_anchor; 717*d62bc4baSyz dap->da_npush = diap->dia_npush; 718*d62bc4baSyz for (i = 0; i < diap->dia_npush; i++) { 719*d62bc4baSyz (void) strlcpy(dap->da_aplist[i], diap->dia_aplist[i], 720*d62bc4baSyz FMNAMESZ + 1); 721*d62bc4baSyz } 722*d62bc4baSyz rw_exit(&dld_ap_hash_lock); 723789e0dbbSdh 724*d62bc4baSyz miocack(q, mp, 0, 0); 725*d62bc4baSyz return; 726*d62bc4baSyz 727*d62bc4baSyz failed: 728*d62bc4baSyz miocnak(q, mp, 0, err); 729*d62bc4baSyz } 730*d62bc4baSyz 731*d62bc4baSyz /* 732*d62bc4baSyz * DLDIOC_GETAUTOPUSH 733*d62bc4baSyz */ 734*d62bc4baSyz static void 735*d62bc4baSyz drv_ioc_getap(dld_ctl_str_t *ctls, mblk_t *mp) 736*d62bc4baSyz { 737*d62bc4baSyz dld_ioc_ap_t *diap; 738*d62bc4baSyz dld_ap_t *dap; 739*d62bc4baSyz int i, err; 740*d62bc4baSyz queue_t *q = ctls->cs_wq; 741*d62bc4baSyz 742*d62bc4baSyz if ((err = miocpullup(mp, sizeof (dld_ioc_ap_t))) != 0) 743789e0dbbSdh goto failed; 744789e0dbbSdh 745*d62bc4baSyz diap = (dld_ioc_ap_t *)mp->b_cont->b_rptr; 746*d62bc4baSyz 747*d62bc4baSyz rw_enter(&dld_ap_hash_lock, RW_READER); 748*d62bc4baSyz if (mod_hash_find(dld_ap_hashp, 749*d62bc4baSyz (mod_hash_key_t)(uintptr_t)diap->dia_linkid, 750*d62bc4baSyz (mod_hash_val_t *)&dap) != 0) { 751*d62bc4baSyz err = ENOENT; 752*d62bc4baSyz rw_exit(&dld_ap_hash_lock); 753789e0dbbSdh goto failed; 754f595a68aSyz } 755*d62bc4baSyz 756*d62bc4baSyz /* 757*d62bc4baSyz * Retrieve the configuration. 758*d62bc4baSyz */ 759*d62bc4baSyz diap->dia_anchor = dap->da_anchor; 760*d62bc4baSyz diap->dia_npush = dap->da_npush; 761*d62bc4baSyz for (i = 0; i < dap->da_npush; i++) { 762*d62bc4baSyz (void) strlcpy(diap->dia_aplist[i], dap->da_aplist[i], 763*d62bc4baSyz FMNAMESZ + 1); 764*d62bc4baSyz } 765*d62bc4baSyz rw_exit(&dld_ap_hash_lock); 766*d62bc4baSyz 767*d62bc4baSyz miocack(q, mp, sizeof (dld_ioc_ap_t), 0); 768*d62bc4baSyz return; 769*d62bc4baSyz 770789e0dbbSdh failed: 771789e0dbbSdh miocnak(q, mp, 0, err); 772f4b3ec61Sdh } 773f4b3ec61Sdh 774f4b3ec61Sdh /* 775*d62bc4baSyz * DLDIOC_CLRAUTOPUSH 776f4b3ec61Sdh */ 777f4b3ec61Sdh static void 778*d62bc4baSyz drv_ioc_clrap(dld_ctl_str_t *ctls, mblk_t *mp) 779f4b3ec61Sdh { 780*d62bc4baSyz dld_ioc_ap_t *diap; 781*d62bc4baSyz mod_hash_val_t val; 782*d62bc4baSyz mod_hash_key_t key; 783f4b3ec61Sdh int err; 784*d62bc4baSyz queue_t *q = ctls->cs_wq; 785f4b3ec61Sdh 786*d62bc4baSyz if ((err = miocpullup(mp, sizeof (dld_ioc_ap_t))) != 0) 787*d62bc4baSyz goto done; 788f4b3ec61Sdh 789*d62bc4baSyz diap = (dld_ioc_ap_t *)mp->b_cont->b_rptr; 790*d62bc4baSyz key = (mod_hash_key_t)(uintptr_t)diap->dia_linkid; 791f4b3ec61Sdh 792*d62bc4baSyz rw_enter(&dld_ap_hash_lock, RW_WRITER); 793*d62bc4baSyz if (mod_hash_find(dld_ap_hashp, key, &val) != 0) { 794*d62bc4baSyz rw_exit(&dld_ap_hash_lock); 795*d62bc4baSyz goto done; 796f4b3ec61Sdh } 797f4b3ec61Sdh 798*d62bc4baSyz VERIFY(mod_hash_remove(dld_ap_hashp, key, &val) == 0); 799*d62bc4baSyz kmem_free(val, sizeof (dld_ap_t)); 800*d62bc4baSyz rw_exit(&dld_ap_hash_lock); 801*d62bc4baSyz 802*d62bc4baSyz done: 803*d62bc4baSyz if (err == 0) 804*d62bc4baSyz miocack(q, mp, 0, 0); 805*d62bc4baSyz else 806*d62bc4baSyz miocnak(q, mp, 0, err); 807f4b3ec61Sdh } 808f4b3ec61Sdh 809f4b3ec61Sdh /* 810*d62bc4baSyz * DLDIOC_DOORSERVER 811f4b3ec61Sdh */ 812f4b3ec61Sdh static void 813*d62bc4baSyz drv_ioc_doorserver(dld_ctl_str_t *ctls, mblk_t *mp) 814f4b3ec61Sdh { 815f4b3ec61Sdh queue_t *q = ctls->cs_wq; 816*d62bc4baSyz dld_ioc_door_t *did; 817f4b3ec61Sdh int err; 818f4b3ec61Sdh 819*d62bc4baSyz if ((err = miocpullup(mp, sizeof (dld_ioc_door_t))) != 0) 820*d62bc4baSyz goto done; 821*d62bc4baSyz 822*d62bc4baSyz did = (dld_ioc_door_t *)mp->b_cont->b_rptr; 823*d62bc4baSyz err = dls_mgmt_door_set(did->did_start_door); 824*d62bc4baSyz 825*d62bc4baSyz done: 826*d62bc4baSyz if (err == 0) 827*d62bc4baSyz miocack(q, mp, 0, 0); 828*d62bc4baSyz else 829f4b3ec61Sdh miocnak(q, mp, 0, err); 830*d62bc4baSyz } 831*d62bc4baSyz 832*d62bc4baSyz /* 833*d62bc4baSyz * DLDIOC_SETZID 834*d62bc4baSyz */ 835*d62bc4baSyz static void 836*d62bc4baSyz drv_ioc_setzid(dld_ctl_str_t *ctls, mblk_t *mp) 837*d62bc4baSyz { 838*d62bc4baSyz queue_t *q = ctls->cs_wq; 839*d62bc4baSyz dld_ioc_setzid_t *dis; 840*d62bc4baSyz int err; 841*d62bc4baSyz 842*d62bc4baSyz if ((err = miocpullup(mp, sizeof (dld_ioc_setzid_t))) != 0) 843*d62bc4baSyz goto done; 844f4b3ec61Sdh 845*d62bc4baSyz dis = (dld_ioc_setzid_t *)mp->b_cont->b_rptr; 846*d62bc4baSyz err = dls_devnet_setzid(dis->dis_link, dis->dis_zid); 847*d62bc4baSyz 848*d62bc4baSyz done: 849*d62bc4baSyz if (err == 0) 850*d62bc4baSyz miocack(q, mp, 0, 0); 851*d62bc4baSyz else 852f4b3ec61Sdh miocnak(q, mp, 0, err); 853*d62bc4baSyz } 854*d62bc4baSyz 855*d62bc4baSyz /* 856*d62bc4baSyz * DLDIOC_GETZID 857*d62bc4baSyz */ 858*d62bc4baSyz static void 859*d62bc4baSyz drv_ioc_getzid(dld_ctl_str_t *ctls, mblk_t *mp) 860*d62bc4baSyz { 861*d62bc4baSyz queue_t *q = ctls->cs_wq; 862*d62bc4baSyz dld_ioc_getzid_t *dig; 863*d62bc4baSyz int err; 864*d62bc4baSyz 865*d62bc4baSyz if ((err = miocpullup(mp, sizeof (dld_ioc_getzid_t))) != 0) 866*d62bc4baSyz goto done; 867*d62bc4baSyz 868*d62bc4baSyz dig = (dld_ioc_getzid_t *)mp->b_cont->b_rptr; 869*d62bc4baSyz err = dls_devnet_getzid(dig->dig_linkid, &dig->dig_zid); 870*d62bc4baSyz 871*d62bc4baSyz done: 872*d62bc4baSyz if (err == 0) 873*d62bc4baSyz miocack(q, mp, sizeof (dld_ioc_getzid_t), 0); 874f4b3ec61Sdh else 875*d62bc4baSyz miocnak(q, mp, 0, err); 876f4b3ec61Sdh } 877210db224Sericheng 878210db224Sericheng /* 879210db224Sericheng * Process an IOCTL message received by the control node. 880210db224Sericheng */ 881210db224Sericheng static void 882210db224Sericheng drv_ioc(dld_ctl_str_t *ctls, mblk_t *mp) 883210db224Sericheng { 884210db224Sericheng uint_t cmd; 885210db224Sericheng 886210db224Sericheng cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd; 887210db224Sericheng switch (cmd) { 888*d62bc4baSyz case DLDIOC_ATTR: 889210db224Sericheng drv_ioc_attr(ctls, mp); 890210db224Sericheng return; 891*d62bc4baSyz case DLDIOC_PHYS_ATTR: 892*d62bc4baSyz drv_ioc_phys_attr(ctls, mp); 8937c478bd9Sstevel@tonic-gate return; 894*d62bc4baSyz case DLDIOC_SECOBJ_SET: 8950ba2cbe9Sxc drv_ioc_secobj_set(ctls, mp); 8960ba2cbe9Sxc return; 897*d62bc4baSyz case DLDIOC_SECOBJ_GET: 8980ba2cbe9Sxc drv_ioc_secobj_get(ctls, mp); 8990ba2cbe9Sxc return; 900*d62bc4baSyz case DLDIOC_SECOBJ_UNSET: 9010ba2cbe9Sxc drv_ioc_secobj_unset(ctls, mp); 9020ba2cbe9Sxc return; 903*d62bc4baSyz case DLDIOC_CREATE_VLAN: 904*d62bc4baSyz drv_ioc_create_vlan(ctls, mp); 905*d62bc4baSyz return; 906*d62bc4baSyz case DLDIOC_DELETE_VLAN: 907*d62bc4baSyz drv_ioc_delete_vlan(ctls, mp); 908*d62bc4baSyz return; 909*d62bc4baSyz case DLDIOC_VLAN_ATTR: 910*d62bc4baSyz drv_ioc_vlan_attr(ctls, mp); 911*d62bc4baSyz return; 912*d62bc4baSyz case DLDIOC_SETAUTOPUSH: 913*d62bc4baSyz drv_ioc_setap(ctls, mp); 914*d62bc4baSyz return; 915*d62bc4baSyz case DLDIOC_GETAUTOPUSH: 916*d62bc4baSyz drv_ioc_getap(ctls, mp); 917*d62bc4baSyz return; 918*d62bc4baSyz case DLDIOC_CLRAUTOPUSH: 919*d62bc4baSyz drv_ioc_clrap(ctls, mp); 920f4b3ec61Sdh return; 921*d62bc4baSyz case DLDIOC_DOORSERVER: 922*d62bc4baSyz drv_ioc_doorserver(ctls, mp); 923f4b3ec61Sdh return; 924*d62bc4baSyz case DLDIOC_SETZID: 925*d62bc4baSyz drv_ioc_setzid(ctls, mp); 926*d62bc4baSyz return; 927*d62bc4baSyz case DLDIOC_GETZID: 928*d62bc4baSyz drv_ioc_getzid(ctls, mp); 929*d62bc4baSyz return; 930*d62bc4baSyz case DLDIOC_RENAME: 931*d62bc4baSyz drv_ioc_rename(ctls, mp); 932f4b3ec61Sdh return; 933210db224Sericheng default: 934210db224Sericheng miocnak(ctls->cs_wq, mp, 0, ENOTSUP); 935210db224Sericheng return; 936210db224Sericheng } 937210db224Sericheng } 9387c478bd9Sstevel@tonic-gate 939210db224Sericheng /* 940210db224Sericheng * Write side put routine of the dld control node. 941210db224Sericheng */ 942210db224Sericheng static void 943210db224Sericheng drv_uw_put(queue_t *q, mblk_t *mp) 944210db224Sericheng { 945210db224Sericheng dld_ctl_str_t *ctls = q->q_ptr; 946210db224Sericheng 947210db224Sericheng switch (mp->b_datap->db_type) { 948210db224Sericheng case M_IOCTL: 949210db224Sericheng drv_ioc(ctls, mp); 950210db224Sericheng break; 951210db224Sericheng default: 952210db224Sericheng freemsg(mp); 953210db224Sericheng break; 954210db224Sericheng } 955210db224Sericheng } 956210db224Sericheng 957210db224Sericheng /* 958210db224Sericheng * Write-side service procedure. 959210db224Sericheng */ 960210db224Sericheng void 961210db224Sericheng drv_uw_srv(queue_t *q) 962210db224Sericheng { 963210db224Sericheng mblk_t *mp; 964210db224Sericheng 965210db224Sericheng while (mp = getq(q)) 966210db224Sericheng drv_uw_put(q, mp); 9677c478bd9Sstevel@tonic-gate } 9680ba2cbe9Sxc 969*d62bc4baSyz /* 970*d62bc4baSyz * Check for GLDv3 autopush information. There are three cases: 971*d62bc4baSyz * 972*d62bc4baSyz * 1. If devp points to a GLDv3 datalink and it has autopush configuration, 973*d62bc4baSyz * fill dlap in with that information and return 0. 974*d62bc4baSyz * 975*d62bc4baSyz * 2. If devp points to a GLDv3 datalink but it doesn't have autopush 976*d62bc4baSyz * configuration, then replace devp with the physical device (if one 977*d62bc4baSyz * exists) and return 1. This allows stropen() to find the old-school 978*d62bc4baSyz * per-driver autopush configuration. (For softmac, the result is that 979*d62bc4baSyz * the softmac dev_t is replaced with the legacy device's dev_t). 980*d62bc4baSyz * 981*d62bc4baSyz * 3. If neither of the above apply, don't touch the args and return -1. 982*d62bc4baSyz */ 983*d62bc4baSyz int 984*d62bc4baSyz dld_autopush(dev_t *devp, struct dlautopush *dlap) 985*d62bc4baSyz { 986*d62bc4baSyz dld_ap_t *dap; 987*d62bc4baSyz datalink_id_t linkid; 988*d62bc4baSyz dev_t phydev; 989*d62bc4baSyz 990*d62bc4baSyz if (!GLDV3_DRV(getmajor(*devp))) 991*d62bc4baSyz return (-1); 992*d62bc4baSyz 993*d62bc4baSyz /* 994*d62bc4baSyz * Find the linkid by the link's dev_t. 995*d62bc4baSyz */ 996*d62bc4baSyz if (dls_devnet_dev2linkid(*devp, &linkid) != 0) 997*d62bc4baSyz return (-1); 998*d62bc4baSyz 999*d62bc4baSyz /* 1000*d62bc4baSyz * Find the autopush configuration associated with the linkid. 1001*d62bc4baSyz */ 1002*d62bc4baSyz rw_enter(&dld_ap_hash_lock, RW_READER); 1003*d62bc4baSyz if (mod_hash_find(dld_ap_hashp, (mod_hash_key_t)(uintptr_t)linkid, 1004*d62bc4baSyz (mod_hash_val_t *)&dap) == 0) { 1005*d62bc4baSyz *dlap = dap->da_ap; 1006*d62bc4baSyz rw_exit(&dld_ap_hash_lock); 1007*d62bc4baSyz return (0); 1008*d62bc4baSyz } 1009*d62bc4baSyz rw_exit(&dld_ap_hash_lock); 1010*d62bc4baSyz 1011*d62bc4baSyz if (dls_devnet_phydev(linkid, &phydev) != 0) 1012*d62bc4baSyz return (-1); 1013*d62bc4baSyz 1014*d62bc4baSyz *devp = phydev; 1015*d62bc4baSyz return (1); 1016*d62bc4baSyz } 1017*d62bc4baSyz 10180ba2cbe9Sxc /* 10190ba2cbe9Sxc * Secure objects implementation 10200ba2cbe9Sxc */ 10210ba2cbe9Sxc 10220ba2cbe9Sxc /* ARGSUSED */ 10230ba2cbe9Sxc static int 10240ba2cbe9Sxc drv_secobj_ctor(void *buf, void *arg, int kmflag) 10250ba2cbe9Sxc { 10260ba2cbe9Sxc bzero(buf, sizeof (dld_secobj_t)); 10270ba2cbe9Sxc return (0); 10280ba2cbe9Sxc } 10290ba2cbe9Sxc 10300ba2cbe9Sxc static void 10310ba2cbe9Sxc drv_secobj_init(void) 10320ba2cbe9Sxc { 10330ba2cbe9Sxc rw_init(&drv_secobj_lock, NULL, RW_DEFAULT, NULL); 10340ba2cbe9Sxc drv_secobj_cachep = kmem_cache_create("drv_secobj_cache", 10350ba2cbe9Sxc sizeof (dld_secobj_t), 0, drv_secobj_ctor, NULL, 10360ba2cbe9Sxc NULL, NULL, NULL, 0); 10370ba2cbe9Sxc drv_secobj_hash = mod_hash_create_extended("drv_secobj_hash", 10380ba2cbe9Sxc SECOBJ_WEP_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, 10390ba2cbe9Sxc mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 10400ba2cbe9Sxc } 10410ba2cbe9Sxc 10420ba2cbe9Sxc static void 10430ba2cbe9Sxc drv_secobj_fini(void) 10440ba2cbe9Sxc { 10450ba2cbe9Sxc mod_hash_destroy_hash(drv_secobj_hash); 10460ba2cbe9Sxc kmem_cache_destroy(drv_secobj_cachep); 10470ba2cbe9Sxc rw_destroy(&drv_secobj_lock); 10480ba2cbe9Sxc } 10490ba2cbe9Sxc 10500ba2cbe9Sxc static void 10510ba2cbe9Sxc drv_ioc_secobj_set(dld_ctl_str_t *ctls, mblk_t *mp) 10520ba2cbe9Sxc { 10530ba2cbe9Sxc dld_ioc_secobj_set_t *ssp; 10540ba2cbe9Sxc dld_secobj_t *sobjp, *objp; 10550ba2cbe9Sxc int err = EINVAL; 10560ba2cbe9Sxc queue_t *q = ctls->cs_wq; 10570ba2cbe9Sxc 10580ba2cbe9Sxc if ((err = miocpullup(mp, sizeof (dld_ioc_secobj_set_t))) != 0) 10590ba2cbe9Sxc goto failed; 10600ba2cbe9Sxc 10610ba2cbe9Sxc ssp = (dld_ioc_secobj_set_t *)mp->b_cont->b_rptr; 10620ba2cbe9Sxc sobjp = &ssp->ss_obj; 10630ba2cbe9Sxc 1064a399b765Szf if (sobjp->so_class != DLD_SECOBJ_CLASS_WEP && 1065a399b765Szf sobjp->so_class != DLD_SECOBJ_CLASS_WPA) 10660ba2cbe9Sxc goto failed; 10670ba2cbe9Sxc 10680ba2cbe9Sxc if (sobjp->so_name[DLD_SECOBJ_NAME_MAX - 1] != '\0' || 10690ba2cbe9Sxc sobjp->so_len > DLD_SECOBJ_VAL_MAX) 10700ba2cbe9Sxc goto failed; 10710ba2cbe9Sxc 10720ba2cbe9Sxc rw_enter(&drv_secobj_lock, RW_WRITER); 10730ba2cbe9Sxc err = mod_hash_find(drv_secobj_hash, (mod_hash_key_t)sobjp->so_name, 10740ba2cbe9Sxc (mod_hash_val_t *)&objp); 10750ba2cbe9Sxc if (err == 0) { 10760ba2cbe9Sxc if ((ssp->ss_flags & DLD_SECOBJ_OPT_CREATE) != 0) { 10770ba2cbe9Sxc err = EEXIST; 10780ba2cbe9Sxc rw_exit(&drv_secobj_lock); 10790ba2cbe9Sxc goto failed; 10800ba2cbe9Sxc } 10810ba2cbe9Sxc } else { 10820ba2cbe9Sxc ASSERT(err == MH_ERR_NOTFOUND); 10830ba2cbe9Sxc if ((ssp->ss_flags & DLD_SECOBJ_OPT_CREATE) == 0) { 10840ba2cbe9Sxc err = ENOENT; 10850ba2cbe9Sxc rw_exit(&drv_secobj_lock); 10860ba2cbe9Sxc goto failed; 10870ba2cbe9Sxc } 10880ba2cbe9Sxc objp = kmem_cache_alloc(drv_secobj_cachep, KM_SLEEP); 10890ba2cbe9Sxc (void) strlcpy(objp->so_name, sobjp->so_name, 10900ba2cbe9Sxc DLD_SECOBJ_NAME_MAX); 10910ba2cbe9Sxc 10920ba2cbe9Sxc err = mod_hash_insert(drv_secobj_hash, 10930ba2cbe9Sxc (mod_hash_key_t)objp->so_name, (mod_hash_val_t)objp); 10940ba2cbe9Sxc ASSERT(err == 0); 10950ba2cbe9Sxc } 10960ba2cbe9Sxc bcopy(sobjp->so_val, objp->so_val, sobjp->so_len); 10970ba2cbe9Sxc objp->so_len = sobjp->so_len; 10980ba2cbe9Sxc objp->so_class = sobjp->so_class; 10990ba2cbe9Sxc rw_exit(&drv_secobj_lock); 11000ba2cbe9Sxc miocack(q, mp, 0, 0); 11010ba2cbe9Sxc return; 11020ba2cbe9Sxc 11030ba2cbe9Sxc failed: 11040ba2cbe9Sxc ASSERT(err != 0); 11050ba2cbe9Sxc miocnak(q, mp, 0, err); 11060ba2cbe9Sxc } 11070ba2cbe9Sxc 11080ba2cbe9Sxc typedef struct dld_secobj_state { 11090ba2cbe9Sxc uint_t ss_free; 11100ba2cbe9Sxc uint_t ss_count; 11110ba2cbe9Sxc int ss_rc; 11120ba2cbe9Sxc dld_secobj_t *ss_objp; 11130ba2cbe9Sxc } dld_secobj_state_t; 11140ba2cbe9Sxc 11150ba2cbe9Sxc /* ARGSUSED */ 11160ba2cbe9Sxc static uint_t 11170ba2cbe9Sxc drv_secobj_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 11180ba2cbe9Sxc { 11190ba2cbe9Sxc dld_secobj_state_t *statep = arg; 11200ba2cbe9Sxc dld_secobj_t *sobjp = (dld_secobj_t *)val; 11210ba2cbe9Sxc 11220ba2cbe9Sxc if (statep->ss_free < sizeof (dld_secobj_t)) { 11230ba2cbe9Sxc statep->ss_rc = ENOSPC; 11240ba2cbe9Sxc return (MH_WALK_TERMINATE); 11250ba2cbe9Sxc } 11260ba2cbe9Sxc bcopy(sobjp, statep->ss_objp, sizeof (dld_secobj_t)); 11270ba2cbe9Sxc statep->ss_objp++; 11280ba2cbe9Sxc statep->ss_free -= sizeof (dld_secobj_t); 11290ba2cbe9Sxc statep->ss_count++; 11300ba2cbe9Sxc return (MH_WALK_CONTINUE); 11310ba2cbe9Sxc } 11320ba2cbe9Sxc 11330ba2cbe9Sxc static void 11340ba2cbe9Sxc drv_ioc_secobj_get(dld_ctl_str_t *ctls, mblk_t *mp) 11350ba2cbe9Sxc { 11360ba2cbe9Sxc dld_ioc_secobj_get_t *sgp; 11370ba2cbe9Sxc dld_secobj_t *sobjp, *objp; 11380ba2cbe9Sxc int err = EINVAL; 11390ba2cbe9Sxc uint_t extra = 0; 11400ba2cbe9Sxc queue_t *q = ctls->cs_wq; 11410ba2cbe9Sxc mblk_t *bp; 11420ba2cbe9Sxc 11430ba2cbe9Sxc if ((err = miocpullup(mp, sizeof (dld_ioc_secobj_get_t))) != 0) 11440ba2cbe9Sxc goto failed; 11450ba2cbe9Sxc 11460ba2cbe9Sxc if ((bp = msgpullup(mp->b_cont, -1)) == NULL) 11470ba2cbe9Sxc goto failed; 11480ba2cbe9Sxc 11490ba2cbe9Sxc freemsg(mp->b_cont); 11500ba2cbe9Sxc mp->b_cont = bp; 11510ba2cbe9Sxc sgp = (dld_ioc_secobj_get_t *)bp->b_rptr; 11520ba2cbe9Sxc sobjp = &sgp->sg_obj; 11530ba2cbe9Sxc 11540ba2cbe9Sxc if (sobjp->so_name[DLD_SECOBJ_NAME_MAX - 1] != '\0') 11550ba2cbe9Sxc goto failed; 11560ba2cbe9Sxc 11570ba2cbe9Sxc rw_enter(&drv_secobj_lock, RW_READER); 11580ba2cbe9Sxc if (sobjp->so_name[0] != '\0') { 11590ba2cbe9Sxc err = mod_hash_find(drv_secobj_hash, 11600ba2cbe9Sxc (mod_hash_key_t)sobjp->so_name, (mod_hash_val_t *)&objp); 11610ba2cbe9Sxc if (err != 0) { 11620ba2cbe9Sxc ASSERT(err == MH_ERR_NOTFOUND); 11630ba2cbe9Sxc err = ENOENT; 11640ba2cbe9Sxc rw_exit(&drv_secobj_lock); 11650ba2cbe9Sxc goto failed; 11660ba2cbe9Sxc } 11670ba2cbe9Sxc bcopy(objp->so_val, sobjp->so_val, objp->so_len); 11680ba2cbe9Sxc sobjp->so_len = objp->so_len; 11690ba2cbe9Sxc sobjp->so_class = objp->so_class; 11700ba2cbe9Sxc sgp->sg_count = 1; 11710ba2cbe9Sxc } else { 11720ba2cbe9Sxc dld_secobj_state_t state; 11730ba2cbe9Sxc 11740ba2cbe9Sxc state.ss_free = MBLKL(bp) - sizeof (dld_ioc_secobj_get_t); 11750ba2cbe9Sxc state.ss_count = 0; 11760ba2cbe9Sxc state.ss_rc = 0; 11770ba2cbe9Sxc state.ss_objp = (dld_secobj_t *)(sgp + 1); 11780ba2cbe9Sxc mod_hash_walk(drv_secobj_hash, drv_secobj_walker, &state); 11790ba2cbe9Sxc if (state.ss_rc != 0) { 11800ba2cbe9Sxc err = state.ss_rc; 11810ba2cbe9Sxc rw_exit(&drv_secobj_lock); 11820ba2cbe9Sxc goto failed; 11830ba2cbe9Sxc } 11840ba2cbe9Sxc sgp->sg_count = state.ss_count; 11850ba2cbe9Sxc extra = state.ss_count * sizeof (dld_secobj_t); 11860ba2cbe9Sxc } 11870ba2cbe9Sxc rw_exit(&drv_secobj_lock); 11880ba2cbe9Sxc miocack(q, mp, sizeof (dld_ioc_secobj_get_t) + extra, 0); 11890ba2cbe9Sxc return; 11900ba2cbe9Sxc 11910ba2cbe9Sxc failed: 11920ba2cbe9Sxc ASSERT(err != 0); 11930ba2cbe9Sxc miocnak(q, mp, 0, err); 11940ba2cbe9Sxc 11950ba2cbe9Sxc } 11960ba2cbe9Sxc 11970ba2cbe9Sxc static void 11980ba2cbe9Sxc drv_ioc_secobj_unset(dld_ctl_str_t *ctls, mblk_t *mp) 11990ba2cbe9Sxc { 12000ba2cbe9Sxc dld_ioc_secobj_unset_t *sup; 12010ba2cbe9Sxc dld_secobj_t *objp; 12020ba2cbe9Sxc mod_hash_val_t val; 12030ba2cbe9Sxc int err = EINVAL; 12040ba2cbe9Sxc queue_t *q = ctls->cs_wq; 12050ba2cbe9Sxc 12060ba2cbe9Sxc if ((err = miocpullup(mp, sizeof (dld_ioc_secobj_unset_t))) != 0) 12070ba2cbe9Sxc goto failed; 12080ba2cbe9Sxc 12090ba2cbe9Sxc sup = (dld_ioc_secobj_unset_t *)mp->b_cont->b_rptr; 12100ba2cbe9Sxc if (sup->su_name[DLD_SECOBJ_NAME_MAX - 1] != '\0') 12110ba2cbe9Sxc goto failed; 12120ba2cbe9Sxc 12130ba2cbe9Sxc rw_enter(&drv_secobj_lock, RW_WRITER); 12140ba2cbe9Sxc err = mod_hash_find(drv_secobj_hash, (mod_hash_key_t)sup->su_name, 12150ba2cbe9Sxc (mod_hash_val_t *)&objp); 12160ba2cbe9Sxc if (err != 0) { 12170ba2cbe9Sxc ASSERT(err == MH_ERR_NOTFOUND); 12180ba2cbe9Sxc err = ENOENT; 12190ba2cbe9Sxc rw_exit(&drv_secobj_lock); 12200ba2cbe9Sxc goto failed; 12210ba2cbe9Sxc } 12220ba2cbe9Sxc err = mod_hash_remove(drv_secobj_hash, (mod_hash_key_t)sup->su_name, 12230ba2cbe9Sxc (mod_hash_val_t *)&val); 12240ba2cbe9Sxc ASSERT(err == 0); 12250ba2cbe9Sxc ASSERT(objp == (dld_secobj_t *)val); 12260ba2cbe9Sxc 12270ba2cbe9Sxc kmem_cache_free(drv_secobj_cachep, objp); 12280ba2cbe9Sxc rw_exit(&drv_secobj_lock); 12290ba2cbe9Sxc miocack(q, mp, 0, 0); 12300ba2cbe9Sxc return; 12310ba2cbe9Sxc 12320ba2cbe9Sxc failed: 12330ba2cbe9Sxc ASSERT(err != 0); 12340ba2cbe9Sxc miocnak(q, mp, 0, err); 12350ba2cbe9Sxc } 1236