10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 52311Sseb * Common Development and Distribution License (the "License"). 62311Sseb * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 222311Sseb * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate /* 290Sstevel@tonic-gate * Data-Link Driver 300Sstevel@tonic-gate */ 310Sstevel@tonic-gate 320Sstevel@tonic-gate #include <sys/conf.h> 33269Sericheng #include <sys/mkdev.h> 34269Sericheng #include <sys/modctl.h> 350Sstevel@tonic-gate #include <sys/stat.h> 36269Sericheng #include <sys/strsun.h> 37269Sericheng #include <sys/dld.h> 38269Sericheng #include <sys/dld_impl.h> 39269Sericheng #include <sys/dls_impl.h> 400Sstevel@tonic-gate #include <inet/common.h> 410Sstevel@tonic-gate 42269Sericheng /* 43269Sericheng * dld control node state, one per open control node session. 44269Sericheng */ 45269Sericheng typedef struct dld_ctl_str_s { 46269Sericheng minor_t cs_minor; 47269Sericheng queue_t *cs_wq; 48269Sericheng } dld_ctl_str_t; 490Sstevel@tonic-gate 500Sstevel@tonic-gate static void drv_init(void); 510Sstevel@tonic-gate static int drv_fini(void); 520Sstevel@tonic-gate 530Sstevel@tonic-gate static int drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 540Sstevel@tonic-gate static int drv_attach(dev_info_t *, ddi_attach_cmd_t); 550Sstevel@tonic-gate static int drv_detach(dev_info_t *, ddi_detach_cmd_t); 560Sstevel@tonic-gate 57269Sericheng /* 58*3147Sxc151355 * Secure objects declarations 59*3147Sxc151355 */ 60*3147Sxc151355 #define SECOBJ_WEP_HASHSZ 67 61*3147Sxc151355 static krwlock_t drv_secobj_lock; 62*3147Sxc151355 static kmem_cache_t *drv_secobj_cachep; 63*3147Sxc151355 static mod_hash_t *drv_secobj_hash; 64*3147Sxc151355 static void drv_secobj_init(void); 65*3147Sxc151355 static void drv_secobj_fini(void); 66*3147Sxc151355 static void drv_ioc_secobj_set(dld_ctl_str_t *, mblk_t *); 67*3147Sxc151355 static void drv_ioc_secobj_get(dld_ctl_str_t *, mblk_t *); 68*3147Sxc151355 static void drv_ioc_secobj_unset(dld_ctl_str_t *, mblk_t *); 69*3147Sxc151355 70*3147Sxc151355 /* 71269Sericheng * The following entry points are private to dld and are used for control 72269Sericheng * operations only. The entry points exported to mac drivers are defined 73269Sericheng * in dld_str.c. Refer to the comment on top of dld_str.c for details. 74269Sericheng */ 750Sstevel@tonic-gate static int drv_open(queue_t *, dev_t *, int, int, cred_t *); 760Sstevel@tonic-gate static int drv_close(queue_t *); 770Sstevel@tonic-gate 780Sstevel@tonic-gate static void drv_uw_put(queue_t *, mblk_t *); 790Sstevel@tonic-gate static void drv_uw_srv(queue_t *); 800Sstevel@tonic-gate 810Sstevel@tonic-gate dev_info_t *dld_dip; /* dev_info_t for the driver */ 82269Sericheng uint32_t dld_opt = 0; /* Global options */ 83269Sericheng static vmem_t *dld_ctl_vmem; /* for control minor numbers */ 840Sstevel@tonic-gate 850Sstevel@tonic-gate static struct module_info drv_info = { 860Sstevel@tonic-gate 0, /* mi_idnum */ 870Sstevel@tonic-gate DLD_DRIVER_NAME, /* mi_idname */ 880Sstevel@tonic-gate 0, /* mi_minpsz */ 890Sstevel@tonic-gate (64 * 1024), /* mi_maxpsz */ 900Sstevel@tonic-gate 1, /* mi_hiwat */ 910Sstevel@tonic-gate 0 /* mi_lowat */ 920Sstevel@tonic-gate }; 930Sstevel@tonic-gate 940Sstevel@tonic-gate static struct qinit drv_ur_init = { 950Sstevel@tonic-gate NULL, /* qi_putp */ 960Sstevel@tonic-gate NULL, /* qi_srvp */ 970Sstevel@tonic-gate drv_open, /* qi_qopen */ 980Sstevel@tonic-gate drv_close, /* qi_qclose */ 990Sstevel@tonic-gate NULL, /* qi_qadmin */ 1000Sstevel@tonic-gate &drv_info, /* qi_minfo */ 1010Sstevel@tonic-gate NULL /* qi_mstat */ 1020Sstevel@tonic-gate }; 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate static struct qinit drv_uw_init = { 1050Sstevel@tonic-gate (pfi_t)drv_uw_put, /* qi_putp */ 1060Sstevel@tonic-gate (pfi_t)drv_uw_srv, /* qi_srvp */ 1070Sstevel@tonic-gate NULL, /* qi_qopen */ 1080Sstevel@tonic-gate NULL, /* qi_qclose */ 1090Sstevel@tonic-gate NULL, /* qi_qadmin */ 1100Sstevel@tonic-gate &drv_info, /* qi_minfo */ 1110Sstevel@tonic-gate NULL /* qi_mstat */ 1120Sstevel@tonic-gate }; 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate static struct streamtab drv_stream = { 1150Sstevel@tonic-gate &drv_ur_init, /* st_rdinit */ 1160Sstevel@tonic-gate &drv_uw_init, /* st_wrinit */ 1170Sstevel@tonic-gate NULL, /* st_muxrinit */ 1180Sstevel@tonic-gate NULL /* st_muxwinit */ 1190Sstevel@tonic-gate }; 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(drv_ops, nulldev, nulldev, drv_attach, drv_detach, 122269Sericheng nodev, drv_getinfo, D_MP, &drv_stream); 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate /* 1250Sstevel@tonic-gate * Module linkage information for the kernel. 1260Sstevel@tonic-gate */ 1270Sstevel@tonic-gate 1280Sstevel@tonic-gate extern struct mod_ops mod_driverops; 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate static struct modldrv drv_modldrv = { 1310Sstevel@tonic-gate &mod_driverops, 1320Sstevel@tonic-gate DLD_INFO, 1330Sstevel@tonic-gate &drv_ops 1340Sstevel@tonic-gate }; 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate static struct modlinkage drv_modlinkage = { 1370Sstevel@tonic-gate MODREV_1, 1380Sstevel@tonic-gate &drv_modldrv, 1390Sstevel@tonic-gate NULL 1400Sstevel@tonic-gate }; 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate int 1430Sstevel@tonic-gate _init(void) 1440Sstevel@tonic-gate { 1450Sstevel@tonic-gate int err; 1460Sstevel@tonic-gate 147269Sericheng drv_init(); 148269Sericheng 1490Sstevel@tonic-gate if ((err = mod_install(&drv_modlinkage)) != 0) 1500Sstevel@tonic-gate return (err); 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate return (0); 1530Sstevel@tonic-gate } 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate int 1560Sstevel@tonic-gate _fini(void) 1570Sstevel@tonic-gate { 1580Sstevel@tonic-gate int err; 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate if ((err = mod_remove(&drv_modlinkage)) != 0) 1610Sstevel@tonic-gate return (err); 1620Sstevel@tonic-gate 163269Sericheng if (drv_fini() != 0) { 164269Sericheng (void) mod_install(&drv_modlinkage); 165269Sericheng return (DDI_FAILURE); 166269Sericheng } 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate return (err); 1690Sstevel@tonic-gate } 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate int 1720Sstevel@tonic-gate _info(struct modinfo *modinfop) 1730Sstevel@tonic-gate { 1740Sstevel@tonic-gate return (mod_info(&drv_modlinkage, modinfop)); 1750Sstevel@tonic-gate } 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate /* 178269Sericheng * Initialize component modules. 1790Sstevel@tonic-gate */ 1800Sstevel@tonic-gate static void 1810Sstevel@tonic-gate drv_init(void) 1820Sstevel@tonic-gate { 183269Sericheng dld_ctl_vmem = vmem_create("dld_ctl", (void *)1, MAXMIN, 1, 184269Sericheng NULL, NULL, NULL, 1, VM_SLEEP | VMC_IDENTIFIER); 185*3147Sxc151355 drv_secobj_init(); 1860Sstevel@tonic-gate dld_str_init(); 1870Sstevel@tonic-gate } 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate static int 1900Sstevel@tonic-gate drv_fini(void) 1910Sstevel@tonic-gate { 1920Sstevel@tonic-gate int err; 1930Sstevel@tonic-gate 194269Sericheng if ((err = dld_str_fini()) != 0) 1950Sstevel@tonic-gate return (err); 1960Sstevel@tonic-gate 197*3147Sxc151355 drv_secobj_fini(); 198269Sericheng vmem_destroy(dld_ctl_vmem); 1990Sstevel@tonic-gate return (0); 2000Sstevel@tonic-gate } 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate /* 2030Sstevel@tonic-gate * devo_getinfo: getinfo(9e) 2040Sstevel@tonic-gate */ 2050Sstevel@tonic-gate /*ARGSUSED*/ 2060Sstevel@tonic-gate static int 2070Sstevel@tonic-gate drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resp) 2080Sstevel@tonic-gate { 2090Sstevel@tonic-gate if (dld_dip == NULL) 2100Sstevel@tonic-gate return (DDI_FAILURE); 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate switch (cmd) { 2130Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 2140Sstevel@tonic-gate *resp = (void *)0; 2150Sstevel@tonic-gate break; 2160Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 2170Sstevel@tonic-gate *resp = (void *)dld_dip; 2180Sstevel@tonic-gate break; 2190Sstevel@tonic-gate default: 2200Sstevel@tonic-gate return (DDI_FAILURE); 2210Sstevel@tonic-gate } 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate return (DDI_SUCCESS); 2240Sstevel@tonic-gate } 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate /* 2270Sstevel@tonic-gate * Check properties to set options. (See dld.h for property definitions). 2280Sstevel@tonic-gate */ 2290Sstevel@tonic-gate static void 2300Sstevel@tonic-gate drv_set_opt(dev_info_t *dip) 2310Sstevel@tonic-gate { 2320Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 2330Sstevel@tonic-gate DLD_PROP_NO_FASTPATH, 0) != 0) { 2340Sstevel@tonic-gate dld_opt |= DLD_OPT_NO_FASTPATH; 2350Sstevel@tonic-gate } 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 2380Sstevel@tonic-gate DLD_PROP_NO_POLL, 0) != 0) { 2390Sstevel@tonic-gate dld_opt |= DLD_OPT_NO_POLL; 2400Sstevel@tonic-gate } 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 2430Sstevel@tonic-gate DLD_PROP_NO_ZEROCOPY, 0) != 0) { 2440Sstevel@tonic-gate dld_opt |= DLD_OPT_NO_ZEROCOPY; 2450Sstevel@tonic-gate } 2460Sstevel@tonic-gate } 2470Sstevel@tonic-gate 2480Sstevel@tonic-gate /* 2490Sstevel@tonic-gate * devo_attach: attach(9e) 2500Sstevel@tonic-gate */ 2510Sstevel@tonic-gate static int 2520Sstevel@tonic-gate drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2530Sstevel@tonic-gate { 2540Sstevel@tonic-gate if (cmd != DDI_ATTACH) 2550Sstevel@tonic-gate return (DDI_FAILURE); 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate ASSERT(ddi_get_instance(dip) == 0); 2580Sstevel@tonic-gate 2590Sstevel@tonic-gate drv_set_opt(dip); 2600Sstevel@tonic-gate 2610Sstevel@tonic-gate /* 2620Sstevel@tonic-gate * Create control node. DLPI provider nodes will be created on demand. 2630Sstevel@tonic-gate */ 2640Sstevel@tonic-gate if (ddi_create_minor_node(dip, DLD_CONTROL_MINOR_NAME, S_IFCHR, 2650Sstevel@tonic-gate DLD_CONTROL_MINOR, DDI_PSEUDO, 0) != DDI_SUCCESS) 2660Sstevel@tonic-gate return (DDI_FAILURE); 2670Sstevel@tonic-gate 2680Sstevel@tonic-gate dld_dip = dip; 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate /* 2710Sstevel@tonic-gate * Log the fact that the driver is now attached. 2720Sstevel@tonic-gate */ 2730Sstevel@tonic-gate ddi_report_dev(dip); 2740Sstevel@tonic-gate return (DDI_SUCCESS); 2750Sstevel@tonic-gate } 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate /* 2780Sstevel@tonic-gate * devo_detach: detach(9e) 2790Sstevel@tonic-gate */ 2800Sstevel@tonic-gate static int 2810Sstevel@tonic-gate drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2820Sstevel@tonic-gate { 2830Sstevel@tonic-gate if (cmd != DDI_DETACH) 2840Sstevel@tonic-gate return (DDI_FAILURE); 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate ASSERT(dld_dip == dip); 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate /* 2890Sstevel@tonic-gate * Remove the control node. 2900Sstevel@tonic-gate */ 2910Sstevel@tonic-gate ddi_remove_minor_node(dip, DLD_CONTROL_MINOR_NAME); 2920Sstevel@tonic-gate dld_dip = NULL; 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate return (DDI_SUCCESS); 2950Sstevel@tonic-gate } 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate /* 298269Sericheng * dld control node open procedure. 2990Sstevel@tonic-gate */ 3000Sstevel@tonic-gate /*ARGSUSED*/ 3010Sstevel@tonic-gate static int 3020Sstevel@tonic-gate drv_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp) 3030Sstevel@tonic-gate { 304269Sericheng dld_ctl_str_t *ctls; 3050Sstevel@tonic-gate minor_t minor; 306269Sericheng queue_t *oq = OTHERQ(rq); 3070Sstevel@tonic-gate 308269Sericheng if (sflag == MODOPEN) 309269Sericheng return (ENOTSUP); 3100Sstevel@tonic-gate 3110Sstevel@tonic-gate /* 3120Sstevel@tonic-gate * This is a cloning driver and therefore each queue should only 3130Sstevel@tonic-gate * ever get opened once. 3140Sstevel@tonic-gate */ 3150Sstevel@tonic-gate if (rq->q_ptr != NULL) 3160Sstevel@tonic-gate return (EBUSY); 3170Sstevel@tonic-gate 318269Sericheng minor = (minor_t)(uintptr_t)vmem_alloc(dld_ctl_vmem, 1, VM_NOSLEEP); 319269Sericheng if (minor == 0) 320269Sericheng return (ENOMEM); 3210Sstevel@tonic-gate 322269Sericheng ctls = kmem_zalloc(sizeof (dld_ctl_str_t), KM_NOSLEEP); 323269Sericheng if (ctls == NULL) { 324269Sericheng vmem_free(dld_ctl_vmem, (void *)(uintptr_t)minor, 1); 325269Sericheng return (ENOMEM); 326269Sericheng } 3270Sstevel@tonic-gate 328269Sericheng ctls->cs_minor = minor; 329269Sericheng ctls->cs_wq = WR(rq); 3300Sstevel@tonic-gate 331269Sericheng rq->q_ptr = ctls; 332269Sericheng oq->q_ptr = ctls; 3330Sstevel@tonic-gate 3340Sstevel@tonic-gate /* 3350Sstevel@tonic-gate * Enable the queue srv(9e) routine. 3360Sstevel@tonic-gate */ 3370Sstevel@tonic-gate qprocson(rq); 3380Sstevel@tonic-gate 3390Sstevel@tonic-gate /* 3400Sstevel@tonic-gate * Construct a cloned dev_t to hand back. 3410Sstevel@tonic-gate */ 342269Sericheng *devp = makedevice(getmajor(*devp), ctls->cs_minor); 3430Sstevel@tonic-gate return (0); 3440Sstevel@tonic-gate } 3450Sstevel@tonic-gate 3460Sstevel@tonic-gate /* 347269Sericheng * dld control node close procedure. 3480Sstevel@tonic-gate */ 3490Sstevel@tonic-gate static int 3500Sstevel@tonic-gate drv_close(queue_t *rq) 3510Sstevel@tonic-gate { 352269Sericheng dld_ctl_str_t *ctls; 3530Sstevel@tonic-gate 354269Sericheng ctls = rq->q_ptr; 355269Sericheng ASSERT(ctls != NULL); 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate /* 3580Sstevel@tonic-gate * Disable the queue srv(9e) routine. 3590Sstevel@tonic-gate */ 3600Sstevel@tonic-gate qprocsoff(rq); 3610Sstevel@tonic-gate 362269Sericheng vmem_free(dld_ctl_vmem, (void *)(uintptr_t)ctls->cs_minor, 1); 3630Sstevel@tonic-gate 364269Sericheng kmem_free(ctls, sizeof (dld_ctl_str_t)); 365269Sericheng 3660Sstevel@tonic-gate return (0); 3670Sstevel@tonic-gate } 3680Sstevel@tonic-gate 3690Sstevel@tonic-gate /* 370269Sericheng * DLDIOCATTR 3710Sstevel@tonic-gate */ 3720Sstevel@tonic-gate static void 373269Sericheng drv_ioc_attr(dld_ctl_str_t *ctls, mblk_t *mp) 3740Sstevel@tonic-gate { 3752311Sseb dld_ioc_attr_t *diap; 376269Sericheng dls_vlan_t *dvp = NULL; 377269Sericheng dls_link_t *dlp = NULL; 378269Sericheng int err; 379269Sericheng queue_t *q = ctls->cs_wq; 380269Sericheng 381269Sericheng if ((err = miocpullup(mp, sizeof (dld_ioc_attr_t))) != 0) 382269Sericheng goto failed; 383269Sericheng 384269Sericheng diap = (dld_ioc_attr_t *)mp->b_cont->b_rptr; 385269Sericheng diap->dia_name[IFNAMSIZ - 1] = '\0'; 386269Sericheng 387269Sericheng if (dls_vlan_hold(diap->dia_name, &dvp, B_FALSE) != 0) { 388269Sericheng err = ENOENT; 389269Sericheng goto failed; 390269Sericheng } 391269Sericheng 392269Sericheng dlp = dvp->dv_dlp; 3932311Sseb (void) strlcpy(diap->dia_dev, dlp->dl_name, sizeof (diap->dia_dev)); 394269Sericheng diap->dia_vid = dvp->dv_id; 395269Sericheng diap->dia_max_sdu = dlp->dl_mip->mi_sdu_max; 396269Sericheng 397269Sericheng dls_vlan_rele(dvp); 398269Sericheng miocack(q, mp, sizeof (dld_ioc_attr_t), 0); 399269Sericheng return; 400269Sericheng 401269Sericheng failed: 402269Sericheng ASSERT(err != 0); 403269Sericheng if (err == ENOENT) { 404269Sericheng char devname[MAXNAMELEN]; 405269Sericheng uint_t instance; 406269Sericheng major_t major; 407269Sericheng 408269Sericheng /* 409269Sericheng * Try to detect if the specified device is gldv3 410269Sericheng * and return ENODEV if it is not. 411269Sericheng */ 412269Sericheng if (ddi_parse(diap->dia_name, devname, &instance) == 0 && 413269Sericheng (major = ddi_name_to_major(devname)) != (major_t)-1 && 414269Sericheng !GLDV3_DRV(major)) 415269Sericheng err = ENODEV; 416269Sericheng } 417269Sericheng miocnak(q, mp, 0, err); 418269Sericheng } 419269Sericheng 420269Sericheng 421269Sericheng /* 422269Sericheng * DLDIOCVLAN 423269Sericheng */ 424269Sericheng typedef struct dld_ioc_vlan_state { 425269Sericheng uint_t bytes_left; 426733Skrgopi dld_ioc_vlan_t *divp; 427269Sericheng dld_vlan_info_t *vlanp; 428269Sericheng } dld_ioc_vlan_state_t; 429269Sericheng 430269Sericheng static int 431269Sericheng drv_ioc_vlan_info(dls_vlan_t *dvp, void *arg) 432269Sericheng { 433269Sericheng dld_ioc_vlan_state_t *statep = arg; 4340Sstevel@tonic-gate 435733Skrgopi /* 436733Skrgopi * passed buffer space is limited to 65536 bytes. So 437733Skrgopi * copy only the vlans associated with the passed link. 438733Skrgopi */ 4392311Sseb if (strcmp(dvp->dv_dlp->dl_name, statep->divp->div_name) == 0 && 440733Skrgopi dvp->dv_id != 0) { 441733Skrgopi if (statep->bytes_left < sizeof (dld_vlan_info_t)) 442733Skrgopi return (ENOSPC); 443269Sericheng 444733Skrgopi (void) strlcpy(statep->vlanp->dvi_name, 445733Skrgopi dvp->dv_name, IFNAMSIZ); 446733Skrgopi statep->divp->div_count++; 447733Skrgopi statep->bytes_left -= sizeof (dld_vlan_info_t); 448733Skrgopi statep->vlanp += 1; 449733Skrgopi } 450269Sericheng return (0); 451269Sericheng } 452269Sericheng 453269Sericheng static void 454269Sericheng drv_ioc_vlan(dld_ctl_str_t *ctls, mblk_t *mp) 455269Sericheng { 456269Sericheng dld_ioc_vlan_t *divp; 457269Sericheng dld_ioc_vlan_state_t state; 458269Sericheng int err = EINVAL; 459269Sericheng queue_t *q = ctls->cs_wq; 460733Skrgopi mblk_t *bp; 461269Sericheng 462269Sericheng if ((err = miocpullup(mp, sizeof (dld_ioc_vlan_t))) != 0) 463269Sericheng goto failed; 464269Sericheng 465733Skrgopi if ((bp = msgpullup(mp->b_cont, -1)) == NULL) 466733Skrgopi goto failed; 467733Skrgopi 468733Skrgopi freemsg(mp->b_cont); 469733Skrgopi mp->b_cont = bp; 470733Skrgopi divp = (dld_ioc_vlan_t *)bp->b_rptr; 471733Skrgopi divp->div_count = 0; 472733Skrgopi state.bytes_left = MBLKL(bp) - sizeof (dld_ioc_vlan_t); 473733Skrgopi state.divp = divp; 474269Sericheng state.vlanp = (dld_vlan_info_t *)(divp + 1); 475269Sericheng 476269Sericheng err = dls_vlan_walk(drv_ioc_vlan_info, &state); 477269Sericheng if (err != 0) 478269Sericheng goto failed; 4790Sstevel@tonic-gate 480269Sericheng miocack(q, mp, sizeof (dld_ioc_vlan_t) + 481733Skrgopi state.divp->div_count * sizeof (dld_vlan_info_t), 0); 482269Sericheng return; 483269Sericheng 484269Sericheng failed: 485269Sericheng ASSERT(err != 0); 486269Sericheng miocnak(q, mp, 0, err); 487269Sericheng } 488269Sericheng 489269Sericheng 490269Sericheng /* 491269Sericheng * Process an IOCTL message received by the control node. 492269Sericheng */ 493269Sericheng static void 494269Sericheng drv_ioc(dld_ctl_str_t *ctls, mblk_t *mp) 495269Sericheng { 496269Sericheng uint_t cmd; 497269Sericheng 498269Sericheng cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd; 499269Sericheng switch (cmd) { 500269Sericheng case DLDIOCATTR: 501269Sericheng drv_ioc_attr(ctls, mp); 502269Sericheng return; 503269Sericheng case DLDIOCVLAN: 504269Sericheng drv_ioc_vlan(ctls, mp); 505269Sericheng return; 506*3147Sxc151355 case DLDIOCSECOBJSET: 507*3147Sxc151355 drv_ioc_secobj_set(ctls, mp); 508*3147Sxc151355 return; 509*3147Sxc151355 case DLDIOCSECOBJGET: 510*3147Sxc151355 drv_ioc_secobj_get(ctls, mp); 511*3147Sxc151355 return; 512*3147Sxc151355 case DLDIOCSECOBJUNSET: 513*3147Sxc151355 drv_ioc_secobj_unset(ctls, mp); 514*3147Sxc151355 return; 515269Sericheng default: 516269Sericheng miocnak(ctls->cs_wq, mp, 0, ENOTSUP); 517269Sericheng return; 518269Sericheng } 5190Sstevel@tonic-gate } 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate /* 522269Sericheng * Write side put routine of the dld control node. 5230Sstevel@tonic-gate */ 5240Sstevel@tonic-gate static void 525269Sericheng drv_uw_put(queue_t *q, mblk_t *mp) 5260Sstevel@tonic-gate { 527269Sericheng dld_ctl_str_t *ctls = q->q_ptr; 5280Sstevel@tonic-gate 529269Sericheng switch (mp->b_datap->db_type) { 530269Sericheng case M_IOCTL: 531269Sericheng drv_ioc(ctls, mp); 532269Sericheng break; 533269Sericheng default: 534269Sericheng freemsg(mp); 535269Sericheng break; 536269Sericheng } 537269Sericheng } 5380Sstevel@tonic-gate 539269Sericheng /* 540269Sericheng * Write-side service procedure. 541269Sericheng */ 542269Sericheng void 543269Sericheng drv_uw_srv(queue_t *q) 544269Sericheng { 545269Sericheng mblk_t *mp; 5460Sstevel@tonic-gate 547269Sericheng while (mp = getq(q)) 548269Sericheng drv_uw_put(q, mp); 5490Sstevel@tonic-gate } 550*3147Sxc151355 551*3147Sxc151355 /* 552*3147Sxc151355 * Secure objects implementation 553*3147Sxc151355 */ 554*3147Sxc151355 555*3147Sxc151355 /* ARGSUSED */ 556*3147Sxc151355 static int 557*3147Sxc151355 drv_secobj_ctor(void *buf, void *arg, int kmflag) 558*3147Sxc151355 { 559*3147Sxc151355 bzero(buf, sizeof (dld_secobj_t)); 560*3147Sxc151355 return (0); 561*3147Sxc151355 } 562*3147Sxc151355 563*3147Sxc151355 static void 564*3147Sxc151355 drv_secobj_init(void) 565*3147Sxc151355 { 566*3147Sxc151355 rw_init(&drv_secobj_lock, NULL, RW_DEFAULT, NULL); 567*3147Sxc151355 drv_secobj_cachep = kmem_cache_create("drv_secobj_cache", 568*3147Sxc151355 sizeof (dld_secobj_t), 0, drv_secobj_ctor, NULL, 569*3147Sxc151355 NULL, NULL, NULL, 0); 570*3147Sxc151355 drv_secobj_hash = mod_hash_create_extended("drv_secobj_hash", 571*3147Sxc151355 SECOBJ_WEP_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, 572*3147Sxc151355 mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 573*3147Sxc151355 } 574*3147Sxc151355 575*3147Sxc151355 static void 576*3147Sxc151355 drv_secobj_fini(void) 577*3147Sxc151355 { 578*3147Sxc151355 mod_hash_destroy_hash(drv_secobj_hash); 579*3147Sxc151355 kmem_cache_destroy(drv_secobj_cachep); 580*3147Sxc151355 rw_destroy(&drv_secobj_lock); 581*3147Sxc151355 } 582*3147Sxc151355 583*3147Sxc151355 static void 584*3147Sxc151355 drv_ioc_secobj_set(dld_ctl_str_t *ctls, mblk_t *mp) 585*3147Sxc151355 { 586*3147Sxc151355 dld_ioc_secobj_set_t *ssp; 587*3147Sxc151355 dld_secobj_t *sobjp, *objp; 588*3147Sxc151355 int err = EINVAL; 589*3147Sxc151355 queue_t *q = ctls->cs_wq; 590*3147Sxc151355 591*3147Sxc151355 if ((err = miocpullup(mp, sizeof (dld_ioc_secobj_set_t))) != 0) 592*3147Sxc151355 goto failed; 593*3147Sxc151355 594*3147Sxc151355 ssp = (dld_ioc_secobj_set_t *)mp->b_cont->b_rptr; 595*3147Sxc151355 sobjp = &ssp->ss_obj; 596*3147Sxc151355 597*3147Sxc151355 if (sobjp->so_class != DLD_SECOBJ_CLASS_WEP) 598*3147Sxc151355 goto failed; 599*3147Sxc151355 600*3147Sxc151355 if (sobjp->so_name[DLD_SECOBJ_NAME_MAX - 1] != '\0' || 601*3147Sxc151355 sobjp->so_len > DLD_SECOBJ_VAL_MAX) 602*3147Sxc151355 goto failed; 603*3147Sxc151355 604*3147Sxc151355 rw_enter(&drv_secobj_lock, RW_WRITER); 605*3147Sxc151355 err = mod_hash_find(drv_secobj_hash, (mod_hash_key_t)sobjp->so_name, 606*3147Sxc151355 (mod_hash_val_t *)&objp); 607*3147Sxc151355 if (err == 0) { 608*3147Sxc151355 if ((ssp->ss_flags & DLD_SECOBJ_OPT_CREATE) != 0) { 609*3147Sxc151355 err = EEXIST; 610*3147Sxc151355 rw_exit(&drv_secobj_lock); 611*3147Sxc151355 goto failed; 612*3147Sxc151355 } 613*3147Sxc151355 } else { 614*3147Sxc151355 ASSERT(err == MH_ERR_NOTFOUND); 615*3147Sxc151355 if ((ssp->ss_flags & DLD_SECOBJ_OPT_CREATE) == 0) { 616*3147Sxc151355 err = ENOENT; 617*3147Sxc151355 rw_exit(&drv_secobj_lock); 618*3147Sxc151355 goto failed; 619*3147Sxc151355 } 620*3147Sxc151355 objp = kmem_cache_alloc(drv_secobj_cachep, KM_SLEEP); 621*3147Sxc151355 (void) strlcpy(objp->so_name, sobjp->so_name, 622*3147Sxc151355 DLD_SECOBJ_NAME_MAX); 623*3147Sxc151355 624*3147Sxc151355 err = mod_hash_insert(drv_secobj_hash, 625*3147Sxc151355 (mod_hash_key_t)objp->so_name, (mod_hash_val_t)objp); 626*3147Sxc151355 ASSERT(err == 0); 627*3147Sxc151355 } 628*3147Sxc151355 bcopy(sobjp->so_val, objp->so_val, sobjp->so_len); 629*3147Sxc151355 objp->so_len = sobjp->so_len; 630*3147Sxc151355 objp->so_class = sobjp->so_class; 631*3147Sxc151355 rw_exit(&drv_secobj_lock); 632*3147Sxc151355 miocack(q, mp, 0, 0); 633*3147Sxc151355 return; 634*3147Sxc151355 635*3147Sxc151355 failed: 636*3147Sxc151355 ASSERT(err != 0); 637*3147Sxc151355 miocnak(q, mp, 0, err); 638*3147Sxc151355 639*3147Sxc151355 } 640*3147Sxc151355 641*3147Sxc151355 typedef struct dld_secobj_state { 642*3147Sxc151355 uint_t ss_free; 643*3147Sxc151355 uint_t ss_count; 644*3147Sxc151355 int ss_rc; 645*3147Sxc151355 dld_secobj_t *ss_objp; 646*3147Sxc151355 } dld_secobj_state_t; 647*3147Sxc151355 648*3147Sxc151355 /* ARGSUSED */ 649*3147Sxc151355 static uint_t 650*3147Sxc151355 drv_secobj_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 651*3147Sxc151355 { 652*3147Sxc151355 dld_secobj_state_t *statep = arg; 653*3147Sxc151355 dld_secobj_t *sobjp = (dld_secobj_t *)val; 654*3147Sxc151355 655*3147Sxc151355 if (statep->ss_free < sizeof (dld_secobj_t)) { 656*3147Sxc151355 statep->ss_rc = ENOSPC; 657*3147Sxc151355 return (MH_WALK_TERMINATE); 658*3147Sxc151355 } 659*3147Sxc151355 bcopy(sobjp, statep->ss_objp, sizeof (dld_secobj_t)); 660*3147Sxc151355 statep->ss_objp++; 661*3147Sxc151355 statep->ss_free -= sizeof (dld_secobj_t); 662*3147Sxc151355 statep->ss_count++; 663*3147Sxc151355 return (MH_WALK_CONTINUE); 664*3147Sxc151355 } 665*3147Sxc151355 666*3147Sxc151355 static void 667*3147Sxc151355 drv_ioc_secobj_get(dld_ctl_str_t *ctls, mblk_t *mp) 668*3147Sxc151355 { 669*3147Sxc151355 dld_ioc_secobj_get_t *sgp; 670*3147Sxc151355 dld_secobj_t *sobjp, *objp; 671*3147Sxc151355 int err = EINVAL; 672*3147Sxc151355 uint_t extra = 0; 673*3147Sxc151355 queue_t *q = ctls->cs_wq; 674*3147Sxc151355 mblk_t *bp; 675*3147Sxc151355 676*3147Sxc151355 if ((err = miocpullup(mp, sizeof (dld_ioc_secobj_get_t))) != 0) 677*3147Sxc151355 goto failed; 678*3147Sxc151355 679*3147Sxc151355 if ((bp = msgpullup(mp->b_cont, -1)) == NULL) 680*3147Sxc151355 goto failed; 681*3147Sxc151355 682*3147Sxc151355 freemsg(mp->b_cont); 683*3147Sxc151355 mp->b_cont = bp; 684*3147Sxc151355 sgp = (dld_ioc_secobj_get_t *)bp->b_rptr; 685*3147Sxc151355 sobjp = &sgp->sg_obj; 686*3147Sxc151355 687*3147Sxc151355 if (sobjp->so_name[DLD_SECOBJ_NAME_MAX - 1] != '\0') 688*3147Sxc151355 goto failed; 689*3147Sxc151355 690*3147Sxc151355 rw_enter(&drv_secobj_lock, RW_READER); 691*3147Sxc151355 if (sobjp->so_name[0] != '\0') { 692*3147Sxc151355 err = mod_hash_find(drv_secobj_hash, 693*3147Sxc151355 (mod_hash_key_t)sobjp->so_name, (mod_hash_val_t *)&objp); 694*3147Sxc151355 if (err != 0) { 695*3147Sxc151355 ASSERT(err == MH_ERR_NOTFOUND); 696*3147Sxc151355 err = ENOENT; 697*3147Sxc151355 rw_exit(&drv_secobj_lock); 698*3147Sxc151355 goto failed; 699*3147Sxc151355 } 700*3147Sxc151355 bcopy(objp->so_val, sobjp->so_val, objp->so_len); 701*3147Sxc151355 sobjp->so_len = objp->so_len; 702*3147Sxc151355 sobjp->so_class = objp->so_class; 703*3147Sxc151355 sgp->sg_count = 1; 704*3147Sxc151355 } else { 705*3147Sxc151355 dld_secobj_state_t state; 706*3147Sxc151355 707*3147Sxc151355 state.ss_free = MBLKL(bp) - sizeof (dld_ioc_secobj_get_t); 708*3147Sxc151355 state.ss_count = 0; 709*3147Sxc151355 state.ss_rc = 0; 710*3147Sxc151355 state.ss_objp = (dld_secobj_t *)(sgp + 1); 711*3147Sxc151355 mod_hash_walk(drv_secobj_hash, drv_secobj_walker, &state); 712*3147Sxc151355 if (state.ss_rc != 0) { 713*3147Sxc151355 err = state.ss_rc; 714*3147Sxc151355 rw_exit(&drv_secobj_lock); 715*3147Sxc151355 goto failed; 716*3147Sxc151355 } 717*3147Sxc151355 sgp->sg_count = state.ss_count; 718*3147Sxc151355 extra = state.ss_count * sizeof (dld_secobj_t); 719*3147Sxc151355 } 720*3147Sxc151355 rw_exit(&drv_secobj_lock); 721*3147Sxc151355 miocack(q, mp, sizeof (dld_ioc_secobj_get_t) + extra, 0); 722*3147Sxc151355 return; 723*3147Sxc151355 724*3147Sxc151355 failed: 725*3147Sxc151355 ASSERT(err != 0); 726*3147Sxc151355 miocnak(q, mp, 0, err); 727*3147Sxc151355 728*3147Sxc151355 } 729*3147Sxc151355 730*3147Sxc151355 static void 731*3147Sxc151355 drv_ioc_secobj_unset(dld_ctl_str_t *ctls, mblk_t *mp) 732*3147Sxc151355 { 733*3147Sxc151355 dld_ioc_secobj_unset_t *sup; 734*3147Sxc151355 dld_secobj_t *objp; 735*3147Sxc151355 mod_hash_val_t val; 736*3147Sxc151355 int err = EINVAL; 737*3147Sxc151355 queue_t *q = ctls->cs_wq; 738*3147Sxc151355 739*3147Sxc151355 if ((err = miocpullup(mp, sizeof (dld_ioc_secobj_unset_t))) != 0) 740*3147Sxc151355 goto failed; 741*3147Sxc151355 742*3147Sxc151355 sup = (dld_ioc_secobj_unset_t *)mp->b_cont->b_rptr; 743*3147Sxc151355 if (sup->su_name[DLD_SECOBJ_NAME_MAX - 1] != '\0') 744*3147Sxc151355 goto failed; 745*3147Sxc151355 746*3147Sxc151355 rw_enter(&drv_secobj_lock, RW_WRITER); 747*3147Sxc151355 err = mod_hash_find(drv_secobj_hash, (mod_hash_key_t)sup->su_name, 748*3147Sxc151355 (mod_hash_val_t *)&objp); 749*3147Sxc151355 if (err != 0) { 750*3147Sxc151355 ASSERT(err == MH_ERR_NOTFOUND); 751*3147Sxc151355 err = ENOENT; 752*3147Sxc151355 rw_exit(&drv_secobj_lock); 753*3147Sxc151355 goto failed; 754*3147Sxc151355 } 755*3147Sxc151355 err = mod_hash_remove(drv_secobj_hash, (mod_hash_key_t)sup->su_name, 756*3147Sxc151355 (mod_hash_val_t *)&val); 757*3147Sxc151355 ASSERT(err == 0); 758*3147Sxc151355 ASSERT(objp == (dld_secobj_t *)val); 759*3147Sxc151355 760*3147Sxc151355 kmem_cache_free(drv_secobj_cachep, objp); 761*3147Sxc151355 rw_exit(&drv_secobj_lock); 762*3147Sxc151355 miocack(q, mp, 0, 0); 763*3147Sxc151355 return; 764*3147Sxc151355 765*3147Sxc151355 failed: 766*3147Sxc151355 ASSERT(err != 0); 767*3147Sxc151355 miocnak(q, mp, 0, err); 768*3147Sxc151355 } 769