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 */