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