xref: /illumos-gate/usr/src/uts/common/ipp/ippctl.c (revision 204eecd741aeb173ccbd0761993ea21a279d1e00)
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 static void	ippctl_debug(uint64_t, char *, char *, ...)
77 	__KPRINTFLIKE(3);
78 
79 #define	DBG0(_type, _fmt)					\
80 	ippctl_debug((_type), __FN__, (_fmt));
81 
82 #define	DBG1(_type, _fmt, _a1)					\
83 	ippctl_debug((_type), __FN__, (_fmt), (_a1));
84 
85 #define	DBG2(_type, _fmt, _a1, _a2)				\
86 	ippctl_debug((_type), __FN__, (_fmt), (_a1), (_a2));
87 
88 #define	DBG3(_type, _fmt, _a1, _a2, _a3)			\
89 	ippctl_debug((_type), __FN__, (_fmt), (_a1), (_a2),	\
90 	    (_a3));
91 
92 #define	DBG4(_type, _fmt, _a1, _a2, _a3, _a4)			\
93 	ippctl_debug((_type), __FN__, (_fmt), (_a1), (_a2),	\
94 	    (_a3), (_a4));
95 
96 #define	DBG5(_type, _fmt, _a1, _a2, _a3, _a4, _a5)		\
97 	ippctl_debug((_type), __FN__, (_fmt), (_a1), (_a2),	\
98 	    (_a3), (_a4), (_a5));
99 
100 #else	/* IPPCTL_DBG */
101 
102 #define	DBG0(_type, _fmt)
103 #define	DBG1(_type, _fmt, _a1)
104 #define	DBG2(_type, _fmt, _a1, _a2)
105 #define	DBG3(_type, _fmt, _a1, _a2, _a3)
106 #define	DBG4(_type, _fmt, _a1, _a2, _a3, _a4)
107 #define	DBG5(_type, _fmt, _a1, _a2, _a3, _a4, _a5)
108 
109 #endif	/* IPPCTL_DBG */
110 
111 /*
112  * cb_ops
113  */
114 
115 static int	ippctl_open(dev_t *, int, int, cred_t *);
116 static int	ippctl_close(dev_t, int, int, cred_t *);
117 static int	ippctl_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
118 
119 static	struct cb_ops	ippctl_cb_ops = {
120 	ippctl_open,	/* cb_open */
121 	ippctl_close,	/* cb_close */
122 	nodev,		/* cb_strategy */
123 	nodev,		/* cb_print */
124 	nodev,		/* cb_dump */
125 	nodev,		/* cb_read */
126 	nodev,		/* cb_write */
127 	ippctl_ioctl,	/* cb_ioctl */
128 	nodev,		/* cb_devmap */
129 	nodev,		/* cb_mmap */
130 	nodev,		/* cb_segmap */
131 	nochpoll,	/* cb_chpoll */
132 	ddi_prop_op,	/* cb_prop_op */
133 	0,		/* cb_str */
134 	D_NEW | D_MP,	/* cb_flag */
135 	CB_REV,		/* cb_rev */
136 	nodev,		/* cb_aread */
137 	nodev		/* cb_awrite */
138 };
139 
140 /*
141  * dev_ops
142  */
143 
144 static	int	ippctl_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
145 static	int	ippctl_attach(dev_info_t *, ddi_attach_cmd_t);
146 static	int	ippctl_detach(dev_info_t *, ddi_detach_cmd_t);
147 
148 static	struct dev_ops	ippctl_dev_ops = {
149 	DEVO_REV,		/* devo_rev, */
150 	0,			/* devo_refcnt  */
151 	ippctl_info,		/* devo_getinfo */
152 	nulldev,		/* devo_identify */
153 	nulldev,		/* devo_probe */
154 	ippctl_attach,		/* devo_attach */
155 	ippctl_detach,		/* devo_detach */
156 	nodev,			/* devo_reset */
157 	&ippctl_cb_ops,		/* devo_cb_ops */
158 	(struct bus_ops *)0,	/* devo_bus_ops */
159 	NULL,			/* devo_power */
160 	ddi_quiesce_not_needed,		/* devo_quiesce */
161 };
162 
163 static	struct modldrv modldrv = {
164 	&mod_driverops,
165 	"IP Policy Configuration Driver",
166 	&ippctl_dev_ops,
167 };
168 
169 static	struct modlinkage modlinkage = {
170 	MODREV_1,
171 	&modldrv,
172 	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 */
1830