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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 30 /* All Rights Reserved */ 31 32 33 /* 34 * STREAMS Administrative Driver 35 * 36 * Currently only handles autopush and module name verification. 37 */ 38 39 #include <sys/types.h> 40 #include <sys/param.h> 41 #include <sys/errno.h> 42 #include <sys/stream.h> 43 #include <sys/stropts.h> 44 #include <sys/strsubr.h> 45 #include <sys/strsun.h> 46 #include <sys/conf.h> 47 #include <sys/sad.h> 48 #include <sys/cred.h> 49 #include <sys/debug.h> 50 #include <sys/ddi.h> 51 #include <sys/sunddi.h> 52 #include <sys/stat.h> 53 #include <sys/cmn_err.h> 54 #include <sys/systm.h> 55 #include <sys/modctl.h> 56 #include <sys/priv_names.h> 57 58 static int sadopen(queue_t *, dev_t *, int, int, cred_t *); 59 static int sadclose(queue_t *, int, cred_t *); 60 static int sadwput(queue_t *qp, mblk_t *mp); 61 62 static int sad_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 63 static int sad_attach(dev_info_t *, ddi_attach_cmd_t); 64 65 static struct autopush *ap_alloc(), *ap_hfind(); 66 static void ap_hadd(), ap_hrmv(); 67 static void apush_ioctl(), apush_iocdata(); 68 static void vml_ioctl(), vml_iocdata(); 69 static int valid_major(major_t); 70 71 extern kmutex_t sad_lock; 72 static dev_info_t *sad_dip; /* private copy of devinfo pointer */ 73 static struct autopush *strpfreep; /* autopush freelist */ 74 75 static struct module_info sad_minfo = { 76 0x7361, "sad", 0, INFPSZ, 0, 0 77 }; 78 79 static struct qinit sad_rinit = { 80 NULL, NULL, sadopen, sadclose, NULL, &sad_minfo, NULL 81 }; 82 83 static struct qinit sad_winit = { 84 sadwput, NULL, NULL, NULL, NULL, &sad_minfo, NULL 85 }; 86 87 struct streamtab sadinfo = { 88 &sad_rinit, &sad_winit, NULL, NULL 89 }; 90 91 DDI_DEFINE_STREAM_OPS(sad_ops, nulldev, nulldev, sad_attach, 92 nodev, nodev, sad_info, D_NEW | D_MTPERQ | D_MP, &sadinfo); 93 94 /* 95 * Module linkage information for the kernel. 96 */ 97 98 static struct modldrv modldrv = { 99 &mod_driverops, /* Type of module. This one is a pseudo driver */ 100 "STREAMS Administrative Driver 'sad' %I%", 101 &sad_ops, /* driver ops */ 102 }; 103 104 static struct modlinkage modlinkage = { 105 MODREV_1, &modldrv, NULL 106 }; 107 108 int 109 _init(void) 110 { 111 return (mod_install(&modlinkage)); 112 } 113 114 int 115 _fini(void) 116 { 117 return (mod_remove(&modlinkage)); 118 } 119 120 int 121 _info(struct modinfo *modinfop) 122 { 123 return (mod_info(&modlinkage, modinfop)); 124 } 125 126 static int 127 sad_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 128 { 129 if (cmd != DDI_ATTACH) 130 return (DDI_FAILURE); 131 132 if (ddi_create_minor_node(devi, "user", S_IFCHR, 133 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 134 ddi_remove_minor_node(devi, NULL); 135 return (DDI_FAILURE); 136 } 137 if (ddi_create_priv_minor_node(devi, "admin", S_IFCHR, 138 1, DDI_PSEUDO, PRIVONLY_DEV, PRIV_SYS_CONFIG, 139 PRIV_SYS_CONFIG, 0666) == DDI_FAILURE) { 140 ddi_remove_minor_node(devi, NULL); 141 return (DDI_FAILURE); 142 } 143 sad_dip = devi; 144 return (DDI_SUCCESS); 145 } 146 147 /* ARGSUSED */ 148 static int 149 sad_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 150 { 151 int error; 152 153 switch (infocmd) { 154 case DDI_INFO_DEVT2DEVINFO: 155 if (sad_dip == NULL) { 156 error = DDI_FAILURE; 157 } else { 158 *result = sad_dip; 159 error = DDI_SUCCESS; 160 } 161 break; 162 case DDI_INFO_DEVT2INSTANCE: 163 *result = (void *)0; 164 error = DDI_SUCCESS; 165 break; 166 default: 167 error = DDI_FAILURE; 168 } 169 return (error); 170 } 171 172 173 /* 174 * sadinit() - 175 * Initialize autopush freelist. 176 */ 177 void 178 sadinit() 179 { 180 struct autopush *ap; 181 int i; 182 183 /* 184 * build the autopush freelist. 185 */ 186 strpfreep = autopush; 187 ap = autopush; 188 for (i = 1; i < nautopush; i++) { 189 ap->ap_nextp = &autopush[i]; 190 ap->ap_flags = APFREE; 191 ap = ap->ap_nextp; 192 } 193 ap->ap_nextp = NULL; 194 ap->ap_flags = APFREE; 195 } 196 197 /* 198 * sadopen() - 199 * Allocate a sad device. Only one 200 * open at a time allowed per device. 201 */ 202 /* ARGSUSED */ 203 static int 204 sadopen( 205 queue_t *qp, /* pointer to read queue */ 206 dev_t *devp, /* major/minor device of stream */ 207 int flag, /* file open flags */ 208 int sflag, /* stream open flags */ 209 cred_t *credp) /* user credentials */ 210 { 211 int i; 212 213 if (sflag) /* no longer called from clone driver */ 214 return (EINVAL); 215 216 /* 217 * Both USRMIN and ADMMIN are clone interfaces. 218 */ 219 for (i = 0; i < sadcnt; i++) 220 if (saddev[i].sa_qp == NULL) 221 break; 222 if (i >= sadcnt) /* no such device */ 223 return (ENXIO); 224 225 switch (getminor(*devp)) { 226 case USRMIN: /* mere mortal */ 227 saddev[i].sa_flags = 0; 228 break; 229 230 case ADMMIN: /* privileged user */ 231 saddev[i].sa_flags = SADPRIV; 232 break; 233 234 default: 235 return (EINVAL); 236 } 237 238 saddev[i].sa_qp = qp; 239 qp->q_ptr = (caddr_t)&saddev[i]; 240 WR(qp)->q_ptr = (caddr_t)&saddev[i]; 241 242 /* 243 * NOTE: should the ADMMIN or USRMIN minors change 244 * then so should the offset of 2 below 245 * Both USRMIN and ADMMIN are clone interfaces and 246 * therefore their minor numbers (0 and 1) are reserved. 247 */ 248 *devp = makedevice(getemajor(*devp), i + 2); 249 qprocson(qp); 250 return (0); 251 } 252 253 /* 254 * sadclose() - 255 * Clean up the data structures. 256 */ 257 /* ARGSUSED */ 258 static int 259 sadclose( 260 queue_t *qp, /* pointer to read queue */ 261 int flag, /* file open flags */ 262 cred_t *credp) /* user credentials */ 263 { 264 struct saddev *sadp; 265 266 qprocsoff(qp); 267 sadp = (struct saddev *)qp->q_ptr; 268 sadp->sa_qp = NULL; 269 sadp->sa_addr = NULL; 270 qp->q_ptr = NULL; 271 WR(qp)->q_ptr = NULL; 272 return (0); 273 } 274 275 /* 276 * sadwput() - 277 * Write side put procedure. 278 */ 279 static int 280 sadwput( 281 queue_t *qp, /* pointer to write queue */ 282 mblk_t *mp) /* message pointer */ 283 { 284 struct iocblk *iocp; 285 286 switch (mp->b_datap->db_type) { 287 case M_FLUSH: 288 if (*mp->b_rptr & FLUSHR) { 289 *mp->b_rptr &= ~FLUSHW; 290 qreply(qp, mp); 291 } else 292 freemsg(mp); 293 break; 294 295 case M_IOCTL: 296 iocp = (struct iocblk *)mp->b_rptr; 297 switch (SAD_CMD(iocp->ioc_cmd)) { 298 case SAD_CMD(SAD_SAP): 299 case SAD_CMD(SAD_GAP): 300 apush_ioctl(qp, mp); 301 break; 302 303 case SAD_VML: 304 vml_ioctl(qp, mp); 305 break; 306 307 default: 308 miocnak(qp, mp, 0, EINVAL); 309 break; 310 } 311 break; 312 313 case M_IOCDATA: 314 iocp = (struct iocblk *)mp->b_rptr; 315 switch (SAD_CMD(iocp->ioc_cmd)) { 316 case SAD_CMD(SAD_SAP): 317 case SAD_CMD(SAD_GAP): 318 apush_iocdata(qp, mp); 319 break; 320 321 case SAD_VML: 322 vml_iocdata(qp, mp); 323 break; 324 325 default: 326 cmn_err(CE_WARN, 327 "sadwput: invalid ioc_cmd in case M_IOCDATA: %d", 328 iocp->ioc_cmd); 329 freemsg(mp); 330 break; 331 } 332 break; 333 334 default: 335 freemsg(mp); 336 break; 337 } /* switch (db_type) */ 338 return (0); 339 } 340 341 /* 342 * apush_ioctl() - 343 * Handle the M_IOCTL messages associated with 344 * the autopush feature. 345 */ 346 static void 347 apush_ioctl( 348 queue_t *qp, /* pointer to write queue */ 349 mblk_t *mp) /* message pointer */ 350 { 351 struct iocblk *iocp; 352 struct saddev *sadp; 353 uint_t size; 354 355 iocp = (struct iocblk *)mp->b_rptr; 356 if (iocp->ioc_count != TRANSPARENT) { 357 miocnak(qp, mp, 0, EINVAL); 358 return; 359 } 360 if (SAD_VER(iocp->ioc_cmd) > AP_VERSION) { 361 miocnak(qp, mp, 0, EINVAL); 362 return; 363 } 364 365 sadp = (struct saddev *)qp->q_ptr; 366 switch (SAD_CMD(iocp->ioc_cmd)) { 367 case SAD_CMD(SAD_SAP): 368 if (!(sadp->sa_flags & SADPRIV)) { 369 miocnak(qp, mp, 0, EPERM); 370 break; 371 } 372 /* FALLTHRU */ 373 374 case SAD_CMD(SAD_GAP): 375 sadp->sa_addr = (caddr_t)*(uintptr_t *)mp->b_cont->b_rptr; 376 if (SAD_VER(iocp->ioc_cmd) == 1) 377 size = STRAPUSH_V1_LEN; 378 else 379 size = STRAPUSH_V0_LEN; 380 mcopyin(mp, (void *)GETSTRUCT, size, NULL); 381 qreply(qp, mp); 382 break; 383 384 default: 385 ASSERT(0); 386 miocnak(qp, mp, 0, EINVAL); 387 break; 388 } /* switch (ioc_cmd) */ 389 } 390 391 /* 392 * apush_iocdata() - 393 * Handle the M_IOCDATA messages associated with 394 * the autopush feature. 395 */ 396 static void 397 apush_iocdata( 398 queue_t *qp, /* pointer to write queue */ 399 mblk_t *mp) /* message pointer */ 400 { 401 int i, ret; 402 struct copyresp *csp; 403 struct strapush *sap; 404 struct autopush *ap; 405 struct saddev *sadp; 406 uint_t size; 407 408 csp = (struct copyresp *)mp->b_rptr; 409 if (csp->cp_rval) { /* if there was an error */ 410 freemsg(mp); 411 return; 412 } 413 if (mp->b_cont) 414 /* sap needed only if mp->b_cont is set */ 415 sap = (struct strapush *)mp->b_cont->b_rptr; 416 switch (SAD_CMD(csp->cp_cmd)) { 417 case SAD_CMD(SAD_SAP): 418 switch ((long)csp->cp_private) { 419 case GETSTRUCT: 420 switch (sap->sap_cmd) { 421 case SAP_ONE: 422 case SAP_RANGE: 423 case SAP_ALL: 424 if ((sap->sap_npush == 0) || 425 (sap->sap_npush > MAXAPUSH) || 426 (sap->sap_npush > nstrpush)) { 427 428 /* invalid number of modules to push */ 429 430 miocnak(qp, mp, 0, EINVAL); 431 break; 432 } 433 if (ret = valid_major(sap->sap_major)) { 434 miocnak(qp, mp, 0, ret); 435 break; 436 } 437 if ((sap->sap_cmd == SAP_RANGE) && 438 (sap->sap_lastminor <= sap->sap_minor)) { 439 440 /* bad range */ 441 442 miocnak(qp, mp, 0, ERANGE); 443 break; 444 } 445 446 /* 447 * Validate that the specified list of 448 * modules exist. 449 */ 450 for (i = 0; i < sap->sap_npush; i++) { 451 sap->sap_list[i][FMNAMESZ] = '\0'; 452 if (fmodsw_find(sap->sap_list[i], 453 FMODSW_LOAD) == NULL) { 454 miocnak(qp, mp, 0, EINVAL); 455 return; 456 } 457 } 458 459 mutex_enter(&sad_lock); 460 if (ap_hfind(sap->sap_major, sap->sap_minor, 461 sap->sap_lastminor, sap->sap_cmd)) { 462 mutex_exit(&sad_lock); 463 464 /* already configured */ 465 466 miocnak(qp, mp, 0, EEXIST); 467 break; 468 } 469 if ((ap = ap_alloc()) == NULL) { 470 mutex_exit(&sad_lock); 471 472 /* no autopush structures */ 473 474 miocnak(qp, mp, 0, ENOSR); 475 break; 476 } 477 ap->ap_cnt++; 478 ap->ap_common = sap->sap_common; 479 if (SAD_VER(csp->cp_cmd) > 0) 480 ap->ap_anchor = sap->sap_anchor; 481 else 482 ap->ap_anchor = 0; 483 for (i = 0; i < ap->ap_npush; i++) 484 (void) strcpy(ap->ap_list[i], 485 sap->sap_list[i]); 486 ap_hadd(ap); 487 mutex_exit(&sad_lock); 488 miocack(qp, mp, 0, 0); 489 break; 490 491 case SAP_CLEAR: 492 if (ret = valid_major(sap->sap_major)) { 493 miocnak(qp, mp, 0, ret); 494 break; 495 } 496 mutex_enter(&sad_lock); 497 if ((ap = ap_hfind(sap->sap_major, 498 sap->sap_minor, sap->sap_lastminor, 499 sap->sap_cmd)) == NULL) { 500 mutex_exit(&sad_lock); 501 502 /* not configured */ 503 504 miocnak(qp, mp, 0, ENODEV); 505 break; 506 } 507 if ((ap->ap_type == SAP_RANGE) && 508 (sap->sap_minor != ap->ap_minor)) { 509 mutex_exit(&sad_lock); 510 511 /* starting minors do not match */ 512 513 miocnak(qp, mp, 0, ERANGE); 514 break; 515 } 516 if ((ap->ap_type == SAP_ALL) && 517 (sap->sap_minor != 0)) { 518 mutex_exit(&sad_lock); 519 520 /* SAP_ALL must have minor == 0 */ 521 522 miocnak(qp, mp, 0, EINVAL); 523 break; 524 } 525 ap_hrmv(ap); 526 if (--(ap->ap_cnt) <= 0) 527 ap_free(ap); 528 mutex_exit(&sad_lock); 529 miocack(qp, mp, 0, 0); 530 break; 531 532 default: 533 miocnak(qp, mp, 0, EINVAL); 534 break; 535 } /* switch (sap_cmd) */ 536 break; 537 538 default: 539 cmn_err(CE_WARN, 540 "apush_iocdata: cp_private bad in SAD_SAP: %p", 541 (void *)csp->cp_private); 542 freemsg(mp); 543 break; 544 } /* switch (cp_private) */ 545 break; 546 547 case SAD_CMD(SAD_GAP): 548 switch ((long)csp->cp_private) { 549 550 case GETSTRUCT: { 551 if (ret = valid_major(sap->sap_major)) { 552 miocnak(qp, mp, 0, ret); 553 break; 554 } 555 mutex_enter(&sad_lock); 556 if ((ap = ap_hfind(sap->sap_major, sap->sap_minor, 557 sap->sap_lastminor, SAP_ONE)) == NULL) { 558 mutex_exit(&sad_lock); 559 560 /* not configured */ 561 562 miocnak(qp, mp, 0, ENODEV); 563 break; 564 } 565 566 sap->sap_common = ap->ap_common; 567 if (SAD_VER(csp->cp_cmd) > 0) 568 sap->sap_anchor = ap->ap_anchor; 569 for (i = 0; i < ap->ap_npush; i++) 570 (void) strcpy(sap->sap_list[i], ap->ap_list[i]); 571 for (; i < MAXAPUSH; i++) 572 bzero(sap->sap_list[i], FMNAMESZ + 1); 573 mutex_exit(&sad_lock); 574 575 if (SAD_VER(csp->cp_cmd) == 1) 576 size = STRAPUSH_V1_LEN; 577 else 578 size = STRAPUSH_V0_LEN; 579 580 sadp = (struct saddev *)qp->q_ptr; 581 mcopyout(mp, (void *)GETRESULT, size, sadp->sa_addr, 582 NULL); 583 qreply(qp, mp); 584 break; 585 } 586 case GETRESULT: 587 miocack(qp, mp, 0, 0); 588 break; 589 590 default: 591 cmn_err(CE_WARN, 592 "apush_iocdata: cp_private bad case SAD_GAP: %p", 593 (void *)csp->cp_private); 594 freemsg(mp); 595 break; 596 } /* switch (cp_private) */ 597 break; 598 599 default: /* can't happen */ 600 ASSERT(0); 601 freemsg(mp); 602 break; 603 } /* switch (cp_cmd) */ 604 } 605 606 /* 607 * ap_alloc() - 608 * Allocate an autopush structure. 609 */ 610 static struct autopush * 611 ap_alloc(void) 612 { 613 struct autopush *ap; 614 615 ASSERT(MUTEX_HELD(&sad_lock)); 616 if (strpfreep == NULL) 617 return (NULL); 618 ap = strpfreep; 619 if (ap->ap_flags != APFREE) 620 cmn_err(CE_PANIC, "ap_alloc: autopush struct not free: %d", 621 ap->ap_flags); 622 strpfreep = strpfreep->ap_nextp; 623 ap->ap_nextp = NULL; 624 ap->ap_flags = APUSED; 625 return (ap); 626 } 627 628 /* 629 * ap_free() - 630 * Give an autopush structure back to the freelist. 631 */ 632 void 633 ap_free(struct autopush *ap) 634 { 635 ASSERT(MUTEX_HELD(&sad_lock)); 636 if (!(ap->ap_flags & APUSED)) 637 cmn_err(CE_PANIC, "ap_free: autopush struct not used: %d", 638 ap->ap_flags); 639 if (ap->ap_flags & APHASH) 640 cmn_err(CE_PANIC, "ap_free: autopush struct not hashed: %d", 641 ap->ap_flags); 642 ap->ap_flags = APFREE; 643 ap->ap_nextp = strpfreep; 644 strpfreep = ap; 645 } 646 647 /* 648 * ap_hadd() - 649 * Add an autopush structure to the hash list. 650 */ 651 static void 652 ap_hadd(struct autopush *ap) 653 { 654 ASSERT(MUTEX_HELD(&sad_lock)); 655 if (!(ap->ap_flags & APUSED)) 656 cmn_err(CE_PANIC, "ap_hadd: autopush struct not used: %d", 657 ap->ap_flags); 658 if (ap->ap_flags & APHASH) 659 cmn_err(CE_PANIC, "ap_hadd: autopush struct not hashed: %d", 660 ap->ap_flags); 661 ap->ap_nextp = strphash(ap->ap_major); 662 strphash(ap->ap_major) = ap; 663 ap->ap_flags |= APHASH; 664 } 665 666 /* 667 * ap_hrmv() - 668 * Remove an autopush structure from the hash list. 669 */ 670 static void 671 ap_hrmv(struct autopush *ap) 672 { 673 struct autopush *hap; 674 struct autopush *prevp = NULL; 675 676 ASSERT(MUTEX_HELD(&sad_lock)); 677 if (!(ap->ap_flags & APUSED)) 678 cmn_err(CE_PANIC, "ap_hrmv: autopush struct not used: %d", 679 ap->ap_flags); 680 if (!(ap->ap_flags & APHASH)) 681 cmn_err(CE_PANIC, "ap_hrmv: autopush struct not hashed: %d", 682 ap->ap_flags); 683 684 hap = strphash(ap->ap_major); 685 while (hap) { 686 if (ap == hap) { 687 hap->ap_flags &= ~APHASH; 688 if (prevp) 689 prevp->ap_nextp = hap->ap_nextp; 690 else 691 strphash(ap->ap_major) = hap->ap_nextp; 692 return; 693 } /* if */ 694 prevp = hap; 695 hap = hap->ap_nextp; 696 } /* while */ 697 } 698 699 /* 700 * ap_hfind() - 701 * Look for an autopush structure in the hash list 702 * based on major, minor, lastminor, and command. 703 */ 704 static struct autopush * 705 ap_hfind( 706 major_t maj, /* major device number */ 707 minor_t minor, /* minor device number */ 708 minor_t last, /* last minor device number (SAP_RANGE only) */ 709 uint_t cmd) /* who is asking */ 710 { 711 struct autopush *ap; 712 713 ASSERT(MUTEX_HELD(&sad_lock)); 714 ap = strphash(maj); 715 while (ap) { 716 if (ap->ap_major == maj) { 717 if (cmd == SAP_ALL) 718 break; 719 switch (ap->ap_type) { 720 case SAP_ALL: 721 break; 722 723 case SAP_ONE: 724 if (ap->ap_minor == minor) 725 break; 726 if ((cmd == SAP_RANGE) && 727 (ap->ap_minor >= minor) && 728 (ap->ap_minor <= last)) 729 break; 730 ap = ap->ap_nextp; 731 continue; 732 733 case SAP_RANGE: 734 if ((cmd == SAP_RANGE) && 735 (((minor >= ap->ap_minor) && 736 (minor <= ap->ap_lastminor)) || 737 ((ap->ap_minor >= minor) && 738 (ap->ap_minor <= last)))) 739 break; 740 if ((minor >= ap->ap_minor) && 741 (minor <= ap->ap_lastminor)) 742 break; 743 ap = ap->ap_nextp; 744 continue; 745 746 default: 747 ASSERT(0); 748 break; 749 } 750 break; 751 } 752 ap = ap->ap_nextp; 753 } 754 return (ap); 755 } 756 757 /* 758 * vml_ioctl() - 759 * Handle the M_IOCTL message associated with a request 760 * to validate a module list. 761 */ 762 static void 763 vml_ioctl( 764 queue_t *qp, /* pointer to write queue */ 765 mblk_t *mp) /* message pointer */ 766 { 767 struct iocblk *iocp; 768 769 iocp = (struct iocblk *)mp->b_rptr; 770 if (iocp->ioc_count != TRANSPARENT) { 771 miocnak(qp, mp, 0, EINVAL); 772 return; 773 } 774 ASSERT(iocp->ioc_cmd == SAD_VML); 775 mcopyin(mp, (void *)GETSTRUCT, 776 SIZEOF_STRUCT(str_list, iocp->ioc_flag), NULL); 777 qreply(qp, mp); 778 } 779 780 /* 781 * vml_iocdata() - 782 * Handle the M_IOCDATA messages associated with 783 * a request to validate a module list. 784 */ 785 static void 786 vml_iocdata( 787 queue_t *qp, /* pointer to write queue */ 788 mblk_t *mp) /* message pointer */ 789 { 790 long i; 791 int nmods; 792 struct copyresp *csp; 793 struct str_mlist *lp; 794 STRUCT_HANDLE(str_list, slp); 795 struct saddev *sadp; 796 797 csp = (struct copyresp *)mp->b_rptr; 798 if (csp->cp_rval) { /* if there was an error */ 799 freemsg(mp); 800 return; 801 } 802 803 ASSERT(csp->cp_cmd == SAD_VML); 804 sadp = (struct saddev *)qp->q_ptr; 805 switch ((long)csp->cp_private) { 806 case GETSTRUCT: 807 STRUCT_SET_HANDLE(slp, csp->cp_flag, 808 (struct str_list *)mp->b_cont->b_rptr); 809 nmods = STRUCT_FGET(slp, sl_nmods); 810 if (nmods <= 0) { 811 miocnak(qp, mp, 0, EINVAL); 812 break; 813 } 814 sadp->sa_addr = (caddr_t)(uintptr_t)nmods; 815 816 mcopyin(mp, (void *)GETLIST, nmods * sizeof (struct str_mlist), 817 STRUCT_FGETP(slp, sl_modlist)); 818 qreply(qp, mp); 819 break; 820 821 case GETLIST: 822 lp = (struct str_mlist *)mp->b_cont->b_rptr; 823 for (i = 0; i < (long)sadp->sa_addr; i++, lp++) { 824 lp->l_name[FMNAMESZ] = '\0'; 825 if (fmodsw_find(lp->l_name, FMODSW_LOAD) == NULL) { 826 miocack(qp, mp, 0, 1); 827 return; 828 } 829 } 830 miocack(qp, mp, 0, 0); 831 break; 832 833 default: 834 cmn_err(CE_WARN, "vml_iocdata: invalid cp_private value: %p", 835 (void *)csp->cp_private); 836 freemsg(mp); 837 break; 838 } /* switch (cp_private) */ 839 } 840 841 /* 842 * Validate a major number and also verify if 843 * it is a STREAMS device. 844 * Return values: 0 if a valid STREAMS dev 845 * error code otherwise 846 */ 847 static int 848 valid_major(major_t major) 849 { 850 int ret = 0; 851 852 if (etoimajor(major) == -1) 853 return (EINVAL); 854 855 /* 856 * attempt to load the driver 'major' and verify that 857 * it is a STREAMS driver. 858 */ 859 if (ddi_hold_driver(major) == NULL) 860 return (EINVAL); 861 862 if (!STREAMSTAB(major)) 863 ret = ENOSTR; 864 865 ddi_rele_driver(major); 866 867 return (ret); 868 } 869