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