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, 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 nvlist_free(nvlp); 1247 return (rc); 1248 } 1249 1250 /* 1251 * If the module passed back an nvlist, add this as 1252 * well. 1253 */ 1254 1255 if (nvlp != NULL) { 1256 rc = ippctl_callback(nvlp, NULL); 1257 nvlist_free(nvlp); 1258 } else 1259 rc = 0; 1260 1261 return (rc); 1262 } 1263 #undef __FN__ 1264 1265 #define __FN__ "ippctl_action_info" 1266 static int 1267 ippctl_action_info( 1268 char *aname, 1269 ipp_flags_t flags) 1270 { 1271 ipp_action_id_t aid; 1272 int ipp_rc; 1273 int rc; 1274 1275 /* 1276 * Look up the action and call the information retrieval 1277 * entry point. 1278 * 1279 * NOTE: The callback function that is passed in packs and 1280 * stores each of the nvlists it is called with in the array 1281 * that will be passed back to libipp. 1282 */ 1283 1284 aid = ipp_action_lookup(aname); 1285 FREE_TEXT(aname); 1286 1287 ipp_rc = ipp_action_info(aid, ippctl_callback, NULL, flags); 1288 1289 /* 1290 * Add an nvlist containing the kernel return code to the 1291 * set of nvlists to pass back to libipp. 1292 */ 1293 1294 if ((rc = ippctl_set_rc(ipp_rc)) != 0) 1295 return (rc); 1296 1297 /* 1298 * There's no more information to pass back. 1299 */ 1300 1301 return (0); 1302 } 1303 #undef __FN__ 1304 1305 #define __FN__ "ippctl_action_mod" 1306 static int 1307 ippctl_action_mod( 1308 char *aname) 1309 { 1310 ipp_mod_id_t mid; 1311 ipp_action_id_t aid; 1312 char *modname; 1313 nvlist_t *nvlp; 1314 int ipp_rc; 1315 int rc; 1316 1317 /* 1318 * Look up the action id and get the id of the module that 1319 * implements the action. If that succeeds then look up the 1320 * name of the module. 1321 */ 1322 1323 aid = ipp_action_lookup(aname); 1324 FREE_TEXT(aname); 1325 1326 if ((ipp_rc = ipp_action_mod(aid, &mid)) == 0) 1327 ipp_rc = ipp_mod_name(mid, &modname); 1328 1329 /* 1330 * Add an nvlist containing the kernel return code to the 1331 * set of nvlists to pass back to libipp. 1332 */ 1333 1334 if ((rc = ippctl_set_rc(ipp_rc)) != 0) 1335 return (rc); 1336 1337 /* 1338 * If everything succeeded add an nvlist containing the 1339 * module name to the set of nvlists to pass back to libipp. 1340 */ 1341 1342 if (ipp_rc == 0) { 1343 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, KM_SLEEP)) != 0) 1344 return (rc); 1345 1346 if ((rc = ippctl_attach_modname(nvlp, modname)) != 0) { 1347 nvlist_free(nvlp); 1348 return (rc); 1349 } 1350 1351 FREE_TEXT(modname); 1352 1353 rc = ippctl_callback(nvlp, NULL); 1354 nvlist_free(nvlp); 1355 } else 1356 rc = 0; 1357 1358 return (rc); 1359 } 1360 #undef __FN__ 1361 1362 #define __FN__ "ippctl_list_mods" 1363 static int 1364 ippctl_list_mods( 1365 void) 1366 { 1367 nvlist_t *nvlp; 1368 int ipp_rc; 1369 int rc = 0; 1370 ipp_mod_id_t *mid_array; 1371 char **modname_array = NULL; 1372 int nelt; 1373 int length; 1374 int i; 1375 1376 /* 1377 * Get a list of all the module ids. If that succeeds, 1378 * translate the ids into names. 1379 * 1380 * NOTE: This translation may fail if a module is 1381 * unloaded during this operation. If this occurs, EAGAIN 1382 * will be passed back to libipp note that a transient 1383 * problem occured. 1384 */ 1385 1386 if ((ipp_rc = ipp_list_mods(&mid_array, &nelt)) == 0) { 1387 1388 /* 1389 * It is possible that there are no modules 1390 * registered. 1391 */ 1392 1393 if (nelt > 0) { 1394 length = nelt * sizeof (char *); 1395 modname_array = kmem_zalloc(length, KM_SLEEP); 1396 1397 for (i = 0; i < nelt; i++) { 1398 if (ipp_mod_name(mid_array[i], 1399 &modname_array[i]) != 0) { 1400 kmem_free(mid_array, nelt * 1401 sizeof (ipp_mod_id_t)); 1402 FREE_TEXT_ARRAY(modname_array, nelt); 1403 ipp_rc = EAGAIN; 1404 goto done; 1405 } 1406 } 1407 1408 kmem_free(mid_array, nelt * sizeof (ipp_mod_id_t)); 1409 1410 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, 1411 KM_SLEEP)) != 0) { 1412 FREE_TEXT_ARRAY(modname_array, nelt); 1413 return (rc); 1414 } 1415 1416 if ((rc = ippctl_attach_modname_array(nvlp, 1417 modname_array, nelt)) != 0) { 1418 FREE_TEXT_ARRAY(modname_array, nelt); 1419 nvlist_free(nvlp); 1420 return (rc); 1421 } 1422 1423 FREE_TEXT_ARRAY(modname_array, nelt); 1424 1425 if ((rc = ippctl_callback(nvlp, NULL)) != 0) { 1426 nvlist_free(nvlp); 1427 return (rc); 1428 } 1429 1430 nvlist_free(nvlp); 1431 } 1432 } 1433 1434 done: 1435 /* 1436 * Add an nvlist containing the kernel return code to the 1437 * set of nvlists to pass back to libipp. 1438 */ 1439 1440 if ((rc = ippctl_set_rc(ipp_rc)) != 0) 1441 return (rc); 1442 1443 return (0); 1444 } 1445 #undef __FN__ 1446 1447 #define __FN__ "ippctl_mod_list_actions" 1448 static int 1449 ippctl_mod_list_actions( 1450 char *modname) 1451 { 1452 ipp_mod_id_t mid; 1453 nvlist_t *nvlp; 1454 int ipp_rc; 1455 int rc = 0; 1456 ipp_action_id_t *aid_array; 1457 char **aname_array = NULL; 1458 int nelt; 1459 int length; 1460 int i; 1461 1462 /* 1463 * Get the module id. 1464 */ 1465 1466 mid = ipp_mod_lookup(modname); 1467 FREE_TEXT(modname); 1468 1469 /* 1470 * Get a list of all the action ids for the module. If that succeeds, 1471 * translate the ids into names. 1472 * 1473 * NOTE: This translation may fail if an action is 1474 * destroyed during this operation. If this occurs, EAGAIN 1475 * will be passed back to libipp note that a transient 1476 * problem occured. 1477 */ 1478 1479 if ((ipp_rc = ipp_mod_list_actions(mid, &aid_array, &nelt)) == 0) { 1480 1481 /* 1482 * It is possible that there are no actions defined. 1483 * (This is unlikely though as the module would normally 1484 * be auto-unloaded fairly quickly) 1485 */ 1486 1487 if (nelt > 0) { 1488 length = nelt * sizeof (char *); 1489 aname_array = kmem_zalloc(length, KM_SLEEP); 1490 1491 for (i = 0; i < nelt; i++) { 1492 if (ipp_action_name(aid_array[i], 1493 &aname_array[i]) != 0) { 1494 kmem_free(aid_array, nelt * 1495 sizeof (ipp_action_id_t)); 1496 FREE_TEXT_ARRAY(aname_array, nelt); 1497 ipp_rc = EAGAIN; 1498 goto done; 1499 } 1500 } 1501 1502 kmem_free(aid_array, nelt * sizeof (ipp_action_id_t)); 1503 1504 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, 1505 KM_SLEEP)) != 0) { 1506 FREE_TEXT_ARRAY(aname_array, nelt); 1507 return (rc); 1508 } 1509 1510 if ((rc = ippctl_attach_aname_array(nvlp, aname_array, 1511 nelt)) != 0) { 1512 FREE_TEXT_ARRAY(aname_array, nelt); 1513 nvlist_free(nvlp); 1514 return (rc); 1515 } 1516 1517 FREE_TEXT_ARRAY(aname_array, nelt); 1518 1519 if ((rc = ippctl_callback(nvlp, NULL)) != 0) { 1520 nvlist_free(nvlp); 1521 return (rc); 1522 } 1523 1524 nvlist_free(nvlp); 1525 } 1526 } 1527 1528 done: 1529 /* 1530 * Add an nvlist containing the kernel return code to the 1531 * set of nvlists to pass back to libipp. 1532 */ 1533 1534 if ((rc = ippctl_set_rc(ipp_rc)) != 0) 1535 return (rc); 1536 1537 return (0); 1538 } 1539 #undef __FN__ 1540 1541 #define __FN__ "ippctl_data" 1542 static int 1543 ippctl_data( 1544 char **dbufp, 1545 size_t *dbuflenp, 1546 size_t *nextbuflenp) 1547 { 1548 int i; 1549 1550 DBG0(DBG_CBOPS, "called\n"); 1551 1552 /* 1553 * Get the next data buffer from the array by looking at the 1554 * 'read index'. If this is the same as the 'write index' then 1555 * there's no more buffers in the array. 1556 */ 1557 1558 i = ippctl_rindex; 1559 if (i == ippctl_windex) 1560 return (ENOENT); 1561 1562 /* 1563 * Extract the buffer details. It is a pre-packed nvlist. 1564 */ 1565 1566 *dbufp = ippctl_array[i].buf; 1567 *dbuflenp = ippctl_array[i].buflen; 1568 1569 DBG2(DBG_CBOPS, "accessing nvlist[%d], length %lu\n", i, *dbuflenp); 1570 ASSERT(*dbufp != NULL); 1571 1572 /* 1573 * Advance the 'read index' and check if there's another buffer. 1574 * If there is then we need to pass back its length to libipp so that 1575 * another data ioctl will be issued. 1576 */ 1577 1578 i++; 1579 if (i < ippctl_windex) 1580 *nextbuflenp = ippctl_array[i].buflen; 1581 else 1582 *nextbuflenp = 0; 1583 1584 ippctl_rindex = i; 1585 return (0); 1586 } 1587 #undef __FN__ 1588 1589 #define __FN__ "ippctl_flush" 1590 static void 1591 ippctl_flush( 1592 void) 1593 { 1594 int i; 1595 char *buf; 1596 size_t buflen; 1597 1598 /* 1599 * Free any buffers left in the array. 1600 */ 1601 1602 for (i = 0; i < ippctl_limit; i++) { 1603 if ((buflen = ippctl_array[i].buflen) > 0) { 1604 buf = ippctl_array[i].buf; 1605 ASSERT(buf != NULL); 1606 kmem_free(buf, buflen); 1607 } 1608 } 1609 1610 /* 1611 * NULL all the entries. 1612 */ 1613 1614 bzero(ippctl_array, ippctl_limit * sizeof (ippctl_buf_t)); 1615 1616 /* 1617 * Reset the indexes. 1618 */ 1619 1620 ippctl_rindex = 0; 1621 ippctl_windex = 1; 1622 } 1623 #undef __FN__ 1624 1625 #define __FN__ "ippctl_add_nvlist" 1626 static int 1627 ippctl_add_nvlist( 1628 nvlist_t *nvlp, 1629 int i) 1630 { 1631 char *buf; 1632 size_t buflen; 1633 int rc; 1634 1635 /* 1636 * NULL the buffer pointer so that a buffer is automatically 1637 * allocated for us. 1638 */ 1639 1640 buf = NULL; 1641 1642 /* 1643 * Pack the nvlist and get back the buffer pointer and length. 1644 */ 1645 1646 if ((rc = nvlist_pack(nvlp, &buf, &buflen, NV_ENCODE_NATIVE, 1647 KM_SLEEP)) != 0) { 1648 ippctl_array[i].buf = NULL; 1649 ippctl_array[i].buflen = 0; 1650 return (rc); 1651 } 1652 1653 DBG2(DBG_CBOPS, "added nvlist[%d]: length %lu\n", i, buflen); 1654 1655 /* 1656 * Store the pointer an length in the array at the given index. 1657 */ 1658 1659 ippctl_array[i].buf = buf; 1660 ippctl_array[i].buflen = buflen; 1661 1662 return (0); 1663 } 1664 #undef __FN__ 1665 1666 #define __FN__ "ippctl_callback" 1667 /*ARGSUSED*/ 1668 static int 1669 ippctl_callback( 1670 nvlist_t *nvlp, 1671 void *arg) 1672 { 1673 int i; 1674 int rc; 1675 1676 /* 1677 * Check the 'write index' to see if there's space in the array for 1678 * a new entry. 1679 */ 1680 1681 i = ippctl_windex; 1682 ASSERT(i != 0); 1683 1684 /* 1685 * If there's no space, re-allocate the array (see comments in 1686 * ippctl_realloc() for details). 1687 */ 1688 1689 if (i == ippctl_limit) 1690 ippctl_realloc(); 1691 1692 /* 1693 * Add the nvlist to the array. 1694 */ 1695 1696 if ((rc = ippctl_add_nvlist(nvlp, i)) == 0) 1697 ippctl_windex++; 1698 1699 return (rc); 1700 } 1701 #undef __FN__ 1702 1703 #define __FN__ "ippctl_set_rc" 1704 static int 1705 ippctl_set_rc( 1706 int val) 1707 { 1708 nvlist_t *nvlp; 1709 int rc; 1710 1711 /* 1712 * Create an nvlist to store the return code, 1713 */ 1714 1715 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, KM_SLEEP)) != 0) 1716 return (ENOMEM); 1717 1718 if ((rc = nvlist_add_int32(nvlp, IPPCTL_RC, val)) != 0) { 1719 nvlist_free(nvlp); 1720 return (rc); 1721 } 1722 1723 /* 1724 * Add it at the beginning of the array. 1725 */ 1726 1727 rc = ippctl_add_nvlist(nvlp, 0); 1728 1729 nvlist_free(nvlp); 1730 return (rc); 1731 } 1732 #undef __FN__ 1733 1734 #define __FN__ "ippctl_alloc" 1735 static void 1736 ippctl_alloc( 1737 int limit) 1738 { 1739 /* 1740 * Allocate the data buffer array and initialize the indexes. 1741 */ 1742 1743 ippctl_array = kmem_zalloc(limit * sizeof (ippctl_buf_t), KM_SLEEP); 1744 ippctl_limit = limit; 1745 ippctl_rindex = 0; 1746 ippctl_windex = 1; 1747 } 1748 #undef __FN__ 1749 1750 #define __FN__ "ippctl_realloc" 1751 static void 1752 ippctl_realloc( 1753 void) 1754 { 1755 ippctl_buf_t *array; 1756 int limit; 1757 int i; 1758 1759 /* 1760 * Allocate a new array twice the size of the old one. 1761 */ 1762 1763 limit = ippctl_limit << 1; 1764 array = kmem_zalloc(limit * sizeof (ippctl_buf_t), KM_SLEEP); 1765 1766 /* 1767 * Copy across the information from the old array into the new one. 1768 */ 1769 1770 for (i = 0; i < ippctl_limit; i++) 1771 array[i] = ippctl_array[i]; 1772 1773 /* 1774 * Free the old array. 1775 */ 1776 1777 kmem_free(ippctl_array, ippctl_limit * sizeof (ippctl_buf_t)); 1778 1779 ippctl_array = array; 1780 ippctl_limit = limit; 1781 } 1782 #undef __FN__ 1783 1784 #define __FN__ "ippctl_free" 1785 static void 1786 ippctl_free( 1787 void) 1788 { 1789 /* 1790 * Flush the array prior to freeing it to make sure no buffers are 1791 * leaked. 1792 */ 1793 1794 ippctl_flush(); 1795 1796 /* 1797 * Free the array. 1798 */ 1799 1800 kmem_free(ippctl_array, ippctl_limit * sizeof (ippctl_buf_t)); 1801 ippctl_array = NULL; 1802 ippctl_limit = -1; 1803 ippctl_rindex = -1; 1804 ippctl_windex = -1; 1805 } 1806 #undef __FN__ 1807 1808 #ifdef IPPCTL_DEBUG 1809 static void 1810 ippctl_debug( 1811 uint64_t type, 1812 char *fn, 1813 char *fmt, 1814 ...) 1815 { 1816 char buf[255]; 1817 va_list adx; 1818 1819 if ((type & ippctl_debug_flags) == 0) 1820 return; 1821 1822 mutex_enter(debug_mutex); 1823 va_start(adx, fmt); 1824 (void) vsnprintf(buf, 255, fmt, adx); 1825 va_end(adx); 1826 1827 printf("%s: %s", fn, buf); 1828 mutex_exit(debug_mutex); 1829 } 1830 #endif /* IPPCTL_DBG */ 1831