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 /* 30 * IP Policy Framework config driver 31 */ 32 33 #include <sys/types.h> 34 #include <sys/cmn_err.h> 35 #include <sys/kmem.h> 36 #include <sys/errno.h> 37 #include <sys/cpuvar.h> 38 #include <sys/open.h> 39 #include <sys/stat.h> 40 #include <sys/conf.h> 41 #include <sys/ddi.h> 42 #include <sys/sunddi.h> 43 #include <sys/modctl.h> 44 #include <sys/stream.h> 45 #include <ipp/ipp.h> 46 #include <ipp/ippctl.h> 47 #include <sys/nvpair.h> 48 #include <sys/policy.h> 49 50 /* 51 * Debug switch. 52 */ 53 54 #if defined(DEBUG) 55 #define IPPCTL_DEBUG 56 #endif 57 58 /* 59 * Debug macros. 60 */ 61 62 #ifdef IPPCTL_DEBUG 63 64 #define DBG_MODLINK 0x00000001ull 65 #define DBG_DEVOPS 0x00000002ull 66 #define DBG_CBOPS 0x00000004ull 67 68 static uint64_t ippctl_debug_flags = 69 /* 70 * DBG_MODLINK | 71 * DBG_DEVOPS | 72 * DBG_CBOPS | 73 */ 74 0; 75 76 static kmutex_t debug_mutex[1]; 77 78 /*PRINTFLIKE3*/ 79 static void ippctl_debug(uint64_t, char *, char *, ...) 80 __PRINTFLIKE(3); 81 82 #define DBG0(_type, _fmt) \ 83 ippctl_debug((_type), __FN__, (_fmt)); 84 85 #define DBG1(_type, _fmt, _a1) \ 86 ippctl_debug((_type), __FN__, (_fmt), (_a1)); 87 88 #define DBG2(_type, _fmt, _a1, _a2) \ 89 ippctl_debug((_type), __FN__, (_fmt), (_a1), (_a2)); 90 91 #define DBG3(_type, _fmt, _a1, _a2, _a3) \ 92 ippctl_debug((_type), __FN__, (_fmt), (_a1), (_a2), \ 93 (_a3)); 94 95 #define DBG4(_type, _fmt, _a1, _a2, _a3, _a4) \ 96 ippctl_debug((_type), __FN__, (_fmt), (_a1), (_a2), \ 97 (_a3), (_a4)); 98 99 #define DBG5(_type, _fmt, _a1, _a2, _a3, _a4, _a5) \ 100 ippctl_debug((_type), __FN__, (_fmt), (_a1), (_a2), \ 101 (_a3), (_a4), (_a5)); 102 103 #else /* IPPCTL_DBG */ 104 105 #define DBG0(_type, _fmt) 106 #define DBG1(_type, _fmt, _a1) 107 #define DBG2(_type, _fmt, _a1, _a2) 108 #define DBG3(_type, _fmt, _a1, _a2, _a3) 109 #define DBG4(_type, _fmt, _a1, _a2, _a3, _a4) 110 #define DBG5(_type, _fmt, _a1, _a2, _a3, _a4, _a5) 111 112 #endif /* IPPCTL_DBG */ 113 114 /* 115 * cb_ops 116 */ 117 118 static int ippctl_open(dev_t *, int, int, cred_t *); 119 static int ippctl_close(dev_t, int, int, cred_t *); 120 static int ippctl_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 121 122 static struct cb_ops ippctl_cb_ops = { 123 ippctl_open, /* cb_open */ 124 ippctl_close, /* cb_close */ 125 nodev, /* cb_strategy */ 126 nodev, /* cb_print */ 127 nodev, /* cb_dump */ 128 nodev, /* cb_read */ 129 nodev, /* cb_write */ 130 ippctl_ioctl, /* cb_ioctl */ 131 nodev, /* cb_devmap */ 132 nodev, /* cb_mmap */ 133 nodev, /* cb_segmap */ 134 nochpoll, /* cb_chpoll */ 135 ddi_prop_op, /* cb_prop_op */ 136 0, /* cb_str */ 137 D_NEW | D_MP, /* cb_flag */ 138 CB_REV, /* cb_rev */ 139 nodev, /* cb_aread */ 140 nodev /* cb_awrite */ 141 }; 142 143 /* 144 * dev_ops 145 */ 146 147 static int ippctl_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 148 static int ippctl_attach(dev_info_t *, ddi_attach_cmd_t); 149 static int ippctl_detach(dev_info_t *, ddi_detach_cmd_t); 150 151 static struct dev_ops ippctl_dev_ops = { 152 DEVO_REV, /* devo_rev, */ 153 0, /* devo_refcnt */ 154 ippctl_info, /* devo_getinfo */ 155 nulldev, /* devo_identify */ 156 nulldev, /* devo_probe */ 157 ippctl_attach, /* devo_attach */ 158 ippctl_detach, /* devo_detach */ 159 nodev, /* devo_reset */ 160 &ippctl_cb_ops, /* devo_cb_ops */ 161 (struct bus_ops *)0 /* devo_bus_ops */ 162 }; 163 164 static struct modldrv modldrv = { 165 &mod_driverops, 166 "IP Policy Configuration Driver v%I%", 167 &ippctl_dev_ops, 168 }; 169 170 static struct modlinkage modlinkage = { 171 MODREV_1, 172 &modldrv, 173 NULL 174 }; 175 176 /* 177 * Local definitions, types and prototypes. 178 */ 179 180 #define MAXUBUFLEN (1 << 16) 181 182 #define FREE_TEXT(_string) \ 183 kmem_free((_string), strlen(_string) + 1) 184 185 #define FREE_TEXT_ARRAY(_array, _nelt) \ 186 { \ 187 int j; \ 188 \ 189 for (j = 0; j < (_nelt); j++) \ 190 if ((_array)[j] != NULL) \ 191 FREE_TEXT((_array)[j]); \ 192 kmem_free((_array), (_nelt) * sizeof (char *)); \ 193 } 194 195 typedef struct ippctl_buf ippctl_buf_t; 196 197 struct ippctl_buf { 198 char *buf; 199 size_t buflen; 200 }; 201 202 static int ippctl_copyin(caddr_t, int, char **, size_t *); 203 static int ippctl_copyout(caddr_t, int, char *, size_t); 204 static int ippctl_extract_op(nvlist_t *, uint8_t *); 205 static int ippctl_extract_aname(nvlist_t *, char **); 206 static int ippctl_extract_modname(nvlist_t *, char **); 207 static int ippctl_attach_modname(nvlist_t *nvlp, char *val); 208 static int ippctl_attach_modname_array(nvlist_t *nvlp, char **val, int); 209 static int ippctl_attach_aname_array(nvlist_t *nvlp, char **val, int); 210 static int ippctl_extract_flags(nvlist_t *, ipp_flags_t *); 211 static int ippctl_cmd(char *, size_t, size_t *); 212 static int ippctl_action_create(char *, char *, nvlist_t *, ipp_flags_t); 213 static int ippctl_action_destroy(char *, ipp_flags_t); 214 static int ippctl_action_modify(char *, nvlist_t *, ipp_flags_t); 215 static int ippctl_action_info(char *, ipp_flags_t); 216 static int ippctl_action_mod(char *); 217 static int ippctl_list_mods(void); 218 static int ippctl_mod_list_actions(char *); 219 static int ippctl_data(char **, size_t *, size_t *); 220 static void ippctl_flush(void); 221 static int ippctl_add_nvlist(nvlist_t *, int); 222 static int ippctl_callback(nvlist_t *, void *); 223 static int ippctl_set_rc(int); 224 static void ippctl_alloc(int); 225 static void ippctl_realloc(void); 226 static void ippctl_free(void); 227 228 /* 229 * Global data 230 */ 231 232 static dev_info_t *ippctl_dip = NULL; 233 static kmutex_t ippctl_lock; 234 static boolean_t ippctl_busy; 235 static ippctl_buf_t *ippctl_array = NULL; 236 static int ippctl_limit = -1; 237 static int ippctl_rindex = -1; 238 static int ippctl_windex = -1; 239 240 /* 241 * Module linkage functions 242 */ 243 244 #define __FN__ "_init" 245 int 246 _init( 247 void) 248 { 249 int rc; 250 251 if ((rc = mod_install(&modlinkage)) != 0) { 252 DBG0(DBG_MODLINK, "mod_install failed\n"); 253 return (rc); 254 } 255 256 return (rc); 257 } 258 #undef __FN__ 259 260 #define __FN__ "_fini" 261 int 262 _fini( 263 void) 264 { 265 int rc; 266 267 if ((rc = mod_remove(&modlinkage)) == 0) { 268 return (rc); 269 } 270 271 DBG0(DBG_MODLINK, "mod_remove failed\n"); 272 return (rc); 273 } 274 #undef __FN__ 275 276 #define __FN__ "_info" 277 int 278 _info( 279 struct modinfo *modinfop) 280 { 281 DBG0(DBG_MODLINK, "calling mod_info\n"); 282 return (mod_info(&modlinkage, modinfop)); 283 } 284 #undef __FN__ 285 286 /* 287 * Driver interface functions (dev_ops and cb_ops) 288 */ 289 290 #define __FN__ "ippctl_info" 291 /*ARGSUSED*/ 292 static int 293 ippctl_info( 294 dev_info_t *dip, 295 ddi_info_cmd_t cmd, 296 void *arg, 297 void **result) 298 { 299 int rc = DDI_FAILURE; 300 301 switch (cmd) { 302 case DDI_INFO_DEVT2INSTANCE: 303 *result = (void *)0; /* Single instance driver */ 304 rc = DDI_SUCCESS; 305 break; 306 case DDI_INFO_DEVT2DEVINFO: 307 *result = (void *)ippctl_dip; 308 rc = DDI_SUCCESS; 309 break; 310 default: 311 break; 312 } 313 314 return (rc); 315 } 316 #undef __FN__ 317 318 #define __FN__ "ippctl_attach" 319 static int 320 ippctl_attach( 321 dev_info_t *dip, 322 ddi_attach_cmd_t cmd) 323 { 324 switch (cmd) { 325 case DDI_ATTACH: 326 break; 327 case DDI_PM_RESUME: 328 /*FALLTHRU*/ 329 case DDI_RESUME: 330 /*FALLTHRU*/ 331 default: 332 return (DDI_FAILURE); 333 } 334 335 DBG0(DBG_DEVOPS, "DDI_ATTACH\n"); 336 337 /* 338 * This is strictly a single instance driver. 339 */ 340 341 if (ippctl_dip != NULL) 342 return (DDI_FAILURE); 343 344 /* 345 * Create minor node. 346 */ 347 348 if (ddi_create_minor_node(dip, "ctl", S_IFCHR, 0, 349 DDI_PSEUDO, 0) != DDI_SUCCESS) 350 return (DDI_FAILURE); 351 352 /* 353 * No need for per-instance structure, just store vital data in 354 * globals. 355 */ 356 357 ippctl_dip = dip; 358 mutex_init(&ippctl_lock, NULL, MUTEX_DRIVER, NULL); 359 ippctl_busy = B_FALSE; 360 361 return (DDI_SUCCESS); 362 } 363 #undef __FN__ 364 365 #define __FN__ "ippctl_detach" 366 /*ARGSUSED*/ 367 static int 368 ippctl_detach( 369 dev_info_t *dip, 370 ddi_detach_cmd_t cmd) 371 { 372 switch (cmd) { 373 case DDI_DETACH: 374 break; 375 case DDI_PM_SUSPEND: 376 /*FALLTHRU*/ 377 case DDI_SUSPEND: 378 /*FALLTHRU*/ 379 default: 380 return (DDI_FAILURE); 381 } 382 383 DBG0(DBG_DEVOPS, "DDI_DETACH\n"); 384 385 ASSERT(dip == ippctl_dip); 386 387 ddi_remove_minor_node(dip, NULL); 388 mutex_destroy(&ippctl_lock); 389 ippctl_dip = NULL; 390 391 return (DDI_SUCCESS); 392 } 393 #undef __FN__ 394 395 #define __FN__ "ippctl_open" 396 /*ARGSUSED*/ 397 static int 398 ippctl_open( 399 dev_t *devp, 400 int flag, 401 int otyp, 402 cred_t *credp) 403 { 404 minor_t minor = getminor(*devp); 405 #define LIMIT 4 406 407 DBG0(DBG_CBOPS, "open\n"); 408 409 /* 410 * Only allow privileged users to open our device. 411 */ 412 413 if (secpolicy_net_config(credp, B_FALSE) != 0) { 414 DBG0(DBG_CBOPS, "not privileged user\n"); 415 return (EPERM); 416 } 417 418 /* 419 * Sanity check other arguments. 420 */ 421 422 if (minor != 0) { 423 DBG0(DBG_CBOPS, "bad minor\n"); 424 return (ENXIO); 425 } 426 427 if (otyp != OTYP_CHR) { 428 DBG0(DBG_CBOPS, "bad device type\n"); 429 return (EINVAL); 430 } 431 432 /* 433 * This is also a single dev_t driver. 434 */ 435 436 mutex_enter(&ippctl_lock); 437 if (ippctl_busy) { 438 mutex_exit(&ippctl_lock); 439 return (EBUSY); 440 } 441 ippctl_busy = B_TRUE; 442 mutex_exit(&ippctl_lock); 443 444 /* 445 * Allocate data buffer array (starting with length LIMIT, defined 446 * at the start of this function). 447 */ 448 449 ippctl_alloc(LIMIT); 450 451 DBG0(DBG_CBOPS, "success\n"); 452 453 return (0); 454 455 #undef LIMIT 456 } 457 #undef __FN__ 458 459 #define __FN__ "ippctl_close" 460 /*ARGSUSED*/ 461 static int 462 ippctl_close( 463 dev_t dev, 464 int flag, 465 int otyp, 466 cred_t *credp) 467 { 468 minor_t minor = getminor(dev); 469 470 DBG0(DBG_CBOPS, "close\n"); 471 472 ASSERT(minor == 0); 473 474 /* 475 * Free the data buffer array. 476 */ 477 478 ippctl_free(); 479 480 mutex_enter(&ippctl_lock); 481 ippctl_busy = B_FALSE; 482 mutex_exit(&ippctl_lock); 483 484 DBG0(DBG_CBOPS, "success\n"); 485 486 return (0); 487 } 488 #undef __FN__ 489 490 #define __FN__ "ippctl_ioctl" 491 static int 492 ippctl_ioctl( 493 dev_t dev, 494 int cmd, 495 intptr_t arg, 496 int mode, 497 cred_t *credp, 498 int *rvalp) 499 { 500 minor_t minor = getminor(dev); 501 char *cbuf; 502 char *dbuf; 503 size_t cbuflen; 504 size_t dbuflen; 505 size_t nextbuflen; 506 int rc; 507 508 /* 509 * Paranoia check. 510 */ 511 512 if (secpolicy_net_config(credp, B_FALSE) != 0) { 513 DBG0(DBG_CBOPS, "not privileged user\n"); 514 return (EPERM); 515 } 516 517 if (minor != 0) { 518 DBG0(DBG_CBOPS, "bad minor\n"); 519 return (ENXIO); 520 } 521 522 switch (cmd) { 523 case IPPCTL_CMD: 524 DBG0(DBG_CBOPS, "command\n"); 525 526 /* 527 * Copy in the command buffer from user space. 528 */ 529 530 if ((rc = ippctl_copyin((caddr_t)arg, mode, &cbuf, 531 &cbuflen)) != 0) 532 break; 533 534 /* 535 * Execute the command. 536 */ 537 538 rc = ippctl_cmd(cbuf, cbuflen, &nextbuflen); 539 540 /* 541 * Pass back the length of the first data buffer. 542 */ 543 544 DBG1(DBG_CBOPS, "nextbuflen = %lu\n", nextbuflen); 545 *rvalp = nextbuflen; 546 547 /* 548 * Free the kernel copy of the command buffer. 549 */ 550 551 kmem_free(cbuf, cbuflen); 552 break; 553 554 case IPPCTL_DATA: 555 DBG0(DBG_CBOPS, "data\n"); 556 557 /* 558 * Grab the next data buffer from the array of pending 559 * buffers. 560 */ 561 562 if ((rc = ippctl_data(&dbuf, &dbuflen, &nextbuflen)) != 0) 563 break; 564 565 /* 566 * Copy it out to user space. 567 */ 568 569 rc = ippctl_copyout((caddr_t)arg, mode, dbuf, dbuflen); 570 571 /* 572 * Pass back the length of the next data buffer. 573 */ 574 575 DBG1(DBG_CBOPS, "nextbuflen = %lu\n", nextbuflen); 576 *rvalp = nextbuflen; 577 break; 578 579 default: 580 DBG0(DBG_CBOPS, "unrecognized ioctl\n"); 581 rc = EINVAL; 582 break; 583 } 584 585 DBG1(DBG_CBOPS, "rc = %d\n", rc); 586 return (rc); 587 } 588 #undef __FN__ 589 590 /* 591 * Local functions 592 */ 593 594 #define __FN__ "ippctl_copyin" 595 static int 596 ippctl_copyin( 597 caddr_t arg, 598 int mode, 599 char **kbufp, 600 size_t *kbuflenp) 601 { 602 ippctl_ioctl_t iioc; 603 caddr_t ubuf; 604 char *kbuf; 605 size_t ubuflen; 606 607 DBG0(DBG_CBOPS, "copying in ioctl structure\n"); 608 609 /* 610 * Copy in the ioctl structure from user-space, converting from 32-bit 611 * as necessary. 612 */ 613 614 #ifdef _MULTI_DATAMODEL 615 switch (ddi_model_convert_from(mode & FMODELS)) { 616 case DDI_MODEL_ILP32: 617 { 618 ippctl_ioctl32_t iioc32; 619 620 DBG0(DBG_CBOPS, "converting from 32-bit\n"); 621 622 if (ddi_copyin(arg, (caddr_t)&iioc32, 623 sizeof (ippctl_ioctl32_t), mode) != 0) 624 return (EFAULT); 625 626 ubuf = (caddr_t)(uintptr_t)iioc32.ii32_buf; 627 ubuflen = (size_t)iioc32.ii32_buflen; 628 } 629 break; 630 case DDI_MODEL_NONE: 631 if (ddi_copyin(arg, (caddr_t)&iioc, sizeof (ippctl_ioctl_t), 632 mode) != 0) 633 return (EFAULT); 634 635 ubuf = iioc.ii_buf; 636 ubuflen = iioc.ii_buflen; 637 break; 638 default: 639 return (EFAULT); 640 } 641 #else /* _MULTI_DATAMODEL */ 642 if (ddi_copyin(arg, (caddr_t)&iioc, sizeof (ippctl_ioctl_t), 643 mode) != 0) 644 return (EFAULT); 645 646 ubuf = iioc.ii_buf; 647 ubuflen = iioc.ii_buflen; 648 #endif /* _MULTI_DATAMODEL */ 649 650 DBG1(DBG_CBOPS, "ubuf = 0x%p\n", (void *)ubuf); 651 DBG1(DBG_CBOPS, "ubuflen = %lu\n", ubuflen); 652 653 /* 654 * Sanity check the command buffer information. 655 */ 656 657 if (ubuflen == 0 || ubuf == NULL) 658 return (EINVAL); 659 if (ubuflen > MAXUBUFLEN) 660 return (E2BIG); 661 662 /* 663 * Allocate some memory for the command buffer and copy it in. 664 */ 665 666 kbuf = kmem_zalloc(ubuflen, KM_SLEEP); 667 DBG0(DBG_CBOPS, "copying in nvlist\n"); 668 if (ddi_copyin(ubuf, (caddr_t)kbuf, ubuflen, mode) != 0) { 669 kmem_free(kbuf, ubuflen); 670 return (EFAULT); 671 } 672 673 *kbufp = kbuf; 674 *kbuflenp = ubuflen; 675 return (0); 676 } 677 #undef __FN__ 678 679 #define __FN__ "ippctl_copyout" 680 static int 681 ippctl_copyout( 682 caddr_t arg, 683 int mode, 684 char *kbuf, 685 size_t kbuflen) 686 { 687 ippctl_ioctl_t iioc; 688 caddr_t ubuf; 689 int ubuflen; 690 691 DBG0(DBG_CBOPS, "copying out ioctl structure\n"); 692 693 /* 694 * Copy in the ioctl structure from user-space, converting from 32-bit 695 * as necessary. 696 */ 697 698 #ifdef _MULTI_DATAMODEL 699 switch (ddi_model_convert_from(mode & FMODELS)) { 700 case DDI_MODEL_ILP32: 701 { 702 ippctl_ioctl32_t iioc32; 703 704 if (ddi_copyin(arg, (caddr_t)&iioc32, 705 sizeof (ippctl_ioctl32_t), mode) != 0) 706 return (EFAULT); 707 708 ubuf = (caddr_t)(uintptr_t)iioc32.ii32_buf; 709 ubuflen = iioc32.ii32_buflen; 710 } 711 break; 712 case DDI_MODEL_NONE: 713 if (ddi_copyin(arg, (caddr_t)&iioc, sizeof (ippctl_ioctl_t), 714 mode) != 0) 715 return (EFAULT); 716 717 ubuf = iioc.ii_buf; 718 ubuflen = iioc.ii_buflen; 719 break; 720 default: 721 return (EFAULT); 722 } 723 #else /* _MULTI_DATAMODEL */ 724 if (ddi_copyin(arg, (caddr_t)&iioc, sizeof (ippctl_ioctl_t), 725 mode) != 0) 726 return (EFAULT); 727 728 ubuf = iioc.ii_buf; 729 ubuflen = iioc.ii_buflen; 730 #endif /* _MULTI_DATAMODEL */ 731 732 DBG1(DBG_CBOPS, "ubuf = 0x%p\n", (void *)ubuf); 733 DBG1(DBG_CBOPS, "ubuflen = %d\n", ubuflen); 734 735 /* 736 * Sanity check the data buffer details. 737 */ 738 739 if (ubuflen == 0 || ubuf == NULL) 740 return (EINVAL); 741 742 if (ubuflen < kbuflen) 743 return (ENOSPC); 744 if (ubuflen > MAXUBUFLEN) 745 return (E2BIG); 746 747 /* 748 * Copy out the data buffer to user space. 749 */ 750 751 DBG0(DBG_CBOPS, "copying out nvlist\n"); 752 if (ddi_copyout((caddr_t)kbuf, ubuf, kbuflen, mode) != 0) 753 return (EFAULT); 754 755 return (0); 756 } 757 #undef __FN__ 758 759 #define __FN__ "ippctl_extract_op" 760 static int 761 ippctl_extract_op( 762 nvlist_t *nvlp, 763 uint8_t *valp) 764 { 765 int rc; 766 767 /* 768 * Look-up and remove the opcode passed from libipp from the 769 * nvlist. 770 */ 771 772 if ((rc = nvlist_lookup_byte(nvlp, IPPCTL_OP, valp)) != 0) 773 return (rc); 774 775 (void) nvlist_remove_all(nvlp, IPPCTL_OP); 776 return (0); 777 } 778 #undef __FN__ 779 780 #define __FN__ "ippctl_extract_aname" 781 static int 782 ippctl_extract_aname( 783 nvlist_t *nvlp, 784 char **valp) 785 { 786 int rc; 787 char *ptr; 788 789 /* 790 * Look-up and remove the action name passed from libipp from the 791 * nvlist. 792 */ 793 794 if ((rc = nvlist_lookup_string(nvlp, IPPCTL_ANAME, &ptr)) != 0) 795 return (rc); 796 797 *valp = kmem_alloc(strlen(ptr) + 1, KM_SLEEP); 798 (void) strcpy(*valp, ptr); 799 (void) nvlist_remove_all(nvlp, IPPCTL_ANAME); 800 return (0); 801 } 802 #undef __FN__ 803 804 #define __FN__ "ippctl_extract_modname" 805 static int 806 ippctl_extract_modname( 807 nvlist_t *nvlp, 808 char **valp) 809 { 810 int rc; 811 char *ptr; 812 813 /* 814 * Look-up and remove the module name passed from libipp from the 815 * nvlist. 816 */ 817 818 if ((rc = nvlist_lookup_string(nvlp, IPPCTL_MODNAME, &ptr)) != 0) 819 return (rc); 820 821 *valp = kmem_alloc(strlen(ptr) + 1, KM_SLEEP); 822 (void) strcpy(*valp, ptr); 823 (void) nvlist_remove_all(nvlp, IPPCTL_MODNAME); 824 return (0); 825 } 826 #undef __FN__ 827 828 #define __FN__ "ippctl_attach_modname" 829 static int 830 ippctl_attach_modname( 831 nvlist_t *nvlp, 832 char *modname) 833 { 834 /* 835 * Add a module name to an nvlist for passing back to user 836 * space. 837 */ 838 839 return (nvlist_add_string(nvlp, IPPCTL_MODNAME, modname)); 840 } 841 #undef __FN__ 842 843 #define __FN__ "ippctl_attach_modname_array" 844 static int 845 ippctl_attach_modname_array( 846 nvlist_t *nvlp, 847 char **modname_array, 848 int nelt) 849 { 850 /* 851 * Add a module name array to an nvlist for passing back to user 852 * space. 853 */ 854 855 return (nvlist_add_string_array(nvlp, IPPCTL_MODNAME_ARRAY, 856 modname_array, nelt)); 857 } 858 #undef __FN__ 859 860 #define __FN__ "ippctl_attach_aname_array" 861 static int 862 ippctl_attach_aname_array( 863 nvlist_t *nvlp, 864 char **aname_array, 865 int nelt) 866 { 867 /* 868 * Add an action name array to an nvlist for passing back to user 869 * space. 870 */ 871 872 return (nvlist_add_string_array(nvlp, IPPCTL_ANAME_ARRAY, 873 aname_array, nelt)); 874 } 875 #undef __FN__ 876 877 #define __FN__ "ippctl_extract_flags" 878 static int 879 ippctl_extract_flags( 880 nvlist_t *nvlp, 881 ipp_flags_t *valp) 882 { 883 int rc; 884 885 /* 886 * Look-up and remove the flags passed from libipp from the 887 * nvlist. 888 */ 889 890 if ((rc = nvlist_lookup_uint32(nvlp, IPPCTL_FLAGS, 891 (uint32_t *)valp)) != 0) 892 return (rc); 893 894 (void) nvlist_remove_all(nvlp, IPPCTL_FLAGS); 895 return (0); 896 } 897 #undef __FN__ 898 899 #define __FN__ "ippctl_cmd" 900 static int 901 ippctl_cmd( 902 char *cbuf, 903 size_t cbuflen, 904 size_t *nextbuflenp) 905 { 906 nvlist_t *nvlp = NULL; 907 int rc; 908 char *aname = NULL; 909 char *modname = NULL; 910 ipp_flags_t flags; 911 uint8_t op; 912 913 /* 914 * Start a new command cycle by flushing any previous data buffers. 915 */ 916 917 ippctl_flush(); 918 *nextbuflenp = 0; 919 920 /* 921 * Unpack the nvlist from the command buffer. 922 */ 923 924 if ((rc = nvlist_unpack(cbuf, cbuflen, &nvlp, KM_SLEEP)) != 0) 925 return (rc); 926 927 /* 928 * Extract the opcode to find out what we should do. 929 */ 930 931 if ((rc = ippctl_extract_op(nvlp, &op)) != 0) { 932 nvlist_free(nvlp); 933 return (rc); 934 } 935 936 switch (op) { 937 case IPPCTL_OP_ACTION_CREATE: 938 /* 939 * Create a new action. 940 */ 941 942 DBG0(DBG_CBOPS, "op = IPPCTL_OP_ACTION_CREATE\n"); 943 944 /* 945 * Extract the module name, action name and flags from the 946 * nvlist. 947 */ 948 949 if ((rc = ippctl_extract_modname(nvlp, &modname)) != 0) { 950 nvlist_free(nvlp); 951 return (rc); 952 } 953 954 if ((rc = ippctl_extract_aname(nvlp, &aname)) != 0) { 955 FREE_TEXT(modname); 956 nvlist_free(nvlp); 957 return (rc); 958 } 959 960 if ((rc = ippctl_extract_flags(nvlp, &flags)) != 0) { 961 FREE_TEXT(aname); 962 FREE_TEXT(modname); 963 nvlist_free(nvlp); 964 return (rc); 965 } 966 967 968 rc = ippctl_action_create(modname, aname, nvlp, flags); 969 break; 970 971 case IPPCTL_OP_ACTION_MODIFY: 972 973 /* 974 * Modify an existing action. 975 */ 976 977 DBG0(DBG_CBOPS, "op = IPPCTL_OP_ACTION_MODIFY\n"); 978 979 /* 980 * Extract the action name and flags from the nvlist. 981 */ 982 983 if ((rc = ippctl_extract_aname(nvlp, &aname)) != 0) { 984 nvlist_free(nvlp); 985 return (rc); 986 } 987 988 if ((rc = ippctl_extract_flags(nvlp, &flags)) != 0) { 989 FREE_TEXT(aname); 990 nvlist_free(nvlp); 991 return (rc); 992 } 993 994 rc = ippctl_action_modify(aname, nvlp, flags); 995 break; 996 997 case IPPCTL_OP_ACTION_DESTROY: 998 999 /* 1000 * Destroy an action. 1001 */ 1002 1003 DBG0(DBG_CBOPS, "op = IPPCTL_OP_ACTION_DESTROY\n"); 1004 1005 /* 1006 * Extract the action name and flags from the nvlist. 1007 */ 1008 1009 if ((rc = ippctl_extract_aname(nvlp, &aname)) != 0) { 1010 nvlist_free(nvlp); 1011 return (rc); 1012 } 1013 1014 if ((rc = ippctl_extract_flags(nvlp, &flags)) != 0) { 1015 FREE_TEXT(aname); 1016 nvlist_free(nvlp); 1017 return (rc); 1018 } 1019 1020 nvlist_free(nvlp); 1021 rc = ippctl_action_destroy(aname, flags); 1022 break; 1023 1024 case IPPCTL_OP_ACTION_INFO: 1025 1026 /* 1027 * Retrive the configuration of an action. 1028 */ 1029 1030 DBG0(DBG_CBOPS, "op = IPPCTL_OP_ACTION_INFO\n"); 1031 1032 /* 1033 * Extract the action name and flags from the nvlist. 1034 */ 1035 1036 if ((rc = ippctl_extract_aname(nvlp, &aname)) != 0) { 1037 nvlist_free(nvlp); 1038 return (rc); 1039 } 1040 1041 if ((rc = ippctl_extract_flags(nvlp, &flags)) != 0) { 1042 nvlist_free(nvlp); 1043 FREE_TEXT(aname); 1044 return (rc); 1045 } 1046 1047 nvlist_free(nvlp); 1048 rc = ippctl_action_info(aname, flags); 1049 break; 1050 1051 case IPPCTL_OP_ACTION_MOD: 1052 1053 /* 1054 * Find the module that implements a given action. 1055 */ 1056 1057 DBG0(DBG_CBOPS, "op = IPPCTL_OP_ACTION_MOD\n"); 1058 1059 /* 1060 * Extract the action name from the nvlist. 1061 */ 1062 1063 if ((rc = ippctl_extract_aname(nvlp, &aname)) != 0) { 1064 nvlist_free(nvlp); 1065 return (rc); 1066 } 1067 1068 nvlist_free(nvlp); 1069 rc = ippctl_action_mod(aname); 1070 break; 1071 1072 case IPPCTL_OP_LIST_MODS: 1073 1074 /* 1075 * List all the modules. 1076 */ 1077 1078 DBG0(DBG_CBOPS, "op = IPPCTL_OP_LIST_MODS\n"); 1079 1080 nvlist_free(nvlp); 1081 rc = ippctl_list_mods(); 1082 break; 1083 1084 case IPPCTL_OP_MOD_LIST_ACTIONS: 1085 1086 /* 1087 * List all the actions for a given module. 1088 */ 1089 1090 DBG0(DBG_CBOPS, "op = IPPCTL_OP_LIST_MODS\n"); 1091 1092 if ((rc = ippctl_extract_modname(nvlp, &modname)) != 0) { 1093 nvlist_free(nvlp); 1094 return (rc); 1095 } 1096 1097 nvlist_free(nvlp); 1098 rc = ippctl_mod_list_actions(modname); 1099 break; 1100 1101 default: 1102 1103 /* 1104 * Unrecognized opcode. 1105 */ 1106 1107 nvlist_free(nvlp); 1108 rc = EINVAL; 1109 break; 1110 } 1111 1112 /* 1113 * The length of buffer that we need to notify back to libipp with 1114 * the command ioctl's return is the length of the first data buffer 1115 * in the array. We only expact to pass back data buffers if the 1116 * operation succeeds (NOTE: this does not mean the kernel call has 1117 * to succeed, merely that we successfully issued it and processed 1118 * the results). 1119 */ 1120 1121 if (rc == 0) 1122 *nextbuflenp = ippctl_array[0].buflen; 1123 1124 return (rc); 1125 } 1126 #undef __FN__ 1127 1128 #define __FN__ "ippctl_action_create" 1129 static int 1130 ippctl_action_create( 1131 char *modname, 1132 char *aname, 1133 nvlist_t *nvlp, 1134 ipp_flags_t flags) 1135 { 1136 int ipp_rc; 1137 int rc; 1138 ipp_mod_id_t mid; 1139 ipp_action_id_t aid; 1140 1141 /* 1142 * Look up the module id from the name and create the new 1143 * action. 1144 */ 1145 1146 mid = ipp_mod_lookup(modname); 1147 FREE_TEXT(modname); 1148 1149 ipp_rc = ipp_action_create(mid, aname, &nvlp, flags, &aid); 1150 FREE_TEXT(aname); 1151 1152 /* 1153 * Add an nvlist containing the kernel return code to the 1154 * set of nvlists to pass back to libipp. 1155 */ 1156 1157 if ((rc = ippctl_set_rc(ipp_rc)) != 0) { 1158 if (nvlp != NULL) { 1159 nvlist_free(nvlp); 1160 if (ipp_action_destroy(aid, 0) != 0) { 1161 cmn_err(CE_PANIC, 1162 "ippctl: unrecoverable error (aid = %d)", 1163 aid); 1164 /*NOTREACHED*/ 1165 } 1166 } 1167 return (rc); 1168 } 1169 1170 /* 1171 * If the module passed back an nvlist, add this as 1172 * well. 1173 */ 1174 1175 if (nvlp != NULL) { 1176 rc = ippctl_callback(nvlp, NULL); 1177 nvlist_free(nvlp); 1178 } else 1179 rc = 0; 1180 1181 return (rc); 1182 } 1183 #undef __FN__ 1184 1185 #define __FN__ "ippctl_action_destroy" 1186 static int 1187 ippctl_action_destroy( 1188 char *aname, 1189 ipp_flags_t flags) 1190 { 1191 ipp_action_id_t aid; 1192 int ipp_rc; 1193 int rc; 1194 1195 /* 1196 * Look up the action id and destroy the action. 1197 */ 1198 1199 aid = ipp_action_lookup(aname); 1200 FREE_TEXT(aname); 1201 1202 ipp_rc = ipp_action_destroy(aid, flags); 1203 1204 /* 1205 * Add an nvlist containing the kernel return code to the 1206 * set of nvlists to pass back to libipp. 1207 */ 1208 1209 if ((rc = ippctl_set_rc(ipp_rc)) != 0) 1210 return (rc); 1211 1212 /* 1213 * There's no more information to pass back. 1214 */ 1215 1216 return (0); 1217 } 1218 #undef __FN__ 1219 1220 #define __FN__ "ippctl_action_modify" 1221 static int 1222 ippctl_action_modify( 1223 char *aname, 1224 nvlist_t *nvlp, 1225 ipp_flags_t flags) 1226 { 1227 ipp_action_id_t aid; 1228 int ipp_rc; 1229 int rc; 1230 1231 /* 1232 * Look up the action id and modify the action. 1233 */ 1234 1235 aid = ipp_action_lookup(aname); 1236 FREE_TEXT(aname); 1237 1238 ipp_rc = ipp_action_modify(aid, &nvlp, flags); 1239 1240 /* 1241 * Add an nvlist containing the kernel return code to the 1242 * set of nvlists to pass back to libipp. 1243 */ 1244 1245 if ((rc = ippctl_set_rc(ipp_rc)) != 0) { 1246 if (nvlp != NULL) 1247 nvlist_free(nvlp); 1248 return (rc); 1249 } 1250 1251 /* 1252 * If the module passed back an nvlist, add this as 1253 * well. 1254 */ 1255 1256 if (nvlp != NULL) { 1257 rc = ippctl_callback(nvlp, NULL); 1258 nvlist_free(nvlp); 1259 } else 1260 rc = 0; 1261 1262 return (rc); 1263 } 1264 #undef __FN__ 1265 1266 #define __FN__ "ippctl_action_info" 1267 static int 1268 ippctl_action_info( 1269 char *aname, 1270 ipp_flags_t flags) 1271 { 1272 ipp_action_id_t aid; 1273 int ipp_rc; 1274 int rc; 1275 1276 /* 1277 * Look up the action and call the information retrieval 1278 * entry point. 1279 * 1280 * NOTE: The callback function that is passed in packs and 1281 * stores each of the nvlists it is called with in the array 1282 * that will be passed back to libipp. 1283 */ 1284 1285 aid = ipp_action_lookup(aname); 1286 FREE_TEXT(aname); 1287 1288 ipp_rc = ipp_action_info(aid, ippctl_callback, NULL, flags); 1289 1290 /* 1291 * Add an nvlist containing the kernel return code to the 1292 * set of nvlists to pass back to libipp. 1293 */ 1294 1295 if ((rc = ippctl_set_rc(ipp_rc)) != 0) 1296 return (rc); 1297 1298 /* 1299 * There's no more information to pass back. 1300 */ 1301 1302 return (0); 1303 } 1304 #undef __FN__ 1305 1306 #define __FN__ "ippctl_action_mod" 1307 static int 1308 ippctl_action_mod( 1309 char *aname) 1310 { 1311 ipp_mod_id_t mid; 1312 ipp_action_id_t aid; 1313 char *modname; 1314 nvlist_t *nvlp; 1315 int ipp_rc; 1316 int rc; 1317 1318 /* 1319 * Look up the action id and get the id of the module that 1320 * implements the action. If that succeeds then look up the 1321 * name of the module. 1322 */ 1323 1324 aid = ipp_action_lookup(aname); 1325 FREE_TEXT(aname); 1326 1327 if ((ipp_rc = ipp_action_mod(aid, &mid)) == 0) 1328 ipp_rc = ipp_mod_name(mid, &modname); 1329 1330 /* 1331 * Add an nvlist containing the kernel return code to the 1332 * set of nvlists to pass back to libipp. 1333 */ 1334 1335 if ((rc = ippctl_set_rc(ipp_rc)) != 0) 1336 return (rc); 1337 1338 /* 1339 * If everything succeeded add an nvlist containing the 1340 * module name to the set of nvlists to pass back to libipp. 1341 */ 1342 1343 if (ipp_rc == 0) { 1344 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, KM_SLEEP)) != 0) 1345 return (rc); 1346 1347 if ((rc = ippctl_attach_modname(nvlp, modname)) != 0) { 1348 nvlist_free(nvlp); 1349 return (rc); 1350 } 1351 1352 FREE_TEXT(modname); 1353 1354 rc = ippctl_callback(nvlp, NULL); 1355 nvlist_free(nvlp); 1356 } else 1357 rc = 0; 1358 1359 return (rc); 1360 } 1361 #undef __FN__ 1362 1363 #define __FN__ "ippctl_list_mods" 1364 static int 1365 ippctl_list_mods( 1366 void) 1367 { 1368 nvlist_t *nvlp; 1369 int ipp_rc; 1370 int rc = 0; 1371 ipp_mod_id_t *mid_array; 1372 char **modname_array = NULL; 1373 int nelt; 1374 int length; 1375 int i; 1376 1377 /* 1378 * Get a list of all the module ids. If that succeeds, 1379 * translate the ids into names. 1380 * 1381 * NOTE: This translation may fail if a module is 1382 * unloaded during this operation. If this occurs, EAGAIN 1383 * will be passed back to libipp note that a transient 1384 * problem occured. 1385 */ 1386 1387 if ((ipp_rc = ipp_list_mods(&mid_array, &nelt)) == 0) { 1388 1389 /* 1390 * It is possible that there are no modules 1391 * registered. 1392 */ 1393 1394 if (nelt > 0) { 1395 length = nelt * sizeof (char *); 1396 modname_array = kmem_zalloc(length, KM_SLEEP); 1397 1398 for (i = 0; i < nelt; i++) { 1399 if (ipp_mod_name(mid_array[i], 1400 &modname_array[i]) != 0) { 1401 kmem_free(mid_array, nelt * 1402 sizeof (ipp_mod_id_t)); 1403 FREE_TEXT_ARRAY(modname_array, nelt); 1404 ipp_rc = EAGAIN; 1405 goto done; 1406 } 1407 } 1408 1409 kmem_free(mid_array, nelt * sizeof (ipp_mod_id_t)); 1410 1411 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, 1412 KM_SLEEP)) != 0) { 1413 FREE_TEXT_ARRAY(modname_array, nelt); 1414 return (rc); 1415 } 1416 1417 if ((rc = ippctl_attach_modname_array(nvlp, 1418 modname_array, nelt)) != 0) { 1419 FREE_TEXT_ARRAY(modname_array, nelt); 1420 nvlist_free(nvlp); 1421 return (rc); 1422 } 1423 1424 FREE_TEXT_ARRAY(modname_array, nelt); 1425 1426 if ((rc = ippctl_callback(nvlp, NULL)) != 0) { 1427 nvlist_free(nvlp); 1428 return (rc); 1429 } 1430 1431 nvlist_free(nvlp); 1432 } 1433 } 1434 1435 done: 1436 /* 1437 * Add an nvlist containing the kernel return code to the 1438 * set of nvlists to pass back to libipp. 1439 */ 1440 1441 if ((rc = ippctl_set_rc(ipp_rc)) != 0) 1442 return (rc); 1443 1444 return (0); 1445 } 1446 #undef __FN__ 1447 1448 #define __FN__ "ippctl_mod_list_actions" 1449 static int 1450 ippctl_mod_list_actions( 1451 char *modname) 1452 { 1453 ipp_mod_id_t mid; 1454 nvlist_t *nvlp; 1455 int ipp_rc; 1456 int rc = 0; 1457 ipp_action_id_t *aid_array; 1458 char **aname_array = NULL; 1459 int nelt; 1460 int length; 1461 int i; 1462 1463 /* 1464 * Get the module id. 1465 */ 1466 1467 mid = ipp_mod_lookup(modname); 1468 FREE_TEXT(modname); 1469 1470 /* 1471 * Get a list of all the action ids for the module. If that succeeds, 1472 * translate the ids into names. 1473 * 1474 * NOTE: This translation may fail if an action is 1475 * destroyed during this operation. If this occurs, EAGAIN 1476 * will be passed back to libipp note that a transient 1477 * problem occured. 1478 */ 1479 1480 if ((ipp_rc = ipp_mod_list_actions(mid, &aid_array, &nelt)) == 0) { 1481 1482 /* 1483 * It is possible that there are no actions defined. 1484 * (This is unlikely though as the module would normally 1485 * be auto-unloaded fairly quickly) 1486 */ 1487 1488 if (nelt > 0) { 1489 length = nelt * sizeof (char *); 1490 aname_array = kmem_zalloc(length, KM_SLEEP); 1491 1492 for (i = 0; i < nelt; i++) { 1493 if (ipp_action_name(aid_array[i], 1494 &aname_array[i]) != 0) { 1495 kmem_free(aid_array, nelt * 1496 sizeof (ipp_action_id_t)); 1497 FREE_TEXT_ARRAY(aname_array, nelt); 1498 ipp_rc = EAGAIN; 1499 goto done; 1500 } 1501 } 1502 1503 kmem_free(aid_array, nelt * sizeof (ipp_action_id_t)); 1504 1505 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, 1506 KM_SLEEP)) != 0) { 1507 FREE_TEXT_ARRAY(aname_array, nelt); 1508 return (rc); 1509 } 1510 1511 if ((rc = ippctl_attach_aname_array(nvlp, aname_array, 1512 nelt)) != 0) { 1513 FREE_TEXT_ARRAY(aname_array, nelt); 1514 nvlist_free(nvlp); 1515 return (rc); 1516 } 1517 1518 FREE_TEXT_ARRAY(aname_array, nelt); 1519 1520 if ((rc = ippctl_callback(nvlp, NULL)) != 0) { 1521 nvlist_free(nvlp); 1522 return (rc); 1523 } 1524 1525 nvlist_free(nvlp); 1526 } 1527 } 1528 1529 done: 1530 /* 1531 * Add an nvlist containing the kernel return code to the 1532 * set of nvlists to pass back to libipp. 1533 */ 1534 1535 if ((rc = ippctl_set_rc(ipp_rc)) != 0) 1536 return (rc); 1537 1538 return (0); 1539 } 1540 #undef __FN__ 1541 1542 #define __FN__ "ippctl_data" 1543 static int 1544 ippctl_data( 1545 char **dbufp, 1546 size_t *dbuflenp, 1547 size_t *nextbuflenp) 1548 { 1549 int i; 1550 1551 DBG0(DBG_CBOPS, "called\n"); 1552 1553 /* 1554 * Get the next data buffer from the array by looking at the 1555 * 'read index'. If this is the same as the 'write index' then 1556 * there's no more buffers in the array. 1557 */ 1558 1559 i = ippctl_rindex; 1560 if (i == ippctl_windex) 1561 return (ENOENT); 1562 1563 /* 1564 * Extract the buffer details. It is a pre-packed nvlist. 1565 */ 1566 1567 *dbufp = ippctl_array[i].buf; 1568 *dbuflenp = ippctl_array[i].buflen; 1569 1570 DBG2(DBG_CBOPS, "accessing nvlist[%d], length %lu\n", i, *dbuflenp); 1571 ASSERT(*dbufp != NULL); 1572 1573 /* 1574 * Advance the 'read index' and check if there's another buffer. 1575 * If there is then we need to pass back its length to libipp so that 1576 * another data ioctl will be issued. 1577 */ 1578 1579 i++; 1580 if (i < ippctl_windex) 1581 *nextbuflenp = ippctl_array[i].buflen; 1582 else 1583 *nextbuflenp = 0; 1584 1585 ippctl_rindex = i; 1586 return (0); 1587 } 1588 #undef __FN__ 1589 1590 #define __FN__ "ippctl_flush" 1591 static void 1592 ippctl_flush( 1593 void) 1594 { 1595 int i; 1596 char *buf; 1597 size_t buflen; 1598 1599 /* 1600 * Free any buffers left in the array. 1601 */ 1602 1603 for (i = 0; i < ippctl_limit; i++) { 1604 if ((buflen = ippctl_array[i].buflen) > 0) { 1605 buf = ippctl_array[i].buf; 1606 ASSERT(buf != NULL); 1607 kmem_free(buf, buflen); 1608 } 1609 } 1610 1611 /* 1612 * NULL all the entries. 1613 */ 1614 1615 bzero(ippctl_array, ippctl_limit * sizeof (ippctl_buf_t)); 1616 1617 /* 1618 * Reset the indexes. 1619 */ 1620 1621 ippctl_rindex = 0; 1622 ippctl_windex = 1; 1623 } 1624 #undef __FN__ 1625 1626 #define __FN__ "ippctl_add_nvlist" 1627 static int 1628 ippctl_add_nvlist( 1629 nvlist_t *nvlp, 1630 int i) 1631 { 1632 char *buf; 1633 size_t buflen; 1634 int rc; 1635 1636 /* 1637 * NULL the buffer pointer so that a buffer is automatically 1638 * allocated for us. 1639 */ 1640 1641 buf = NULL; 1642 1643 /* 1644 * Pack the nvlist and get back the buffer pointer and length. 1645 */ 1646 1647 if ((rc = nvlist_pack(nvlp, &buf, &buflen, NV_ENCODE_NATIVE, 1648 KM_SLEEP)) != 0) { 1649 ippctl_array[i].buf = NULL; 1650 ippctl_array[i].buflen = 0; 1651 return (rc); 1652 } 1653 1654 DBG2(DBG_CBOPS, "added nvlist[%d]: length %lu\n", i, buflen); 1655 1656 /* 1657 * Store the pointer an length in the array at the given index. 1658 */ 1659 1660 ippctl_array[i].buf = buf; 1661 ippctl_array[i].buflen = buflen; 1662 1663 return (0); 1664 } 1665 #undef __FN__ 1666 1667 #define __FN__ "ippctl_callback" 1668 /*ARGSUSED*/ 1669 static int 1670 ippctl_callback( 1671 nvlist_t *nvlp, 1672 void *arg) 1673 { 1674 int i; 1675 int rc; 1676 1677 /* 1678 * Check the 'write index' to see if there's space in the array for 1679 * a new entry. 1680 */ 1681 1682 i = ippctl_windex; 1683 ASSERT(i != 0); 1684 1685 /* 1686 * If there's no space, re-allocate the array (see comments in 1687 * ippctl_realloc() for details). 1688 */ 1689 1690 if (i == ippctl_limit) 1691 ippctl_realloc(); 1692 1693 /* 1694 * Add the nvlist to the array. 1695 */ 1696 1697 if ((rc = ippctl_add_nvlist(nvlp, i)) == 0) 1698 ippctl_windex++; 1699 1700 return (rc); 1701 } 1702 #undef __FN__ 1703 1704 #define __FN__ "ippctl_set_rc" 1705 static int 1706 ippctl_set_rc( 1707 int val) 1708 { 1709 nvlist_t *nvlp; 1710 int rc; 1711 1712 /* 1713 * Create an nvlist to store the return code, 1714 */ 1715 1716 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, KM_SLEEP)) != 0) 1717 return (ENOMEM); 1718 1719 if ((rc = nvlist_add_int32(nvlp, IPPCTL_RC, val)) != 0) { 1720 nvlist_free(nvlp); 1721 return (rc); 1722 } 1723 1724 /* 1725 * Add it at the beginning of the array. 1726 */ 1727 1728 rc = ippctl_add_nvlist(nvlp, 0); 1729 1730 nvlist_free(nvlp); 1731 return (rc); 1732 } 1733 #undef __FN__ 1734 1735 #define __FN__ "ippctl_alloc" 1736 static void 1737 ippctl_alloc( 1738 int limit) 1739 { 1740 /* 1741 * Allocate the data buffer array and initialize the indexes. 1742 */ 1743 1744 ippctl_array = kmem_zalloc(limit * sizeof (ippctl_buf_t), KM_SLEEP); 1745 ippctl_limit = limit; 1746 ippctl_rindex = 0; 1747 ippctl_windex = 1; 1748 } 1749 #undef __FN__ 1750 1751 #define __FN__ "ippctl_realloc" 1752 static void 1753 ippctl_realloc( 1754 void) 1755 { 1756 ippctl_buf_t *array; 1757 int limit; 1758 int i; 1759 1760 /* 1761 * Allocate a new array twice the size of the old one. 1762 */ 1763 1764 limit = ippctl_limit << 1; 1765 array = kmem_zalloc(limit * sizeof (ippctl_buf_t), KM_SLEEP); 1766 1767 /* 1768 * Copy across the information from the old array into the new one. 1769 */ 1770 1771 for (i = 0; i < ippctl_limit; i++) 1772 array[i] = ippctl_array[i]; 1773 1774 /* 1775 * Free the old array. 1776 */ 1777 1778 kmem_free(ippctl_array, ippctl_limit * sizeof (ippctl_buf_t)); 1779 1780 ippctl_array = array; 1781 ippctl_limit = limit; 1782 } 1783 #undef __FN__ 1784 1785 #define __FN__ "ippctl_free" 1786 static void 1787 ippctl_free( 1788 void) 1789 { 1790 /* 1791 * Flush the array prior to freeing it to make sure no buffers are 1792 * leaked. 1793 */ 1794 1795 ippctl_flush(); 1796 1797 /* 1798 * Free the array. 1799 */ 1800 1801 kmem_free(ippctl_array, ippctl_limit * sizeof (ippctl_buf_t)); 1802 ippctl_array = NULL; 1803 ippctl_limit = -1; 1804 ippctl_rindex = -1; 1805 ippctl_windex = -1; 1806 } 1807 #undef __FN__ 1808 1809 #ifdef IPPCTL_DEBUG 1810 static void 1811 ippctl_debug( 1812 uint64_t type, 1813 char *fn, 1814 char *fmt, 1815 ...) 1816 { 1817 char buf[255]; 1818 va_list adx; 1819 1820 if ((type & ippctl_debug_flags) == 0) 1821 return; 1822 1823 mutex_enter(debug_mutex); 1824 va_start(adx, fmt); 1825 (void) vsnprintf(buf, 255, fmt, adx); 1826 va_end(adx); 1827 1828 printf("%s: %s", fn, buf); 1829 mutex_exit(debug_mutex); 1830 } 1831 #endif /* IPPCTL_DBG */ 1832