1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Data-Link Driver 30 */ 31 32 #include <sys/conf.h> 33 #include <sys/mkdev.h> 34 #include <sys/modctl.h> 35 #include <sys/stat.h> 36 #include <sys/strsun.h> 37 #include <sys/dld.h> 38 #include <sys/dld_impl.h> 39 #include <sys/dls_impl.h> 40 #include <inet/common.h> 41 42 /* 43 * dld control node state, one per open control node session. 44 */ 45 typedef struct dld_ctl_str_s { 46 minor_t cs_minor; 47 queue_t *cs_wq; 48 } dld_ctl_str_t; 49 50 static void drv_init(void); 51 static int drv_fini(void); 52 53 static int drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 54 static int drv_attach(dev_info_t *, ddi_attach_cmd_t); 55 static int drv_detach(dev_info_t *, ddi_detach_cmd_t); 56 57 /* 58 * Secure objects declarations 59 */ 60 #define SECOBJ_WEP_HASHSZ 67 61 static krwlock_t drv_secobj_lock; 62 static kmem_cache_t *drv_secobj_cachep; 63 static mod_hash_t *drv_secobj_hash; 64 static void drv_secobj_init(void); 65 static void drv_secobj_fini(void); 66 static void drv_ioc_secobj_set(dld_ctl_str_t *, mblk_t *); 67 static void drv_ioc_secobj_get(dld_ctl_str_t *, mblk_t *); 68 static void drv_ioc_secobj_unset(dld_ctl_str_t *, mblk_t *); 69 70 /* 71 * The following entry points are private to dld and are used for control 72 * operations only. The entry points exported to mac drivers are defined 73 * in dld_str.c. Refer to the comment on top of dld_str.c for details. 74 */ 75 static int drv_open(queue_t *, dev_t *, int, int, cred_t *); 76 static int drv_close(queue_t *); 77 78 static void drv_uw_put(queue_t *, mblk_t *); 79 static void drv_uw_srv(queue_t *); 80 81 dev_info_t *dld_dip; /* dev_info_t for the driver */ 82 uint32_t dld_opt = 0; /* Global options */ 83 static vmem_t *dld_ctl_vmem; /* for control minor numbers */ 84 85 static struct module_info drv_info = { 86 0, /* mi_idnum */ 87 DLD_DRIVER_NAME, /* mi_idname */ 88 0, /* mi_minpsz */ 89 (64 * 1024), /* mi_maxpsz */ 90 1, /* mi_hiwat */ 91 0 /* mi_lowat */ 92 }; 93 94 static struct qinit drv_ur_init = { 95 NULL, /* qi_putp */ 96 NULL, /* qi_srvp */ 97 drv_open, /* qi_qopen */ 98 drv_close, /* qi_qclose */ 99 NULL, /* qi_qadmin */ 100 &drv_info, /* qi_minfo */ 101 NULL /* qi_mstat */ 102 }; 103 104 static struct qinit drv_uw_init = { 105 (pfi_t)drv_uw_put, /* qi_putp */ 106 (pfi_t)drv_uw_srv, /* qi_srvp */ 107 NULL, /* qi_qopen */ 108 NULL, /* qi_qclose */ 109 NULL, /* qi_qadmin */ 110 &drv_info, /* qi_minfo */ 111 NULL /* qi_mstat */ 112 }; 113 114 static struct streamtab drv_stream = { 115 &drv_ur_init, /* st_rdinit */ 116 &drv_uw_init, /* st_wrinit */ 117 NULL, /* st_muxrinit */ 118 NULL /* st_muxwinit */ 119 }; 120 121 DDI_DEFINE_STREAM_OPS(drv_ops, nulldev, nulldev, drv_attach, drv_detach, 122 nodev, drv_getinfo, D_MP, &drv_stream); 123 124 /* 125 * Module linkage information for the kernel. 126 */ 127 128 extern struct mod_ops mod_driverops; 129 130 static struct modldrv drv_modldrv = { 131 &mod_driverops, 132 DLD_INFO, 133 &drv_ops 134 }; 135 136 static struct modlinkage drv_modlinkage = { 137 MODREV_1, 138 &drv_modldrv, 139 NULL 140 }; 141 142 int 143 _init(void) 144 { 145 int err; 146 147 drv_init(); 148 149 if ((err = mod_install(&drv_modlinkage)) != 0) 150 return (err); 151 152 return (0); 153 } 154 155 int 156 _fini(void) 157 { 158 int err; 159 160 if ((err = mod_remove(&drv_modlinkage)) != 0) 161 return (err); 162 163 if (drv_fini() != 0) { 164 (void) mod_install(&drv_modlinkage); 165 return (DDI_FAILURE); 166 } 167 168 return (err); 169 } 170 171 int 172 _info(struct modinfo *modinfop) 173 { 174 return (mod_info(&drv_modlinkage, modinfop)); 175 } 176 177 /* 178 * Initialize component modules. 179 */ 180 static void 181 drv_init(void) 182 { 183 dld_ctl_vmem = vmem_create("dld_ctl", (void *)1, MAXMIN, 1, 184 NULL, NULL, NULL, 1, VM_SLEEP | VMC_IDENTIFIER); 185 drv_secobj_init(); 186 dld_str_init(); 187 } 188 189 static int 190 drv_fini(void) 191 { 192 int err; 193 194 if ((err = dld_str_fini()) != 0) 195 return (err); 196 197 drv_secobj_fini(); 198 vmem_destroy(dld_ctl_vmem); 199 return (0); 200 } 201 202 /* 203 * devo_getinfo: getinfo(9e) 204 */ 205 /*ARGSUSED*/ 206 static int 207 drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resp) 208 { 209 if (dld_dip == NULL) 210 return (DDI_FAILURE); 211 212 switch (cmd) { 213 case DDI_INFO_DEVT2INSTANCE: 214 *resp = (void *)0; 215 break; 216 case DDI_INFO_DEVT2DEVINFO: 217 *resp = (void *)dld_dip; 218 break; 219 default: 220 return (DDI_FAILURE); 221 } 222 223 return (DDI_SUCCESS); 224 } 225 226 /* 227 * Check properties to set options. (See dld.h for property definitions). 228 */ 229 static void 230 drv_set_opt(dev_info_t *dip) 231 { 232 if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 233 DLD_PROP_NO_FASTPATH, 0) != 0) { 234 dld_opt |= DLD_OPT_NO_FASTPATH; 235 } 236 237 if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 238 DLD_PROP_NO_POLL, 0) != 0) { 239 dld_opt |= DLD_OPT_NO_POLL; 240 } 241 242 if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 243 DLD_PROP_NO_ZEROCOPY, 0) != 0) { 244 dld_opt |= DLD_OPT_NO_ZEROCOPY; 245 } 246 } 247 248 /* 249 * devo_attach: attach(9e) 250 */ 251 static int 252 drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 253 { 254 if (cmd != DDI_ATTACH) 255 return (DDI_FAILURE); 256 257 ASSERT(ddi_get_instance(dip) == 0); 258 259 drv_set_opt(dip); 260 261 /* 262 * Create control node. DLPI provider nodes will be created on demand. 263 */ 264 if (ddi_create_minor_node(dip, DLD_CONTROL_MINOR_NAME, S_IFCHR, 265 DLD_CONTROL_MINOR, DDI_PSEUDO, 0) != DDI_SUCCESS) 266 return (DDI_FAILURE); 267 268 dld_dip = dip; 269 270 /* 271 * Log the fact that the driver is now attached. 272 */ 273 ddi_report_dev(dip); 274 return (DDI_SUCCESS); 275 } 276 277 /* 278 * devo_detach: detach(9e) 279 */ 280 static int 281 drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 282 { 283 if (cmd != DDI_DETACH) 284 return (DDI_FAILURE); 285 286 ASSERT(dld_dip == dip); 287 288 /* 289 * Remove the control node. 290 */ 291 ddi_remove_minor_node(dip, DLD_CONTROL_MINOR_NAME); 292 dld_dip = NULL; 293 294 return (DDI_SUCCESS); 295 } 296 297 /* 298 * dld control node open procedure. 299 */ 300 /*ARGSUSED*/ 301 static int 302 drv_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp) 303 { 304 dld_ctl_str_t *ctls; 305 minor_t minor; 306 queue_t *oq = OTHERQ(rq); 307 308 if (sflag == MODOPEN) 309 return (ENOTSUP); 310 311 /* 312 * This is a cloning driver and therefore each queue should only 313 * ever get opened once. 314 */ 315 if (rq->q_ptr != NULL) 316 return (EBUSY); 317 318 minor = (minor_t)(uintptr_t)vmem_alloc(dld_ctl_vmem, 1, VM_NOSLEEP); 319 if (minor == 0) 320 return (ENOMEM); 321 322 ctls = kmem_zalloc(sizeof (dld_ctl_str_t), KM_NOSLEEP); 323 if (ctls == NULL) { 324 vmem_free(dld_ctl_vmem, (void *)(uintptr_t)minor, 1); 325 return (ENOMEM); 326 } 327 328 ctls->cs_minor = minor; 329 ctls->cs_wq = WR(rq); 330 331 rq->q_ptr = ctls; 332 oq->q_ptr = ctls; 333 334 /* 335 * Enable the queue srv(9e) routine. 336 */ 337 qprocson(rq); 338 339 /* 340 * Construct a cloned dev_t to hand back. 341 */ 342 *devp = makedevice(getmajor(*devp), ctls->cs_minor); 343 return (0); 344 } 345 346 /* 347 * dld control node close procedure. 348 */ 349 static int 350 drv_close(queue_t *rq) 351 { 352 dld_ctl_str_t *ctls; 353 354 ctls = rq->q_ptr; 355 ASSERT(ctls != NULL); 356 357 /* 358 * Disable the queue srv(9e) routine. 359 */ 360 qprocsoff(rq); 361 362 vmem_free(dld_ctl_vmem, (void *)(uintptr_t)ctls->cs_minor, 1); 363 364 kmem_free(ctls, sizeof (dld_ctl_str_t)); 365 366 return (0); 367 } 368 369 /* 370 * DLDIOCATTR 371 */ 372 static void 373 drv_ioc_attr(dld_ctl_str_t *ctls, mblk_t *mp) 374 { 375 dld_ioc_attr_t *diap; 376 dls_vlan_t *dvp = NULL; 377 dls_link_t *dlp = NULL; 378 int err; 379 queue_t *q = ctls->cs_wq; 380 381 if ((err = miocpullup(mp, sizeof (dld_ioc_attr_t))) != 0) 382 goto failed; 383 384 diap = (dld_ioc_attr_t *)mp->b_cont->b_rptr; 385 diap->dia_name[IFNAMSIZ - 1] = '\0'; 386 387 if (dls_vlan_hold(diap->dia_name, &dvp, B_FALSE) != 0) { 388 err = ENOENT; 389 goto failed; 390 } 391 392 dlp = dvp->dv_dlp; 393 (void) strlcpy(diap->dia_dev, dlp->dl_name, sizeof (diap->dia_dev)); 394 diap->dia_vid = dvp->dv_id; 395 diap->dia_max_sdu = dlp->dl_mip->mi_sdu_max; 396 397 dls_vlan_rele(dvp); 398 miocack(q, mp, sizeof (dld_ioc_attr_t), 0); 399 return; 400 401 failed: 402 ASSERT(err != 0); 403 if (err == ENOENT) { 404 char devname[MAXNAMELEN]; 405 uint_t instance; 406 major_t major; 407 408 /* 409 * Try to detect if the specified device is gldv3 410 * and return ENODEV if it is not. 411 */ 412 if (ddi_parse(diap->dia_name, devname, &instance) == 0 && 413 (major = ddi_name_to_major(devname)) != (major_t)-1 && 414 !GLDV3_DRV(major)) 415 err = ENODEV; 416 } 417 miocnak(q, mp, 0, err); 418 } 419 420 421 /* 422 * DLDIOCVLAN 423 */ 424 typedef struct dld_ioc_vlan_state { 425 uint_t bytes_left; 426 dld_ioc_vlan_t *divp; 427 dld_vlan_info_t *vlanp; 428 } dld_ioc_vlan_state_t; 429 430 static int 431 drv_ioc_vlan_info(dls_vlan_t *dvp, void *arg) 432 { 433 dld_ioc_vlan_state_t *statep = arg; 434 435 /* 436 * passed buffer space is limited to 65536 bytes. So 437 * copy only the vlans associated with the passed link. 438 */ 439 if (strcmp(dvp->dv_dlp->dl_name, statep->divp->div_name) == 0 && 440 dvp->dv_id != 0) { 441 if (statep->bytes_left < sizeof (dld_vlan_info_t)) 442 return (ENOSPC); 443 444 (void) strlcpy(statep->vlanp->dvi_name, 445 dvp->dv_name, IFNAMSIZ); 446 statep->divp->div_count++; 447 statep->bytes_left -= sizeof (dld_vlan_info_t); 448 statep->vlanp += 1; 449 } 450 return (0); 451 } 452 453 static void 454 drv_ioc_vlan(dld_ctl_str_t *ctls, mblk_t *mp) 455 { 456 dld_ioc_vlan_t *divp; 457 dld_ioc_vlan_state_t state; 458 int err = EINVAL; 459 queue_t *q = ctls->cs_wq; 460 mblk_t *bp; 461 462 if ((err = miocpullup(mp, sizeof (dld_ioc_vlan_t))) != 0) 463 goto failed; 464 465 if ((bp = msgpullup(mp->b_cont, -1)) == NULL) 466 goto failed; 467 468 freemsg(mp->b_cont); 469 mp->b_cont = bp; 470 divp = (dld_ioc_vlan_t *)bp->b_rptr; 471 divp->div_count = 0; 472 state.bytes_left = MBLKL(bp) - sizeof (dld_ioc_vlan_t); 473 state.divp = divp; 474 state.vlanp = (dld_vlan_info_t *)(divp + 1); 475 476 err = dls_vlan_walk(drv_ioc_vlan_info, &state); 477 if (err != 0) 478 goto failed; 479 480 miocack(q, mp, sizeof (dld_ioc_vlan_t) + 481 state.divp->div_count * sizeof (dld_vlan_info_t), 0); 482 return; 483 484 failed: 485 ASSERT(err != 0); 486 miocnak(q, mp, 0, err); 487 } 488 489 490 /* 491 * Process an IOCTL message received by the control node. 492 */ 493 static void 494 drv_ioc(dld_ctl_str_t *ctls, mblk_t *mp) 495 { 496 uint_t cmd; 497 498 cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd; 499 switch (cmd) { 500 case DLDIOCATTR: 501 drv_ioc_attr(ctls, mp); 502 return; 503 case DLDIOCVLAN: 504 drv_ioc_vlan(ctls, mp); 505 return; 506 case DLDIOCSECOBJSET: 507 drv_ioc_secobj_set(ctls, mp); 508 return; 509 case DLDIOCSECOBJGET: 510 drv_ioc_secobj_get(ctls, mp); 511 return; 512 case DLDIOCSECOBJUNSET: 513 drv_ioc_secobj_unset(ctls, mp); 514 return; 515 default: 516 miocnak(ctls->cs_wq, mp, 0, ENOTSUP); 517 return; 518 } 519 } 520 521 /* 522 * Write side put routine of the dld control node. 523 */ 524 static void 525 drv_uw_put(queue_t *q, mblk_t *mp) 526 { 527 dld_ctl_str_t *ctls = q->q_ptr; 528 529 switch (mp->b_datap->db_type) { 530 case M_IOCTL: 531 drv_ioc(ctls, mp); 532 break; 533 default: 534 freemsg(mp); 535 break; 536 } 537 } 538 539 /* 540 * Write-side service procedure. 541 */ 542 void 543 drv_uw_srv(queue_t *q) 544 { 545 mblk_t *mp; 546 547 while (mp = getq(q)) 548 drv_uw_put(q, mp); 549 } 550 551 /* 552 * Secure objects implementation 553 */ 554 555 /* ARGSUSED */ 556 static int 557 drv_secobj_ctor(void *buf, void *arg, int kmflag) 558 { 559 bzero(buf, sizeof (dld_secobj_t)); 560 return (0); 561 } 562 563 static void 564 drv_secobj_init(void) 565 { 566 rw_init(&drv_secobj_lock, NULL, RW_DEFAULT, NULL); 567 drv_secobj_cachep = kmem_cache_create("drv_secobj_cache", 568 sizeof (dld_secobj_t), 0, drv_secobj_ctor, NULL, 569 NULL, NULL, NULL, 0); 570 drv_secobj_hash = mod_hash_create_extended("drv_secobj_hash", 571 SECOBJ_WEP_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, 572 mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 573 } 574 575 static void 576 drv_secobj_fini(void) 577 { 578 mod_hash_destroy_hash(drv_secobj_hash); 579 kmem_cache_destroy(drv_secobj_cachep); 580 rw_destroy(&drv_secobj_lock); 581 } 582 583 static void 584 drv_ioc_secobj_set(dld_ctl_str_t *ctls, mblk_t *mp) 585 { 586 dld_ioc_secobj_set_t *ssp; 587 dld_secobj_t *sobjp, *objp; 588 int err = EINVAL; 589 queue_t *q = ctls->cs_wq; 590 591 if ((err = miocpullup(mp, sizeof (dld_ioc_secobj_set_t))) != 0) 592 goto failed; 593 594 ssp = (dld_ioc_secobj_set_t *)mp->b_cont->b_rptr; 595 sobjp = &ssp->ss_obj; 596 597 if (sobjp->so_class != DLD_SECOBJ_CLASS_WEP) 598 goto failed; 599 600 if (sobjp->so_name[DLD_SECOBJ_NAME_MAX - 1] != '\0' || 601 sobjp->so_len > DLD_SECOBJ_VAL_MAX) 602 goto failed; 603 604 rw_enter(&drv_secobj_lock, RW_WRITER); 605 err = mod_hash_find(drv_secobj_hash, (mod_hash_key_t)sobjp->so_name, 606 (mod_hash_val_t *)&objp); 607 if (err == 0) { 608 if ((ssp->ss_flags & DLD_SECOBJ_OPT_CREATE) != 0) { 609 err = EEXIST; 610 rw_exit(&drv_secobj_lock); 611 goto failed; 612 } 613 } else { 614 ASSERT(err == MH_ERR_NOTFOUND); 615 if ((ssp->ss_flags & DLD_SECOBJ_OPT_CREATE) == 0) { 616 err = ENOENT; 617 rw_exit(&drv_secobj_lock); 618 goto failed; 619 } 620 objp = kmem_cache_alloc(drv_secobj_cachep, KM_SLEEP); 621 (void) strlcpy(objp->so_name, sobjp->so_name, 622 DLD_SECOBJ_NAME_MAX); 623 624 err = mod_hash_insert(drv_secobj_hash, 625 (mod_hash_key_t)objp->so_name, (mod_hash_val_t)objp); 626 ASSERT(err == 0); 627 } 628 bcopy(sobjp->so_val, objp->so_val, sobjp->so_len); 629 objp->so_len = sobjp->so_len; 630 objp->so_class = sobjp->so_class; 631 rw_exit(&drv_secobj_lock); 632 miocack(q, mp, 0, 0); 633 return; 634 635 failed: 636 ASSERT(err != 0); 637 miocnak(q, mp, 0, err); 638 639 } 640 641 typedef struct dld_secobj_state { 642 uint_t ss_free; 643 uint_t ss_count; 644 int ss_rc; 645 dld_secobj_t *ss_objp; 646 } dld_secobj_state_t; 647 648 /* ARGSUSED */ 649 static uint_t 650 drv_secobj_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 651 { 652 dld_secobj_state_t *statep = arg; 653 dld_secobj_t *sobjp = (dld_secobj_t *)val; 654 655 if (statep->ss_free < sizeof (dld_secobj_t)) { 656 statep->ss_rc = ENOSPC; 657 return (MH_WALK_TERMINATE); 658 } 659 bcopy(sobjp, statep->ss_objp, sizeof (dld_secobj_t)); 660 statep->ss_objp++; 661 statep->ss_free -= sizeof (dld_secobj_t); 662 statep->ss_count++; 663 return (MH_WALK_CONTINUE); 664 } 665 666 static void 667 drv_ioc_secobj_get(dld_ctl_str_t *ctls, mblk_t *mp) 668 { 669 dld_ioc_secobj_get_t *sgp; 670 dld_secobj_t *sobjp, *objp; 671 int err = EINVAL; 672 uint_t extra = 0; 673 queue_t *q = ctls->cs_wq; 674 mblk_t *bp; 675 676 if ((err = miocpullup(mp, sizeof (dld_ioc_secobj_get_t))) != 0) 677 goto failed; 678 679 if ((bp = msgpullup(mp->b_cont, -1)) == NULL) 680 goto failed; 681 682 freemsg(mp->b_cont); 683 mp->b_cont = bp; 684 sgp = (dld_ioc_secobj_get_t *)bp->b_rptr; 685 sobjp = &sgp->sg_obj; 686 687 if (sobjp->so_name[DLD_SECOBJ_NAME_MAX - 1] != '\0') 688 goto failed; 689 690 rw_enter(&drv_secobj_lock, RW_READER); 691 if (sobjp->so_name[0] != '\0') { 692 err = mod_hash_find(drv_secobj_hash, 693 (mod_hash_key_t)sobjp->so_name, (mod_hash_val_t *)&objp); 694 if (err != 0) { 695 ASSERT(err == MH_ERR_NOTFOUND); 696 err = ENOENT; 697 rw_exit(&drv_secobj_lock); 698 goto failed; 699 } 700 bcopy(objp->so_val, sobjp->so_val, objp->so_len); 701 sobjp->so_len = objp->so_len; 702 sobjp->so_class = objp->so_class; 703 sgp->sg_count = 1; 704 } else { 705 dld_secobj_state_t state; 706 707 state.ss_free = MBLKL(bp) - sizeof (dld_ioc_secobj_get_t); 708 state.ss_count = 0; 709 state.ss_rc = 0; 710 state.ss_objp = (dld_secobj_t *)(sgp + 1); 711 mod_hash_walk(drv_secobj_hash, drv_secobj_walker, &state); 712 if (state.ss_rc != 0) { 713 err = state.ss_rc; 714 rw_exit(&drv_secobj_lock); 715 goto failed; 716 } 717 sgp->sg_count = state.ss_count; 718 extra = state.ss_count * sizeof (dld_secobj_t); 719 } 720 rw_exit(&drv_secobj_lock); 721 miocack(q, mp, sizeof (dld_ioc_secobj_get_t) + extra, 0); 722 return; 723 724 failed: 725 ASSERT(err != 0); 726 miocnak(q, mp, 0, err); 727 728 } 729 730 static void 731 drv_ioc_secobj_unset(dld_ctl_str_t *ctls, mblk_t *mp) 732 { 733 dld_ioc_secobj_unset_t *sup; 734 dld_secobj_t *objp; 735 mod_hash_val_t val; 736 int err = EINVAL; 737 queue_t *q = ctls->cs_wq; 738 739 if ((err = miocpullup(mp, sizeof (dld_ioc_secobj_unset_t))) != 0) 740 goto failed; 741 742 sup = (dld_ioc_secobj_unset_t *)mp->b_cont->b_rptr; 743 if (sup->su_name[DLD_SECOBJ_NAME_MAX - 1] != '\0') 744 goto failed; 745 746 rw_enter(&drv_secobj_lock, RW_WRITER); 747 err = mod_hash_find(drv_secobj_hash, (mod_hash_key_t)sup->su_name, 748 (mod_hash_val_t *)&objp); 749 if (err != 0) { 750 ASSERT(err == MH_ERR_NOTFOUND); 751 err = ENOENT; 752 rw_exit(&drv_secobj_lock); 753 goto failed; 754 } 755 err = mod_hash_remove(drv_secobj_hash, (mod_hash_key_t)sup->su_name, 756 (mod_hash_val_t *)&val); 757 ASSERT(err == 0); 758 ASSERT(objp == (dld_secobj_t *)val); 759 760 kmem_cache_free(drv_secobj_cachep, objp); 761 rw_exit(&drv_secobj_lock); 762 miocack(q, mp, 0, 0); 763 return; 764 765 failed: 766 ASSERT(err != 0); 767 miocnak(q, mp, 0, err); 768 } 769