xref: /onnv-gate/usr/src/uts/common/ipp/ippctl.c (revision 7656:2621e50fdf4a)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7656SSherry.Moore@Sun.COM  * Common Development and Distribution License (the "License").
6*7656SSherry.Moore@Sun.COM  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*7656SSherry.Moore@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * IP Policy Framework config driver
290Sstevel@tonic-gate  */
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #include <sys/types.h>
320Sstevel@tonic-gate #include <sys/cmn_err.h>
330Sstevel@tonic-gate #include <sys/kmem.h>
340Sstevel@tonic-gate #include <sys/errno.h>
350Sstevel@tonic-gate #include <sys/cpuvar.h>
360Sstevel@tonic-gate #include <sys/open.h>
370Sstevel@tonic-gate #include <sys/stat.h>
380Sstevel@tonic-gate #include <sys/conf.h>
390Sstevel@tonic-gate #include <sys/ddi.h>
400Sstevel@tonic-gate #include <sys/sunddi.h>
410Sstevel@tonic-gate #include <sys/modctl.h>
420Sstevel@tonic-gate #include <sys/stream.h>
430Sstevel@tonic-gate #include <ipp/ipp.h>
440Sstevel@tonic-gate #include <ipp/ippctl.h>
450Sstevel@tonic-gate #include <sys/nvpair.h>
460Sstevel@tonic-gate #include <sys/policy.h>
470Sstevel@tonic-gate 
480Sstevel@tonic-gate /*
490Sstevel@tonic-gate  * Debug switch.
500Sstevel@tonic-gate  */
510Sstevel@tonic-gate 
520Sstevel@tonic-gate #if	defined(DEBUG)
530Sstevel@tonic-gate #define	IPPCTL_DEBUG
540Sstevel@tonic-gate #endif
550Sstevel@tonic-gate 
560Sstevel@tonic-gate /*
570Sstevel@tonic-gate  * Debug macros.
580Sstevel@tonic-gate  */
590Sstevel@tonic-gate 
600Sstevel@tonic-gate #ifdef	IPPCTL_DEBUG
610Sstevel@tonic-gate 
620Sstevel@tonic-gate #define	DBG_MODLINK	0x00000001ull
630Sstevel@tonic-gate #define	DBG_DEVOPS	0x00000002ull
640Sstevel@tonic-gate #define	DBG_CBOPS	0x00000004ull
650Sstevel@tonic-gate 
660Sstevel@tonic-gate static	uint64_t	ippctl_debug_flags =
670Sstevel@tonic-gate /*
680Sstevel@tonic-gate  * DBG_MODLINK |
690Sstevel@tonic-gate  * DBG_DEVOPS |
700Sstevel@tonic-gate  * DBG_CBOPS |
710Sstevel@tonic-gate  */
720Sstevel@tonic-gate 0;
730Sstevel@tonic-gate 
740Sstevel@tonic-gate static kmutex_t	debug_mutex[1];
750Sstevel@tonic-gate 
760Sstevel@tonic-gate /*PRINTFLIKE3*/
770Sstevel@tonic-gate static void	ippctl_debug(uint64_t, char *, char *, ...)
780Sstevel@tonic-gate 	__PRINTFLIKE(3);
790Sstevel@tonic-gate 
800Sstevel@tonic-gate #define	DBG0(_type, _fmt)		    			\
810Sstevel@tonic-gate 	ippctl_debug((_type), __FN__, (_fmt));
820Sstevel@tonic-gate 
830Sstevel@tonic-gate #define	DBG1(_type, _fmt, _a1) 					\
840Sstevel@tonic-gate 	ippctl_debug((_type), __FN__, (_fmt), (_a1));
850Sstevel@tonic-gate 
860Sstevel@tonic-gate #define	DBG2(_type, _fmt, _a1, _a2)				\
870Sstevel@tonic-gate 	ippctl_debug((_type), __FN__, (_fmt), (_a1), (_a2));
880Sstevel@tonic-gate 
890Sstevel@tonic-gate #define	DBG3(_type, _fmt, _a1, _a2, _a3)			\
900Sstevel@tonic-gate 	ippctl_debug((_type), __FN__, (_fmt), (_a1), (_a2),	\
910Sstevel@tonic-gate 	    (_a3));
920Sstevel@tonic-gate 
930Sstevel@tonic-gate #define	DBG4(_type, _fmt, _a1, _a2, _a3, _a4)			\
940Sstevel@tonic-gate 	ippctl_debug((_type), __FN__, (_fmt), (_a1), (_a2),	\
950Sstevel@tonic-gate 	    (_a3), (_a4));
960Sstevel@tonic-gate 
970Sstevel@tonic-gate #define	DBG5(_type, _fmt, _a1, _a2, _a3, _a4, _a5)		\
980Sstevel@tonic-gate 	ippctl_debug((_type), __FN__, (_fmt), (_a1), (_a2),	\
990Sstevel@tonic-gate 	    (_a3), (_a4), (_a5));
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate #else	/* IPPCTL_DBG */
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate #define	DBG0(_type, _fmt)
1040Sstevel@tonic-gate #define	DBG1(_type, _fmt, _a1)
1050Sstevel@tonic-gate #define	DBG2(_type, _fmt, _a1, _a2)
1060Sstevel@tonic-gate #define	DBG3(_type, _fmt, _a1, _a2, _a3)
1070Sstevel@tonic-gate #define	DBG4(_type, _fmt, _a1, _a2, _a3, _a4)
1080Sstevel@tonic-gate #define	DBG5(_type, _fmt, _a1, _a2, _a3, _a4, _a5)
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate #endif	/* IPPCTL_DBG */
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate /*
1130Sstevel@tonic-gate  * cb_ops
1140Sstevel@tonic-gate  */
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate static int	ippctl_open(dev_t *, int, int, cred_t *);
1170Sstevel@tonic-gate static int	ippctl_close(dev_t, int, int, cred_t *);
1180Sstevel@tonic-gate static int	ippctl_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate static	struct cb_ops	ippctl_cb_ops = {
1210Sstevel@tonic-gate 	ippctl_open,	/* cb_open */
1220Sstevel@tonic-gate 	ippctl_close,	/* cb_close */
1230Sstevel@tonic-gate 	nodev,		/* cb_strategy */
1240Sstevel@tonic-gate 	nodev,		/* cb_print */
1250Sstevel@tonic-gate 	nodev,		/* cb_dump */
1260Sstevel@tonic-gate 	nodev,		/* cb_read */
1270Sstevel@tonic-gate 	nodev,		/* cb_write */
1280Sstevel@tonic-gate 	ippctl_ioctl,	/* cb_ioctl */
1290Sstevel@tonic-gate 	nodev,		/* cb_devmap */
1300Sstevel@tonic-gate 	nodev,		/* cb_mmap */
1310Sstevel@tonic-gate 	nodev,		/* cb_segmap */
1320Sstevel@tonic-gate 	nochpoll,	/* cb_chpoll */
1330Sstevel@tonic-gate 	ddi_prop_op,	/* cb_prop_op */
1340Sstevel@tonic-gate 	0,		/* cb_str */
1350Sstevel@tonic-gate 	D_NEW | D_MP,	/* cb_flag */
1360Sstevel@tonic-gate 	CB_REV,		/* cb_rev */
1370Sstevel@tonic-gate 	nodev,		/* cb_aread */
1380Sstevel@tonic-gate 	nodev		/* cb_awrite */
1390Sstevel@tonic-gate };
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate /*
1420Sstevel@tonic-gate  * dev_ops
1430Sstevel@tonic-gate  */
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate static	int	ippctl_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
1460Sstevel@tonic-gate static	int	ippctl_attach(dev_info_t *, ddi_attach_cmd_t);
1470Sstevel@tonic-gate static	int	ippctl_detach(dev_info_t *, ddi_detach_cmd_t);
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate static	struct dev_ops	ippctl_dev_ops = {
1500Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev, */
1510Sstevel@tonic-gate 	0,			/* devo_refcnt  */
1520Sstevel@tonic-gate 	ippctl_info,		/* devo_getinfo */
1530Sstevel@tonic-gate 	nulldev,		/* devo_identify */
1540Sstevel@tonic-gate 	nulldev,		/* devo_probe */
1550Sstevel@tonic-gate 	ippctl_attach,		/* devo_attach */
1560Sstevel@tonic-gate 	ippctl_detach,		/* devo_detach */
1570Sstevel@tonic-gate 	nodev,			/* devo_reset */
1580Sstevel@tonic-gate 	&ippctl_cb_ops,		/* devo_cb_ops */
159*7656SSherry.Moore@Sun.COM 	(struct bus_ops *)0,	/* devo_bus_ops */
160*7656SSherry.Moore@Sun.COM 	NULL,			/* devo_power */
161*7656SSherry.Moore@Sun.COM 	ddi_quiesce_not_needed,		/* devo_quiesce */
1620Sstevel@tonic-gate };
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate static	struct modldrv modldrv = {
1650Sstevel@tonic-gate 	&mod_driverops,
166*7656SSherry.Moore@Sun.COM 	"IP Policy Configuration Driver",
1670Sstevel@tonic-gate 	&ippctl_dev_ops,
1680Sstevel@tonic-gate };
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate static	struct modlinkage modlinkage = {
1710Sstevel@tonic-gate 	MODREV_1,
1720Sstevel@tonic-gate 	&modldrv,
1730Sstevel@tonic-gate 	NULL
1740Sstevel@tonic-gate };
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate /*
1770Sstevel@tonic-gate  * Local definitions, types and prototypes.
1780Sstevel@tonic-gate  */
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate #define	MAXUBUFLEN	(1 << 16)
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate #define	FREE_TEXT(_string)					\
1830Sstevel@tonic-gate 	kmem_free((_string), strlen(_string) + 1)
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate #define	FREE_TEXT_ARRAY(_array, _nelt)				\
1860Sstevel@tonic-gate 	{							\
1870Sstevel@tonic-gate 		int	j;					\
1880Sstevel@tonic-gate 								\
1890Sstevel@tonic-gate 		for (j = 0; j < (_nelt); j++)			\
1900Sstevel@tonic-gate 			if ((_array)[j] != NULL)		\
1910Sstevel@tonic-gate 				FREE_TEXT((_array)[j]);		\
1920Sstevel@tonic-gate 		kmem_free((_array), (_nelt) * sizeof (char *));	\
1930Sstevel@tonic-gate 	}
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate typedef	struct ippctl_buf	ippctl_buf_t;
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate struct ippctl_buf {
1980Sstevel@tonic-gate 	char	*buf;
1990Sstevel@tonic-gate 	size_t	buflen;
2000Sstevel@tonic-gate };
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate static int	ippctl_copyin(caddr_t, int, char **, size_t *);
2030Sstevel@tonic-gate static int	ippctl_copyout(caddr_t, int, char *, size_t);
2040Sstevel@tonic-gate static int	ippctl_extract_op(nvlist_t *, uint8_t *);
2050Sstevel@tonic-gate static int	ippctl_extract_aname(nvlist_t *, char **);
2060Sstevel@tonic-gate static int	ippctl_extract_modname(nvlist_t *, char **);
2070Sstevel@tonic-gate static int	ippctl_attach_modname(nvlist_t *nvlp, char *val);
2080Sstevel@tonic-gate static int	ippctl_attach_modname_array(nvlist_t *nvlp, char **val, int);
2090Sstevel@tonic-gate static int	ippctl_attach_aname_array(nvlist_t *nvlp, char **val, int);
2100Sstevel@tonic-gate static int	ippctl_extract_flags(nvlist_t *, ipp_flags_t *);
2110Sstevel@tonic-gate static int	ippctl_cmd(char *, size_t, size_t *);
2120Sstevel@tonic-gate static int	ippctl_action_create(char *, char *, nvlist_t *, ipp_flags_t);
2130Sstevel@tonic-gate static int	ippctl_action_destroy(char *, ipp_flags_t);
2140Sstevel@tonic-gate static int	ippctl_action_modify(char *, nvlist_t *, ipp_flags_t);
2150Sstevel@tonic-gate static int	ippctl_action_info(char *, ipp_flags_t);
2160Sstevel@tonic-gate static int	ippctl_action_mod(char *);
2170Sstevel@tonic-gate static int	ippctl_list_mods(void);
2180Sstevel@tonic-gate static int	ippctl_mod_list_actions(char *);
2190Sstevel@tonic-gate static int	ippctl_data(char **, size_t *, size_t *);
2200Sstevel@tonic-gate static void	ippctl_flush(void);
2210Sstevel@tonic-gate static int	ippctl_add_nvlist(nvlist_t *, int);
2220Sstevel@tonic-gate static int	ippctl_callback(nvlist_t *, void *);
2230Sstevel@tonic-gate static int	ippctl_set_rc(int);
2240Sstevel@tonic-gate static void	ippctl_alloc(int);
2250Sstevel@tonic-gate static void	ippctl_realloc(void);
2260Sstevel@tonic-gate static void	ippctl_free(void);
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate /*
2290Sstevel@tonic-gate  * Global data
2300Sstevel@tonic-gate  */
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate static dev_info_t	*ippctl_dip = NULL;
2330Sstevel@tonic-gate static kmutex_t		ippctl_lock;
2340Sstevel@tonic-gate static boolean_t	ippctl_busy;
2350Sstevel@tonic-gate static ippctl_buf_t	*ippctl_array = NULL;
2360Sstevel@tonic-gate static int		ippctl_limit = -1;
2370Sstevel@tonic-gate static int		ippctl_rindex = -1;
2380Sstevel@tonic-gate static int		ippctl_windex = -1;
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate /*
2410Sstevel@tonic-gate  * Module linkage functions
2420Sstevel@tonic-gate  */
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate #define	__FN__	"_init"
2450Sstevel@tonic-gate int
_init(void)2460Sstevel@tonic-gate _init(
2470Sstevel@tonic-gate 	void)
2480Sstevel@tonic-gate {
2490Sstevel@tonic-gate 	int	rc;
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	if ((rc = mod_install(&modlinkage)) != 0) {
2520Sstevel@tonic-gate 		DBG0(DBG_MODLINK, "mod_install failed\n");
2530Sstevel@tonic-gate 		return (rc);
2540Sstevel@tonic-gate 	}
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 	return (rc);
2570Sstevel@tonic-gate }
2580Sstevel@tonic-gate #undef	__FN__
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate #define	__FN__	"_fini"
2610Sstevel@tonic-gate int
_fini(void)2620Sstevel@tonic-gate _fini(
2630Sstevel@tonic-gate 	void)
2640Sstevel@tonic-gate {
2650Sstevel@tonic-gate 	int	rc;
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	if ((rc = mod_remove(&modlinkage)) == 0) {
2680Sstevel@tonic-gate 		return (rc);
2690Sstevel@tonic-gate 	}
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	DBG0(DBG_MODLINK, "mod_remove failed\n");
2720Sstevel@tonic-gate 	return (rc);
2730Sstevel@tonic-gate }
2740Sstevel@tonic-gate #undef	__FN__
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate #define	__FN__	"_info"
2770Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2780Sstevel@tonic-gate _info(
2790Sstevel@tonic-gate 	struct modinfo	*modinfop)
2800Sstevel@tonic-gate {
2810Sstevel@tonic-gate 	DBG0(DBG_MODLINK, "calling mod_info\n");
2820Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2830Sstevel@tonic-gate }
2840Sstevel@tonic-gate #undef	__FN__
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate /*
2870Sstevel@tonic-gate  * Driver interface functions (dev_ops and cb_ops)
2880Sstevel@tonic-gate  */
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate #define	__FN__	"ippctl_info"
2910Sstevel@tonic-gate /*ARGSUSED*/
2920Sstevel@tonic-gate static	int
ippctl_info(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)2930Sstevel@tonic-gate ippctl_info(
2940Sstevel@tonic-gate 	dev_info_t	*dip,
2950Sstevel@tonic-gate 	ddi_info_cmd_t	cmd,
2960Sstevel@tonic-gate 	void		*arg,
2970Sstevel@tonic-gate 	void 		**result)
2980Sstevel@tonic-gate {
2990Sstevel@tonic-gate 	int		rc = DDI_FAILURE;
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	switch (cmd) {
3020Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
3030Sstevel@tonic-gate 		*result = (void *)0;	/* Single instance driver */
3040Sstevel@tonic-gate 		rc = DDI_SUCCESS;
3050Sstevel@tonic-gate 		break;
3060Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
3070Sstevel@tonic-gate 		*result = (void *)ippctl_dip;
3080Sstevel@tonic-gate 		rc = DDI_SUCCESS;
3090Sstevel@tonic-gate 		break;
3100Sstevel@tonic-gate 	default:
3110Sstevel@tonic-gate 		break;
3120Sstevel@tonic-gate 	}
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	return (rc);
3150Sstevel@tonic-gate }
3160Sstevel@tonic-gate #undef	__FN__
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate #define	__FN__	"ippctl_attach"
3190Sstevel@tonic-gate static	int
ippctl_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)3200Sstevel@tonic-gate ippctl_attach(
3210Sstevel@tonic-gate 	dev_info_t		*dip,
3220Sstevel@tonic-gate 	ddi_attach_cmd_t	cmd)
3230Sstevel@tonic-gate {
3240Sstevel@tonic-gate 	switch (cmd) {
3250Sstevel@tonic-gate 	case DDI_ATTACH:
3260Sstevel@tonic-gate 		break;
3270Sstevel@tonic-gate 	case DDI_PM_RESUME:
3280Sstevel@tonic-gate 		/*FALLTHRU*/
3290Sstevel@tonic-gate 	case DDI_RESUME:
3300Sstevel@tonic-gate 		/*FALLTHRU*/
3310Sstevel@tonic-gate 	default:
3320Sstevel@tonic-gate 		return (DDI_FAILURE);
3330Sstevel@tonic-gate 	}
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	DBG0(DBG_DEVOPS, "DDI_ATTACH\n");
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	/*
3380Sstevel@tonic-gate 	 * This is strictly a single instance driver.
3390Sstevel@tonic-gate 	 */
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	if (ippctl_dip != NULL)
3420Sstevel@tonic-gate 		return (DDI_FAILURE);
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	/*
3450Sstevel@tonic-gate 	 * Create minor node.
3460Sstevel@tonic-gate 	 */
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	if (ddi_create_minor_node(dip, "ctl", S_IFCHR, 0,
3490Sstevel@tonic-gate 	    DDI_PSEUDO, 0) != DDI_SUCCESS)
3500Sstevel@tonic-gate 		return (DDI_FAILURE);
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	/*
3530Sstevel@tonic-gate 	 * No need for per-instance structure, just store vital data in
3540Sstevel@tonic-gate 	 * globals.
3550Sstevel@tonic-gate 	 */
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	ippctl_dip = dip;
3580Sstevel@tonic-gate 	mutex_init(&ippctl_lock, NULL, MUTEX_DRIVER, NULL);
3590Sstevel@tonic-gate 	ippctl_busy = B_FALSE;
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 	return (DDI_SUCCESS);
3620Sstevel@tonic-gate }
3630Sstevel@tonic-gate #undef	__FN__
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate #define	__FN__	"ippctl_detach"
3660Sstevel@tonic-gate /*ARGSUSED*/
3670Sstevel@tonic-gate static	int
ippctl_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)3680Sstevel@tonic-gate ippctl_detach(
3690Sstevel@tonic-gate 	dev_info_t		*dip,
3700Sstevel@tonic-gate 	ddi_detach_cmd_t	cmd)
3710Sstevel@tonic-gate {
3720Sstevel@tonic-gate 	switch (cmd) {
3730Sstevel@tonic-gate 	case DDI_DETACH:
3740Sstevel@tonic-gate 		break;
3750Sstevel@tonic-gate 	case DDI_PM_SUSPEND:
3760Sstevel@tonic-gate 		/*FALLTHRU*/
3770Sstevel@tonic-gate 	case DDI_SUSPEND:
3780Sstevel@tonic-gate 		/*FALLTHRU*/
3790Sstevel@tonic-gate 	default:
3800Sstevel@tonic-gate 		return (DDI_FAILURE);
3810Sstevel@tonic-gate 	}
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 	DBG0(DBG_DEVOPS, "DDI_DETACH\n");
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 	ASSERT(dip == ippctl_dip);
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	ddi_remove_minor_node(dip, NULL);
3880Sstevel@tonic-gate 	mutex_destroy(&ippctl_lock);
3890Sstevel@tonic-gate 	ippctl_dip = NULL;
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 	return (DDI_SUCCESS);
3920Sstevel@tonic-gate }
3930Sstevel@tonic-gate #undef	__FN__
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate #define	__FN__	"ippctl_open"
3960Sstevel@tonic-gate /*ARGSUSED*/
3970Sstevel@tonic-gate static	int
ippctl_open(dev_t * devp,int flag,int otyp,cred_t * credp)3980Sstevel@tonic-gate ippctl_open(
3990Sstevel@tonic-gate 	dev_t	*devp,
4000Sstevel@tonic-gate 	int	flag,
4010Sstevel@tonic-gate 	int	otyp,
4020Sstevel@tonic-gate 	cred_t	*credp)
4030Sstevel@tonic-gate {
4040Sstevel@tonic-gate 	minor_t	minor = getminor(*devp);
4050Sstevel@tonic-gate #define	LIMIT	4
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 	DBG0(DBG_CBOPS, "open\n");
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 	/*
4100Sstevel@tonic-gate 	 * Only allow privileged users to open our device.
4110Sstevel@tonic-gate 	 */
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 	if (secpolicy_net_config(credp, B_FALSE) != 0) {
4140Sstevel@tonic-gate 		DBG0(DBG_CBOPS, "not privileged user\n");
4150Sstevel@tonic-gate 		return (EPERM);
4160Sstevel@tonic-gate 	}
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 	/*
4190Sstevel@tonic-gate 	 * Sanity check other arguments.
4200Sstevel@tonic-gate 	 */
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 	if (minor != 0) {
4230Sstevel@tonic-gate 		DBG0(DBG_CBOPS, "bad minor\n");
4240Sstevel@tonic-gate 		return (ENXIO);
4250Sstevel@tonic-gate 	}
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	if (otyp != OTYP_CHR) {
4280Sstevel@tonic-gate 		DBG0(DBG_CBOPS, "bad device type\n");
4290Sstevel@tonic-gate 		return (EINVAL);
4300Sstevel@tonic-gate 	}
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	/*
4330Sstevel@tonic-gate 	 * This is also a single dev_t driver.
4340Sstevel@tonic-gate 	 */
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 	mutex_enter(&ippctl_lock);
4370Sstevel@tonic-gate 	if (ippctl_busy) {
4380Sstevel@tonic-gate 		mutex_exit(&ippctl_lock);
4390Sstevel@tonic-gate 		return (EBUSY);
4400Sstevel@tonic-gate 	}
4410Sstevel@tonic-gate 	ippctl_busy = B_TRUE;
4420Sstevel@tonic-gate 	mutex_exit(&ippctl_lock);
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	/*
4450Sstevel@tonic-gate 	 * Allocate data buffer array (starting with length LIMIT, defined
4460Sstevel@tonic-gate 	 * at the start of this function).
4470Sstevel@tonic-gate 	 */
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 	ippctl_alloc(LIMIT);
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 	DBG0(DBG_CBOPS, "success\n");
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 	return (0);
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate #undef	LIMIT
4560Sstevel@tonic-gate }
4570Sstevel@tonic-gate #undef	__FN__
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate #define	__FN__	"ippctl_close"
4600Sstevel@tonic-gate /*ARGSUSED*/
4610Sstevel@tonic-gate static	int
ippctl_close(dev_t dev,int flag,int otyp,cred_t * credp)4620Sstevel@tonic-gate ippctl_close(
4630Sstevel@tonic-gate 	dev_t	dev,
4640Sstevel@tonic-gate 	int	flag,
4650Sstevel@tonic-gate 	int	otyp,
4660Sstevel@tonic-gate 	cred_t	*credp)
4670Sstevel@tonic-gate {
4680Sstevel@tonic-gate 	minor_t	minor = getminor(dev);
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	DBG0(DBG_CBOPS, "close\n");
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 	ASSERT(minor == 0);
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	/*
4750Sstevel@tonic-gate 	 * Free the data buffer array.
4760Sstevel@tonic-gate 	 */
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	ippctl_free();
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 	mutex_enter(&ippctl_lock);
4810Sstevel@tonic-gate 	ippctl_busy = B_FALSE;
4820Sstevel@tonic-gate 	mutex_exit(&ippctl_lock);
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 	DBG0(DBG_CBOPS, "success\n");
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	return (0);
4870Sstevel@tonic-gate }
4880Sstevel@tonic-gate #undef	__FN__
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate #define	__FN__	"ippctl_ioctl"
4910Sstevel@tonic-gate static int
ippctl_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)4920Sstevel@tonic-gate ippctl_ioctl(
4930Sstevel@tonic-gate 	dev_t			dev,
4940Sstevel@tonic-gate 	int			cmd,
4950Sstevel@tonic-gate 	intptr_t		arg,
4960Sstevel@tonic-gate 	int			mode,
4970Sstevel@tonic-gate 	cred_t			*credp,
4980Sstevel@tonic-gate 	int			*rvalp)
4990Sstevel@tonic-gate {
5000Sstevel@tonic-gate 	minor_t			minor = getminor(dev);
5010Sstevel@tonic-gate 	char			*cbuf;
5020Sstevel@tonic-gate 	char			*dbuf;
5030Sstevel@tonic-gate 	size_t			cbuflen;
5040Sstevel@tonic-gate 	size_t			dbuflen;
5050Sstevel@tonic-gate 	size_t			nextbuflen;
5060Sstevel@tonic-gate 	int			rc;
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	/*
5090Sstevel@tonic-gate 	 * Paranoia check.
5100Sstevel@tonic-gate 	 */
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	if (secpolicy_net_config(credp, B_FALSE) != 0) {
5130Sstevel@tonic-gate 		DBG0(DBG_CBOPS, "not privileged user\n");
5140Sstevel@tonic-gate 		return (EPERM);
5150Sstevel@tonic-gate 	}
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 	if (minor != 0) {
5180Sstevel@tonic-gate 		DBG0(DBG_CBOPS, "bad minor\n");
5190Sstevel@tonic-gate 		return (ENXIO);
5200Sstevel@tonic-gate 	}
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 	switch (cmd) {
5230Sstevel@tonic-gate 	case IPPCTL_CMD:
5240Sstevel@tonic-gate 		DBG0(DBG_CBOPS, "command\n");
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 		/*
5270Sstevel@tonic-gate 		 * Copy in the command buffer from user space.
5280Sstevel@tonic-gate 		 */
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 		if ((rc = ippctl_copyin((caddr_t)arg, mode, &cbuf,
5310Sstevel@tonic-gate 		    &cbuflen)) != 0)
5320Sstevel@tonic-gate 			break;
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 		/*
5350Sstevel@tonic-gate 		 * Execute the command.
5360Sstevel@tonic-gate 		 */
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 		rc = ippctl_cmd(cbuf, cbuflen, &nextbuflen);
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 		/*
5410Sstevel@tonic-gate 		 * Pass back the length of the first data buffer.
5420Sstevel@tonic-gate 		 */
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 		DBG1(DBG_CBOPS, "nextbuflen = %lu\n", nextbuflen);
5450Sstevel@tonic-gate 		*rvalp = nextbuflen;
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 		/*
5480Sstevel@tonic-gate 		 * Free the kernel copy of the command buffer.
5490Sstevel@tonic-gate 		 */
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 		kmem_free(cbuf, cbuflen);
5520Sstevel@tonic-gate 		break;
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate 	case IPPCTL_DATA:
5550Sstevel@tonic-gate 		DBG0(DBG_CBOPS, "data\n");
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 		/*
5580Sstevel@tonic-gate 		 * Grab the next data buffer from the array of pending
5590Sstevel@tonic-gate 		 * buffers.
5600Sstevel@tonic-gate 		 */
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 		if ((rc = ippctl_data(&dbuf, &dbuflen, &nextbuflen)) != 0)
5630Sstevel@tonic-gate 			break;
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 		/*
5660Sstevel@tonic-gate 		 * Copy it out to user space.
5670Sstevel@tonic-gate 		 */
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 		rc = ippctl_copyout((caddr_t)arg, mode, dbuf, dbuflen);
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 		/*
5720Sstevel@tonic-gate 		 * Pass back the length of the next data buffer.
5730Sstevel@tonic-gate 		 */
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 		DBG1(DBG_CBOPS, "nextbuflen = %lu\n", nextbuflen);
5760Sstevel@tonic-gate 		*rvalp = nextbuflen;
5770Sstevel@tonic-gate 		break;
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 	default:
5800Sstevel@tonic-gate 		DBG0(DBG_CBOPS, "unrecognized ioctl\n");
5810Sstevel@tonic-gate 		rc = EINVAL;
5820Sstevel@tonic-gate 		break;
5830Sstevel@tonic-gate 	}
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 	DBG1(DBG_CBOPS, "rc = %d\n", rc);
5860Sstevel@tonic-gate 	return (rc);
5870Sstevel@tonic-gate }
5880Sstevel@tonic-gate #undef	__FN__
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate /*
5910Sstevel@tonic-gate  * Local functions
5920Sstevel@tonic-gate  */
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate #define	__FN__	"ippctl_copyin"
5950Sstevel@tonic-gate static int
ippctl_copyin(caddr_t arg,int mode,char ** kbufp,size_t * kbuflenp)5960Sstevel@tonic-gate ippctl_copyin(
5970Sstevel@tonic-gate 	caddr_t		arg,
5980Sstevel@tonic-gate 	int		mode,
5990Sstevel@tonic-gate 	char		**kbufp,
6000Sstevel@tonic-gate 	size_t		*kbuflenp)
6010Sstevel@tonic-gate {
6020Sstevel@tonic-gate 	ippctl_ioctl_t	iioc;
6030Sstevel@tonic-gate 	caddr_t		ubuf;
6040Sstevel@tonic-gate 	char		*kbuf;
6050Sstevel@tonic-gate 	size_t		ubuflen;
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 	DBG0(DBG_CBOPS, "copying in ioctl structure\n");
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	/*
6100Sstevel@tonic-gate 	 * Copy in the ioctl structure from user-space, converting from 32-bit
6110Sstevel@tonic-gate 	 * as necessary.
6120Sstevel@tonic-gate 	 */
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate #ifdef	_MULTI_DATAMODEL
6150Sstevel@tonic-gate 	switch (ddi_model_convert_from(mode & FMODELS)) {
6160Sstevel@tonic-gate 	case DDI_MODEL_ILP32:
6170Sstevel@tonic-gate 		{
6180Sstevel@tonic-gate 			ippctl_ioctl32_t	iioc32;
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 			DBG0(DBG_CBOPS, "converting from 32-bit\n");
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate 			if (ddi_copyin(arg, (caddr_t)&iioc32,
6230Sstevel@tonic-gate 			    sizeof (ippctl_ioctl32_t), mode) != 0)
6240Sstevel@tonic-gate 				return (EFAULT);
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 			ubuf = (caddr_t)(uintptr_t)iioc32.ii32_buf;
6270Sstevel@tonic-gate 			ubuflen = (size_t)iioc32.ii32_buflen;
6280Sstevel@tonic-gate 		}
6290Sstevel@tonic-gate 		break;
6300Sstevel@tonic-gate 	case DDI_MODEL_NONE:
6310Sstevel@tonic-gate 		if (ddi_copyin(arg, (caddr_t)&iioc, sizeof (ippctl_ioctl_t),
6320Sstevel@tonic-gate 		    mode) != 0)
6330Sstevel@tonic-gate 			return (EFAULT);
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 		ubuf = iioc.ii_buf;
6360Sstevel@tonic-gate 		ubuflen = iioc.ii_buflen;
6370Sstevel@tonic-gate 		break;
6380Sstevel@tonic-gate 	default:
6390Sstevel@tonic-gate 		return (EFAULT);
6400Sstevel@tonic-gate 	}
6410Sstevel@tonic-gate #else	/* _MULTI_DATAMODEL */
6420Sstevel@tonic-gate 	if (ddi_copyin(arg, (caddr_t)&iioc, sizeof (ippctl_ioctl_t),
6430Sstevel@tonic-gate 	    mode) != 0)
6440Sstevel@tonic-gate 		return (EFAULT);
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 	ubuf = iioc.ii_buf;
6470Sstevel@tonic-gate 	ubuflen = iioc.ii_buflen;
6480Sstevel@tonic-gate #endif	/* _MULTI_DATAMODEL */
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 	DBG1(DBG_CBOPS, "ubuf = 0x%p\n", (void *)ubuf);
6510Sstevel@tonic-gate 	DBG1(DBG_CBOPS, "ubuflen = %lu\n", ubuflen);
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate 	/*
6540Sstevel@tonic-gate 	 * Sanity check the command buffer information.
6550Sstevel@tonic-gate 	 */
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	if (ubuflen == 0 || ubuf == NULL)
6580Sstevel@tonic-gate 		return (EINVAL);
6590Sstevel@tonic-gate 	if (ubuflen > MAXUBUFLEN)
6600Sstevel@tonic-gate 		return (E2BIG);
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 	/*
6630Sstevel@tonic-gate 	 * Allocate some memory for the command buffer and copy it in.
6640Sstevel@tonic-gate 	 */
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 	kbuf = kmem_zalloc(ubuflen, KM_SLEEP);
6670Sstevel@tonic-gate 	DBG0(DBG_CBOPS, "copying in nvlist\n");
6680Sstevel@tonic-gate 	if (ddi_copyin(ubuf, (caddr_t)kbuf, ubuflen, mode) != 0) {
6690Sstevel@tonic-gate 		kmem_free(kbuf, ubuflen);
6700Sstevel@tonic-gate 		return (EFAULT);
6710Sstevel@tonic-gate 	}
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	*kbufp = kbuf;
6740Sstevel@tonic-gate 	*kbuflenp = ubuflen;
6750Sstevel@tonic-gate 	return (0);
6760Sstevel@tonic-gate }
6770Sstevel@tonic-gate #undef	__FN__
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate #define	__FN__	"ippctl_copyout"
6800Sstevel@tonic-gate static int
ippctl_copyout(caddr_t arg,int mode,char * kbuf,size_t kbuflen)6810Sstevel@tonic-gate ippctl_copyout(
6820Sstevel@tonic-gate 	caddr_t		arg,
6830Sstevel@tonic-gate 	int		mode,
6840Sstevel@tonic-gate 	char		*kbuf,
6850Sstevel@tonic-gate 	size_t		kbuflen)
6860Sstevel@tonic-gate {
6870Sstevel@tonic-gate 	ippctl_ioctl_t	iioc;
6880Sstevel@tonic-gate 	caddr_t		ubuf;
6890Sstevel@tonic-gate 	int		ubuflen;
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate 	DBG0(DBG_CBOPS, "copying out ioctl structure\n");
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	/*
6940Sstevel@tonic-gate 	 * Copy in the ioctl structure from user-space, converting from 32-bit
6950Sstevel@tonic-gate 	 * as necessary.
6960Sstevel@tonic-gate 	 */
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate #ifdef	_MULTI_DATAMODEL
6990Sstevel@tonic-gate 	switch (ddi_model_convert_from(mode & FMODELS)) {
7000Sstevel@tonic-gate 	case DDI_MODEL_ILP32:
7010Sstevel@tonic-gate 		{
7020Sstevel@tonic-gate 			ippctl_ioctl32_t	iioc32;
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 			if (ddi_copyin(arg, (caddr_t)&iioc32,
7050Sstevel@tonic-gate 			    sizeof (ippctl_ioctl32_t), mode) != 0)
7060Sstevel@tonic-gate 				return (EFAULT);
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 			ubuf = (caddr_t)(uintptr_t)iioc32.ii32_buf;
7090Sstevel@tonic-gate 			ubuflen = iioc32.ii32_buflen;
7100Sstevel@tonic-gate 		}
7110Sstevel@tonic-gate 		break;
7120Sstevel@tonic-gate 	case DDI_MODEL_NONE:
7130Sstevel@tonic-gate 		if (ddi_copyin(arg, (caddr_t)&iioc, sizeof (ippctl_ioctl_t),
7140Sstevel@tonic-gate 		    mode) != 0)
7150Sstevel@tonic-gate 			return (EFAULT);
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 		ubuf = iioc.ii_buf;
7180Sstevel@tonic-gate 		ubuflen = iioc.ii_buflen;
7190Sstevel@tonic-gate 		break;
7200Sstevel@tonic-gate 	default:
7210Sstevel@tonic-gate 		return (EFAULT);
7220Sstevel@tonic-gate 	}
7230Sstevel@tonic-gate #else	/* _MULTI_DATAMODEL */
7240Sstevel@tonic-gate 	if (ddi_copyin(arg, (caddr_t)&iioc, sizeof (ippctl_ioctl_t),
7250Sstevel@tonic-gate 	    mode) != 0)
7260Sstevel@tonic-gate 		return (EFAULT);
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 	ubuf = iioc.ii_buf;
7290Sstevel@tonic-gate 	ubuflen = iioc.ii_buflen;
7300Sstevel@tonic-gate #endif	/* _MULTI_DATAMODEL */
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	DBG1(DBG_CBOPS, "ubuf = 0x%p\n", (void *)ubuf);
7330Sstevel@tonic-gate 	DBG1(DBG_CBOPS, "ubuflen = %d\n", ubuflen);
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate 	/*
7360Sstevel@tonic-gate 	 * Sanity check the data buffer details.
7370Sstevel@tonic-gate 	 */
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate 	if (ubuflen == 0 || ubuf == NULL)
7400Sstevel@tonic-gate 		return (EINVAL);
7410Sstevel@tonic-gate 
7420Sstevel@tonic-gate 	if (ubuflen < kbuflen)
7430Sstevel@tonic-gate 		return (ENOSPC);
7440Sstevel@tonic-gate 	if (ubuflen > MAXUBUFLEN)
7450Sstevel@tonic-gate 		return (E2BIG);
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	/*
7480Sstevel@tonic-gate 	 * Copy out the data buffer to user space.
7490Sstevel@tonic-gate 	 */
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 	DBG0(DBG_CBOPS, "copying out nvlist\n");
7520Sstevel@tonic-gate 	if (ddi_copyout((caddr_t)kbuf, ubuf, kbuflen, mode) != 0)
7530Sstevel@tonic-gate 		return (EFAULT);
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 	return (0);
7560Sstevel@tonic-gate }
7570Sstevel@tonic-gate #undef	__FN__
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate #define	__FN__	"ippctl_extract_op"
7600Sstevel@tonic-gate static int
ippctl_extract_op(nvlist_t * nvlp,uint8_t * valp)7610Sstevel@tonic-gate ippctl_extract_op(
7620Sstevel@tonic-gate 	nvlist_t	*nvlp,
7630Sstevel@tonic-gate 	uint8_t		*valp)
7640Sstevel@tonic-gate {
7650Sstevel@tonic-gate 	int		rc;
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate 	/*
7680Sstevel@tonic-gate 	 * Look-up and remove the opcode passed from libipp from the
7690Sstevel@tonic-gate 	 * nvlist.
7700Sstevel@tonic-gate 	 */
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate 	if ((rc = nvlist_lookup_byte(nvlp, IPPCTL_OP, valp)) != 0)
7730Sstevel@tonic-gate 		return (rc);
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 	(void) nvlist_remove_all(nvlp, IPPCTL_OP);
7760Sstevel@tonic-gate 	return (0);
7770Sstevel@tonic-gate }
7780Sstevel@tonic-gate #undef	__FN__
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate #define	__FN__	"ippctl_extract_aname"
7810Sstevel@tonic-gate static int
ippctl_extract_aname(nvlist_t * nvlp,char ** valp)7820Sstevel@tonic-gate ippctl_extract_aname(
7830Sstevel@tonic-gate 	nvlist_t	*nvlp,
7840Sstevel@tonic-gate 	char		**valp)
7850Sstevel@tonic-gate {
7860Sstevel@tonic-gate 	int		rc;
7870Sstevel@tonic-gate 	char		*ptr;
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 	/*
7900Sstevel@tonic-gate 	 * Look-up and remove the action name passed from libipp from the
7910Sstevel@tonic-gate 	 * nvlist.
7920Sstevel@tonic-gate 	 */
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate 	if ((rc = nvlist_lookup_string(nvlp, IPPCTL_ANAME, &ptr)) != 0)
7950Sstevel@tonic-gate 		return (rc);
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 	*valp = kmem_alloc(strlen(ptr) + 1, KM_SLEEP);
7980Sstevel@tonic-gate 	(void) strcpy(*valp, ptr);
7990Sstevel@tonic-gate 	(void) nvlist_remove_all(nvlp, IPPCTL_ANAME);
8000Sstevel@tonic-gate 	return (0);
8010Sstevel@tonic-gate }
8020Sstevel@tonic-gate #undef	__FN__
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate #define	__FN__	"ippctl_extract_modname"
8050Sstevel@tonic-gate static int
ippctl_extract_modname(nvlist_t * nvlp,char ** valp)8060Sstevel@tonic-gate ippctl_extract_modname(
8070Sstevel@tonic-gate 	nvlist_t	*nvlp,
8080Sstevel@tonic-gate 	char		**valp)
8090Sstevel@tonic-gate {
8100Sstevel@tonic-gate 	int		rc;
8110Sstevel@tonic-gate 	char		*ptr;
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate 	/*
8140Sstevel@tonic-gate 	 * Look-up and remove the module name passed from libipp from the
8150Sstevel@tonic-gate 	 * nvlist.
8160Sstevel@tonic-gate 	 */
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 	if ((rc = nvlist_lookup_string(nvlp, IPPCTL_MODNAME, &ptr)) != 0)
8190Sstevel@tonic-gate 		return (rc);
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 	*valp = kmem_alloc(strlen(ptr) + 1, KM_SLEEP);
8220Sstevel@tonic-gate 	(void) strcpy(*valp, ptr);
8230Sstevel@tonic-gate 	(void) nvlist_remove_all(nvlp, IPPCTL_MODNAME);
8240Sstevel@tonic-gate 	return (0);
8250Sstevel@tonic-gate }
8260Sstevel@tonic-gate #undef	__FN__
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate #define	__FN__	"ippctl_attach_modname"
8290Sstevel@tonic-gate static int
ippctl_attach_modname(nvlist_t * nvlp,char * modname)8300Sstevel@tonic-gate ippctl_attach_modname(
8310Sstevel@tonic-gate 	nvlist_t	*nvlp,
8320Sstevel@tonic-gate 	char		*modname)
8330Sstevel@tonic-gate {
8340Sstevel@tonic-gate 	/*
8350Sstevel@tonic-gate 	 * Add a module name to an nvlist for passing back to user
8360Sstevel@tonic-gate 	 * space.
8370Sstevel@tonic-gate 	 */
8380Sstevel@tonic-gate 
8390Sstevel@tonic-gate 	return (nvlist_add_string(nvlp, IPPCTL_MODNAME, modname));
8400Sstevel@tonic-gate }
8410Sstevel@tonic-gate #undef	__FN__
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate #define	__FN__	"ippctl_attach_modname_array"
8440Sstevel@tonic-gate static int
ippctl_attach_modname_array(nvlist_t * nvlp,char ** modname_array,int nelt)8450Sstevel@tonic-gate ippctl_attach_modname_array(
8460Sstevel@tonic-gate 	nvlist_t	*nvlp,
8470Sstevel@tonic-gate 	char		**modname_array,
8480Sstevel@tonic-gate 	int		nelt)
8490Sstevel@tonic-gate {
8500Sstevel@tonic-gate 	/*
8510Sstevel@tonic-gate 	 * Add a module name array to an nvlist for passing back to user
8520Sstevel@tonic-gate 	 * space.
8530Sstevel@tonic-gate 	 */
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate 	return (nvlist_add_string_array(nvlp, IPPCTL_MODNAME_ARRAY,
8560Sstevel@tonic-gate 	    modname_array, nelt));
8570Sstevel@tonic-gate }
8580Sstevel@tonic-gate #undef	__FN__
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate #define	__FN__	"ippctl_attach_aname_array"
8610Sstevel@tonic-gate static int
ippctl_attach_aname_array(nvlist_t * nvlp,char ** aname_array,int nelt)8620Sstevel@tonic-gate ippctl_attach_aname_array(
8630Sstevel@tonic-gate 	nvlist_t	*nvlp,
8640Sstevel@tonic-gate 	char		**aname_array,
8650Sstevel@tonic-gate 	int		nelt)
8660Sstevel@tonic-gate {
8670Sstevel@tonic-gate 	/*
8680Sstevel@tonic-gate 	 * Add an action name array to an nvlist for passing back to user
8690Sstevel@tonic-gate 	 * space.
8700Sstevel@tonic-gate 	 */
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate 	return (nvlist_add_string_array(nvlp, IPPCTL_ANAME_ARRAY,
8730Sstevel@tonic-gate 	    aname_array, nelt));
8740Sstevel@tonic-gate }
8750Sstevel@tonic-gate #undef	__FN__
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate #define	__FN__	"ippctl_extract_flags"
8780Sstevel@tonic-gate static int
ippctl_extract_flags(nvlist_t * nvlp,ipp_flags_t * valp)8790Sstevel@tonic-gate ippctl_extract_flags(
8800Sstevel@tonic-gate 	nvlist_t	*nvlp,
8810Sstevel@tonic-gate 	ipp_flags_t	*valp)
8820Sstevel@tonic-gate {
8830Sstevel@tonic-gate 	int		rc;
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 	/*
8860Sstevel@tonic-gate 	 * Look-up and remove the flags passed from libipp from the
8870Sstevel@tonic-gate 	 * nvlist.
8880Sstevel@tonic-gate 	 */
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate 	if ((rc = nvlist_lookup_uint32(nvlp, IPPCTL_FLAGS,
8910Sstevel@tonic-gate 	    (uint32_t *)valp)) != 0)
8920Sstevel@tonic-gate 		return (rc);
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 	(void) nvlist_remove_all(nvlp, IPPCTL_FLAGS);
8950Sstevel@tonic-gate 	return (0);
8960Sstevel@tonic-gate }
8970Sstevel@tonic-gate #undef	__FN__
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate #define	__FN__	"ippctl_cmd"
9000Sstevel@tonic-gate static int
ippctl_cmd(char * cbuf,size_t cbuflen,size_t * nextbuflenp)9010Sstevel@tonic-gate ippctl_cmd(
9020Sstevel@tonic-gate 	char		*cbuf,
9030Sstevel@tonic-gate 	size_t		cbuflen,
9040Sstevel@tonic-gate 	size_t		*nextbuflenp)
9050Sstevel@tonic-gate {
9060Sstevel@tonic-gate 	nvlist_t	*nvlp = NULL;
9070Sstevel@tonic-gate 	int		rc;
9080Sstevel@tonic-gate 	char		*aname = NULL;
9090Sstevel@tonic-gate 	char		*modname = NULL;
9100Sstevel@tonic-gate 	ipp_flags_t	flags;
9110Sstevel@tonic-gate 	uint8_t		op;
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	/*
9140Sstevel@tonic-gate 	 * Start a new command cycle by flushing any previous data buffers.
9150Sstevel@tonic-gate 	 */
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate 	ippctl_flush();
9180Sstevel@tonic-gate 	*nextbuflenp = 0;
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 	/*
9210Sstevel@tonic-gate 	 * Unpack the nvlist from the command buffer.
9220Sstevel@tonic-gate 	 */
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate 	if ((rc = nvlist_unpack(cbuf, cbuflen, &nvlp, KM_SLEEP)) != 0)
9250Sstevel@tonic-gate 		return (rc);
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate 	/*
9280Sstevel@tonic-gate 	 * Extract the opcode to find out what we should do.
9290Sstevel@tonic-gate 	 */
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate 	if ((rc = ippctl_extract_op(nvlp, &op)) != 0) {
9320Sstevel@tonic-gate 		nvlist_free(nvlp);
9330Sstevel@tonic-gate 		return (rc);
9340Sstevel@tonic-gate 	}
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 	switch (op) {
9370Sstevel@tonic-gate 	case IPPCTL_OP_ACTION_CREATE:
9380Sstevel@tonic-gate 		/*
9390Sstevel@tonic-gate 		 * Create a new action.
9400Sstevel@tonic-gate 		 */
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 		DBG0(DBG_CBOPS, "op = IPPCTL_OP_ACTION_CREATE\n");
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate 		/*
9450Sstevel@tonic-gate 		 * Extract the module name, action name and flags from the
9460Sstevel@tonic-gate 		 * nvlist.
9470Sstevel@tonic-gate 		 */
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 		if ((rc = ippctl_extract_modname(nvlp, &modname)) != 0) {
9500Sstevel@tonic-gate 			nvlist_free(nvlp);
9510Sstevel@tonic-gate 			return (rc);
9520Sstevel@tonic-gate 		}
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate 		if ((rc = ippctl_extract_aname(nvlp, &aname)) != 0) {
9550Sstevel@tonic-gate 			FREE_TEXT(modname);
9560Sstevel@tonic-gate 			nvlist_free(nvlp);
9570Sstevel@tonic-gate 			return (rc);
9580Sstevel@tonic-gate 		}
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate 		if ((rc = ippctl_extract_flags(nvlp, &flags)) != 0) {
9610Sstevel@tonic-gate 			FREE_TEXT(aname);
9620Sstevel@tonic-gate 			FREE_TEXT(modname);
9630Sstevel@tonic-gate 			nvlist_free(nvlp);
9640Sstevel@tonic-gate 			return (rc);
9650Sstevel@tonic-gate 		}
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 		rc = ippctl_action_create(modname, aname, nvlp, flags);
9690Sstevel@tonic-gate 		break;
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	case IPPCTL_OP_ACTION_MODIFY:
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate 		/*
9740Sstevel@tonic-gate 		 * Modify an existing action.
9750Sstevel@tonic-gate 		 */
9760Sstevel@tonic-gate 
9770Sstevel@tonic-gate 		DBG0(DBG_CBOPS, "op = IPPCTL_OP_ACTION_MODIFY\n");
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate 		/*
9800Sstevel@tonic-gate 		 * Extract the action name and flags from the nvlist.
9810Sstevel@tonic-gate 		 */
9820Sstevel@tonic-gate 
9830Sstevel@tonic-gate 		if ((rc = ippctl_extract_aname(nvlp, &aname)) != 0) {
9840Sstevel@tonic-gate 			nvlist_free(nvlp);
9850Sstevel@tonic-gate 			return (rc);
9860Sstevel@tonic-gate 		}
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate 		if ((rc = ippctl_extract_flags(nvlp, &flags)) != 0) {
9890Sstevel@tonic-gate 			FREE_TEXT(aname);
9900Sstevel@tonic-gate 			nvlist_free(nvlp);
9910Sstevel@tonic-gate 			return (rc);
9920Sstevel@tonic-gate 		}
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate 		rc = ippctl_action_modify(aname, nvlp, flags);
9950Sstevel@tonic-gate 		break;
9960Sstevel@tonic-gate 
9970Sstevel@tonic-gate 	case IPPCTL_OP_ACTION_DESTROY:
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate 		/*
10000Sstevel@tonic-gate 		 * Destroy an action.
10010Sstevel@tonic-gate 		 */
10020Sstevel@tonic-gate 
10030Sstevel@tonic-gate 		DBG0(DBG_CBOPS, "op = IPPCTL_OP_ACTION_DESTROY\n");
10040Sstevel@tonic-gate 
10050Sstevel@tonic-gate 		/*
10060Sstevel@tonic-gate 		 * Extract the action name and flags from the nvlist.
10070Sstevel@tonic-gate 		 */
10080Sstevel@tonic-gate 
10090Sstevel@tonic-gate 		if ((rc = ippctl_extract_aname(nvlp, &aname)) != 0) {
10100Sstevel@tonic-gate 			nvlist_free(nvlp);
10110Sstevel@tonic-gate 			return (rc);
10120Sstevel@tonic-gate 		}
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate 		if ((rc = ippctl_extract_flags(nvlp, &flags)) != 0) {
10150Sstevel@tonic-gate 			FREE_TEXT(aname);
10160Sstevel@tonic-gate 			nvlist_free(nvlp);
10170Sstevel@tonic-gate 			return (rc);
10180Sstevel@tonic-gate 		}
10190Sstevel@tonic-gate 
10200Sstevel@tonic-gate 		nvlist_free(nvlp);
10210Sstevel@tonic-gate 		rc = ippctl_action_destroy(aname, flags);
10220Sstevel@tonic-gate 		break;
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 	case IPPCTL_OP_ACTION_INFO:
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 		/*
10270Sstevel@tonic-gate 		 * Retrive the configuration of an action.
10280Sstevel@tonic-gate 		 */
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate 		DBG0(DBG_CBOPS, "op = IPPCTL_OP_ACTION_INFO\n");
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 		/*
10330Sstevel@tonic-gate 		 * Extract the action name and flags from the nvlist.
10340Sstevel@tonic-gate 		 */
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate 		if ((rc = ippctl_extract_aname(nvlp, &aname)) != 0) {
10370Sstevel@tonic-gate 			nvlist_free(nvlp);
10380Sstevel@tonic-gate 			return (rc);
10390Sstevel@tonic-gate 		}
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 		if ((rc = ippctl_extract_flags(nvlp, &flags)) != 0) {
10420Sstevel@tonic-gate 			nvlist_free(nvlp);
10430Sstevel@tonic-gate 			FREE_TEXT(aname);
10440Sstevel@tonic-gate 			return (rc);
10450Sstevel@tonic-gate 		}
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 		nvlist_free(nvlp);
10480Sstevel@tonic-gate 		rc = ippctl_action_info(aname, flags);
10490Sstevel@tonic-gate 		break;
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 	case IPPCTL_OP_ACTION_MOD:
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate 		/*
10540Sstevel@tonic-gate 		 * Find the module that implements a given action.
10550Sstevel@tonic-gate 		 */
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 		DBG0(DBG_CBOPS, "op = IPPCTL_OP_ACTION_MOD\n");
10580Sstevel@tonic-gate 
10590Sstevel@tonic-gate 		/*
10600Sstevel@tonic-gate 		 * Extract the action name from the nvlist.
10610Sstevel@tonic-gate 		 */
10620Sstevel@tonic-gate 
10630Sstevel@tonic-gate 		if ((rc = ippctl_extract_aname(nvlp, &aname)) != 0) {
10640Sstevel@tonic-gate 			nvlist_free(nvlp);
10650Sstevel@tonic-gate 			return (rc);
10660Sstevel@tonic-gate 		}
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 		nvlist_free(nvlp);
10690Sstevel@tonic-gate 		rc = ippctl_action_mod(aname);
10700Sstevel@tonic-gate 		break;
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 	case IPPCTL_OP_LIST_MODS:
10730Sstevel@tonic-gate 
10740Sstevel@tonic-gate 		/*
10750Sstevel@tonic-gate 		 * List all the modules.
10760Sstevel@tonic-gate 		 */
10770Sstevel@tonic-gate 
10780Sstevel@tonic-gate 		DBG0(DBG_CBOPS, "op = IPPCTL_OP_LIST_MODS\n");
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate 		nvlist_free(nvlp);
10810Sstevel@tonic-gate 		rc = ippctl_list_mods();
10820Sstevel@tonic-gate 		break;
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate 	case IPPCTL_OP_MOD_LIST_ACTIONS:
10850Sstevel@tonic-gate 
10860Sstevel@tonic-gate 		/*
10870Sstevel@tonic-gate 		 * List all the actions for a given module.
10880Sstevel@tonic-gate 		 */
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 		DBG0(DBG_CBOPS, "op = IPPCTL_OP_LIST_MODS\n");
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate 		if ((rc = ippctl_extract_modname(nvlp, &modname)) != 0) {
10930Sstevel@tonic-gate 			nvlist_free(nvlp);
10940Sstevel@tonic-gate 			return (rc);
10950Sstevel@tonic-gate 		}
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 		nvlist_free(nvlp);
10980Sstevel@tonic-gate 		rc = ippctl_mod_list_actions(modname);
10990Sstevel@tonic-gate 		break;
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate 	default:
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate 		/*
11040Sstevel@tonic-gate 		 * Unrecognized opcode.
11050Sstevel@tonic-gate 		 */
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate 		nvlist_free(nvlp);
11080Sstevel@tonic-gate 		rc = EINVAL;
11090Sstevel@tonic-gate 		break;
11100Sstevel@tonic-gate 	}
11110Sstevel@tonic-gate 
11120Sstevel@tonic-gate 	/*
11130Sstevel@tonic-gate 	 * The length of buffer that we need to notify back to libipp with
11140Sstevel@tonic-gate 	 * the command ioctl's return is the length of the first data buffer
11150Sstevel@tonic-gate 	 * in the array. We only expact to pass back data buffers if the
11160Sstevel@tonic-gate 	 * operation succeeds (NOTE: this does not mean the kernel call has
11170Sstevel@tonic-gate 	 * to succeed, merely that we successfully issued it and processed
11180Sstevel@tonic-gate 	 * the results).
11190Sstevel@tonic-gate 	 */
11200Sstevel@tonic-gate 
11210Sstevel@tonic-gate 	if (rc == 0)
11220Sstevel@tonic-gate 		*nextbuflenp = ippctl_array[0].buflen;
11230Sstevel@tonic-gate 
11240Sstevel@tonic-gate 	return (rc);
11250Sstevel@tonic-gate }
11260Sstevel@tonic-gate #undef	__FN__
11270Sstevel@tonic-gate 
11280Sstevel@tonic-gate #define	__FN__	"ippctl_action_create"
11290Sstevel@tonic-gate static int
ippctl_action_create(char * modname,char * aname,nvlist_t * nvlp,ipp_flags_t flags)11300Sstevel@tonic-gate ippctl_action_create(
11310Sstevel@tonic-gate 	char		*modname,
11320Sstevel@tonic-gate 	char		*aname,
11330Sstevel@tonic-gate 	nvlist_t	*nvlp,
11340Sstevel@tonic-gate 	ipp_flags_t	flags)
11350Sstevel@tonic-gate {
11360Sstevel@tonic-gate 	int		ipp_rc;
11370Sstevel@tonic-gate 	int		rc;
11380Sstevel@tonic-gate 	ipp_mod_id_t	mid;
11390Sstevel@tonic-gate 	ipp_action_id_t	aid;
11400Sstevel@tonic-gate 
11410Sstevel@tonic-gate 	/*
11420Sstevel@tonic-gate 	 * Look up the module id from the name and create the new
11430Sstevel@tonic-gate 	 * action.
11440Sstevel@tonic-gate 	 */
11450Sstevel@tonic-gate 
11460Sstevel@tonic-gate 	mid = ipp_mod_lookup(modname);
11470Sstevel@tonic-gate 	FREE_TEXT(modname);
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate 	ipp_rc = ipp_action_create(mid, aname, &nvlp, flags, &aid);
11500Sstevel@tonic-gate 	FREE_TEXT(aname);
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate 	/*
11530Sstevel@tonic-gate 	 * Add an nvlist containing the kernel return code to the
11540Sstevel@tonic-gate 	 * set of nvlists to pass back to libipp.
11550Sstevel@tonic-gate 	 */
11560Sstevel@tonic-gate 
11570Sstevel@tonic-gate 	if ((rc = ippctl_set_rc(ipp_rc)) != 0) {
11580Sstevel@tonic-gate 		if (nvlp != NULL) {
11590Sstevel@tonic-gate 			nvlist_free(nvlp);
11600Sstevel@tonic-gate 			if (ipp_action_destroy(aid, 0) != 0) {
11610Sstevel@tonic-gate 				cmn_err(CE_PANIC,
11620Sstevel@tonic-gate 				    "ippctl: unrecoverable error (aid = %d)",
11630Sstevel@tonic-gate 				    aid);
11640Sstevel@tonic-gate 				/*NOTREACHED*/
11650Sstevel@tonic-gate 			}
11660Sstevel@tonic-gate 		}
11670Sstevel@tonic-gate 		return (rc);
11680Sstevel@tonic-gate 	}
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate 	/*
11710Sstevel@tonic-gate 	 * If the module passed back an nvlist, add this as
11720Sstevel@tonic-gate 	 * well.
11730Sstevel@tonic-gate 	 */
11740Sstevel@tonic-gate 
11750Sstevel@tonic-gate 	if (nvlp != NULL) {
11760Sstevel@tonic-gate 		rc = ippctl_callback(nvlp, NULL);
11770Sstevel@tonic-gate 		nvlist_free(nvlp);
11780Sstevel@tonic-gate 	} else
11790Sstevel@tonic-gate 		rc = 0;
11800Sstevel@tonic-gate 
11810Sstevel@tonic-gate 	return (rc);
11820Sstevel@tonic-gate }
11830Sstevel@tonic-gate #undef	__FN__
11840Sstevel@tonic-gate 
11850Sstevel@tonic-gate #define	__FN__	"ippctl_action_destroy"
11860Sstevel@tonic-gate static int
ippctl_action_destroy(char * aname,ipp_flags_t flags)11870Sstevel@tonic-gate ippctl_action_destroy(
11880Sstevel@tonic-gate 	char		*aname,
11890Sstevel@tonic-gate 	ipp_flags_t	flags)
11900Sstevel@tonic-gate {
11910Sstevel@tonic-gate 	ipp_action_id_t	aid;
11920Sstevel@tonic-gate 	int		ipp_rc;
11930Sstevel@tonic-gate 	int		rc;
11940Sstevel@tonic-gate 
11950Sstevel@tonic-gate 	/*
11960Sstevel@tonic-gate 	 * Look up the action id and destroy the action.
11970Sstevel@tonic-gate 	 */
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate 	aid = ipp_action_lookup(aname);
12000Sstevel@tonic-gate 	FREE_TEXT(aname);
12010Sstevel@tonic-gate 
12020Sstevel@tonic-gate 	ipp_rc = ipp_action_destroy(aid, flags);
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate 	/*
12050Sstevel@tonic-gate 	 * Add an nvlist containing the kernel return code to the
12060Sstevel@tonic-gate 	 * set of nvlists to pass back to libipp.
12070Sstevel@tonic-gate 	 */
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate 	if ((rc = ippctl_set_rc(ipp_rc)) != 0)
12100Sstevel@tonic-gate 		return (rc);
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate 	/*
12130Sstevel@tonic-gate 	 * There's no more information to pass back.
12140Sstevel@tonic-gate 	 */
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate 	return (0);
12170Sstevel@tonic-gate }
12180Sstevel@tonic-gate #undef	__FN__
12190Sstevel@tonic-gate 
12200Sstevel@tonic-gate #define	__FN__	"ippctl_action_modify"
12210Sstevel@tonic-gate static int
ippctl_action_modify(char * aname,nvlist_t * nvlp,ipp_flags_t flags)12220Sstevel@tonic-gate ippctl_action_modify(
12230Sstevel@tonic-gate 	char		*aname,
12240Sstevel@tonic-gate 	nvlist_t	*nvlp,
12250Sstevel@tonic-gate 	ipp_flags_t	flags)
12260Sstevel@tonic-gate {
12270Sstevel@tonic-gate 	ipp_action_id_t	aid;
12280Sstevel@tonic-gate 	int		ipp_rc;
12290Sstevel@tonic-gate 	int		rc;
12300Sstevel@tonic-gate 
12310Sstevel@tonic-gate 	/*
12320Sstevel@tonic-gate 	 * Look up the action id and modify the action.
12330Sstevel@tonic-gate 	 */
12340Sstevel@tonic-gate 
12350Sstevel@tonic-gate 	aid = ipp_action_lookup(aname);
12360Sstevel@tonic-gate 	FREE_TEXT(aname);
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate 	ipp_rc = ipp_action_modify(aid, &nvlp, flags);
12390Sstevel@tonic-gate 
12400Sstevel@tonic-gate 	/*
12410Sstevel@tonic-gate 	 * Add an nvlist containing the kernel return code to the
12420Sstevel@tonic-gate 	 * set of nvlists to pass back to libipp.
12430Sstevel@tonic-gate 	 */
12440Sstevel@tonic-gate 
12450Sstevel@tonic-gate 	if ((rc = ippctl_set_rc(ipp_rc)) != 0) {
12460Sstevel@tonic-gate 		if (nvlp != NULL)
12470Sstevel@tonic-gate 			nvlist_free(nvlp);
12480Sstevel@tonic-gate 		return (rc);
12490Sstevel@tonic-gate 	}
12500Sstevel@tonic-gate 
12510Sstevel@tonic-gate 	/*
12520Sstevel@tonic-gate 	 * If the module passed back an nvlist, add this as
12530Sstevel@tonic-gate 	 * well.
12540Sstevel@tonic-gate 	 */
12550Sstevel@tonic-gate 
12560Sstevel@tonic-gate 	if (nvlp != NULL) {
12570Sstevel@tonic-gate 		rc = ippctl_callback(nvlp, NULL);
12580Sstevel@tonic-gate 		nvlist_free(nvlp);
12590Sstevel@tonic-gate 	} else
12600Sstevel@tonic-gate 		rc = 0;
12610Sstevel@tonic-gate 
12620Sstevel@tonic-gate 	return (rc);
12630Sstevel@tonic-gate }
12640Sstevel@tonic-gate #undef	__FN__
12650Sstevel@tonic-gate 
12660Sstevel@tonic-gate #define	__FN__	"ippctl_action_info"
12670Sstevel@tonic-gate static int
ippctl_action_info(char * aname,ipp_flags_t flags)12680Sstevel@tonic-gate ippctl_action_info(
12690Sstevel@tonic-gate 	char		*aname,
12700Sstevel@tonic-gate 	ipp_flags_t	flags)
12710Sstevel@tonic-gate {
12720Sstevel@tonic-gate 	ipp_action_id_t	aid;
12730Sstevel@tonic-gate 	int		ipp_rc;
12740Sstevel@tonic-gate 	int		rc;
12750Sstevel@tonic-gate 
12760Sstevel@tonic-gate 	/*
12770Sstevel@tonic-gate 	 * Look up the action and call the information retrieval
12780Sstevel@tonic-gate 	 * entry point.
12790Sstevel@tonic-gate 	 *
12800Sstevel@tonic-gate 	 * NOTE: The callback function that is passed in packs and
12810Sstevel@tonic-gate 	 * stores each of the nvlists it is called with in the array
12820Sstevel@tonic-gate 	 * that will be passed back to libipp.
12830Sstevel@tonic-gate 	 */
12840Sstevel@tonic-gate 
12850Sstevel@tonic-gate 	aid = ipp_action_lookup(aname);
12860Sstevel@tonic-gate 	FREE_TEXT(aname);
12870Sstevel@tonic-gate 
12880Sstevel@tonic-gate 	ipp_rc = ipp_action_info(aid, ippctl_callback, NULL, flags);
12890Sstevel@tonic-gate 
12900Sstevel@tonic-gate 	/*
12910Sstevel@tonic-gate 	 * Add an nvlist containing the kernel return code to the
12920Sstevel@tonic-gate 	 * set of nvlists to pass back to libipp.
12930Sstevel@tonic-gate 	 */
12940Sstevel@tonic-gate 
12950Sstevel@tonic-gate 	if ((rc = ippctl_set_rc(ipp_rc)) != 0)
12960Sstevel@tonic-gate 		return (rc);
12970Sstevel@tonic-gate 
12980Sstevel@tonic-gate 	/*
12990Sstevel@tonic-gate 	 * There's no more information to pass back.
13000Sstevel@tonic-gate 	 */
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate 	return (0);
13030Sstevel@tonic-gate }
13040Sstevel@tonic-gate #undef	__FN__
13050Sstevel@tonic-gate 
13060Sstevel@tonic-gate #define	__FN__	"ippctl_action_mod"
13070Sstevel@tonic-gate static int
ippctl_action_mod(char * aname)13080Sstevel@tonic-gate ippctl_action_mod(
13090Sstevel@tonic-gate 	char		*aname)
13100Sstevel@tonic-gate {
13110Sstevel@tonic-gate 	ipp_mod_id_t	mid;
13120Sstevel@tonic-gate 	ipp_action_id_t	aid;
13130Sstevel@tonic-gate 	char		*modname;
13140Sstevel@tonic-gate 	nvlist_t	*nvlp;
13150Sstevel@tonic-gate 	int		ipp_rc;
13160Sstevel@tonic-gate 	int		rc;
13170Sstevel@tonic-gate 
13180Sstevel@tonic-gate 	/*
13190Sstevel@tonic-gate 	 * Look up the action id and get the id of the module that
13200Sstevel@tonic-gate 	 * implements the action. If that succeeds then look up the
13210Sstevel@tonic-gate 	 * name of the module.
13220Sstevel@tonic-gate 	 */
13230Sstevel@tonic-gate 
13240Sstevel@tonic-gate 	aid = ipp_action_lookup(aname);
13250Sstevel@tonic-gate 	FREE_TEXT(aname);
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate 	if ((ipp_rc = ipp_action_mod(aid, &mid)) == 0)
13280Sstevel@tonic-gate 		ipp_rc = ipp_mod_name(mid, &modname);
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 	/*
13310Sstevel@tonic-gate 	 * Add an nvlist containing the kernel return code to the
13320Sstevel@tonic-gate 	 * set of nvlists to pass back to libipp.
13330Sstevel@tonic-gate 	 */
13340Sstevel@tonic-gate 
13350Sstevel@tonic-gate 	if ((rc = ippctl_set_rc(ipp_rc)) != 0)
13360Sstevel@tonic-gate 		return (rc);
13370Sstevel@tonic-gate 
13380Sstevel@tonic-gate 	/*
13390Sstevel@tonic-gate 	 * If everything succeeded add an nvlist containing the
13400Sstevel@tonic-gate 	 * module name to the set of nvlists to pass back to libipp.
13410Sstevel@tonic-gate 	 */
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate 	if (ipp_rc == 0) {
13440Sstevel@tonic-gate 		if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, KM_SLEEP)) != 0)
13450Sstevel@tonic-gate 			return (rc);
13460Sstevel@tonic-gate 
13470Sstevel@tonic-gate 		if ((rc = ippctl_attach_modname(nvlp, modname)) != 0) {
13480Sstevel@tonic-gate 			nvlist_free(nvlp);
13490Sstevel@tonic-gate 			return (rc);
13500Sstevel@tonic-gate 		}
13510Sstevel@tonic-gate 
13520Sstevel@tonic-gate 		FREE_TEXT(modname);
13530Sstevel@tonic-gate 
13540Sstevel@tonic-gate 		rc = ippctl_callback(nvlp, NULL);
13550Sstevel@tonic-gate 		nvlist_free(nvlp);
13560Sstevel@tonic-gate 	} else
13570Sstevel@tonic-gate 		rc = 0;
13580Sstevel@tonic-gate 
13590Sstevel@tonic-gate 	return (rc);
13600Sstevel@tonic-gate }
13610Sstevel@tonic-gate #undef	__FN__
13620Sstevel@tonic-gate 
13630Sstevel@tonic-gate #define	__FN__	"ippctl_list_mods"
13640Sstevel@tonic-gate static int
ippctl_list_mods(void)13650Sstevel@tonic-gate ippctl_list_mods(
13660Sstevel@tonic-gate 	void)
13670Sstevel@tonic-gate {
13680Sstevel@tonic-gate 	nvlist_t	*nvlp;
13690Sstevel@tonic-gate 	int		ipp_rc;
13700Sstevel@tonic-gate 	int		rc = 0;
13710Sstevel@tonic-gate 	ipp_mod_id_t	*mid_array;
13720Sstevel@tonic-gate 	char		**modname_array = NULL;
13730Sstevel@tonic-gate 	int		nelt;
13740Sstevel@tonic-gate 	int		length;
13750Sstevel@tonic-gate 	int		i;
13760Sstevel@tonic-gate 
13770Sstevel@tonic-gate 	/*
13780Sstevel@tonic-gate 	 * Get a list of all the module ids. If that succeeds,
13790Sstevel@tonic-gate 	 * translate the ids into names.
13800Sstevel@tonic-gate 	 *
13810Sstevel@tonic-gate 	 * NOTE: This translation may fail if a module is
13820Sstevel@tonic-gate 	 * unloaded during this operation. If this occurs, EAGAIN
13830Sstevel@tonic-gate 	 * will be passed back to libipp note that a transient
13840Sstevel@tonic-gate 	 * problem occured.
13850Sstevel@tonic-gate 	 */
13860Sstevel@tonic-gate 
13870Sstevel@tonic-gate 	if ((ipp_rc = ipp_list_mods(&mid_array, &nelt)) == 0) {
13880Sstevel@tonic-gate 
13890Sstevel@tonic-gate 		/*
13900Sstevel@tonic-gate 		 * It is possible that there are no modules
13910Sstevel@tonic-gate 		 * registered.
13920Sstevel@tonic-gate 		 */
13930Sstevel@tonic-gate 
13940Sstevel@tonic-gate 		if (nelt > 0) {
13950Sstevel@tonic-gate 			length = nelt * sizeof (char *);
13960Sstevel@tonic-gate 			modname_array = kmem_zalloc(length, KM_SLEEP);
13970Sstevel@tonic-gate 
13980Sstevel@tonic-gate 			for (i = 0; i < nelt; i++) {
13990Sstevel@tonic-gate 				if (ipp_mod_name(mid_array[i],
14000Sstevel@tonic-gate 				    &modname_array[i]) != 0) {
14010Sstevel@tonic-gate 					kmem_free(mid_array, nelt *
14020Sstevel@tonic-gate 					    sizeof (ipp_mod_id_t));
14030Sstevel@tonic-gate 					FREE_TEXT_ARRAY(modname_array, nelt);
14040Sstevel@tonic-gate 					ipp_rc = EAGAIN;
14050Sstevel@tonic-gate 					goto done;
14060Sstevel@tonic-gate 				}
14070Sstevel@tonic-gate 			}
14080Sstevel@tonic-gate 
14090Sstevel@tonic-gate 			kmem_free(mid_array, nelt * sizeof (ipp_mod_id_t));
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate 			if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME,
14120Sstevel@tonic-gate 			    KM_SLEEP)) != 0) {
14130Sstevel@tonic-gate 				FREE_TEXT_ARRAY(modname_array, nelt);
14140Sstevel@tonic-gate 				return (rc);
14150Sstevel@tonic-gate 			}
14160Sstevel@tonic-gate 
14170Sstevel@tonic-gate 			if ((rc = ippctl_attach_modname_array(nvlp,
14180Sstevel@tonic-gate 			    modname_array, nelt)) != 0) {
14190Sstevel@tonic-gate 				FREE_TEXT_ARRAY(modname_array, nelt);
14200Sstevel@tonic-gate 				nvlist_free(nvlp);
14210Sstevel@tonic-gate 				return (rc);
14220Sstevel@tonic-gate 			}
14230Sstevel@tonic-gate 
14240Sstevel@tonic-gate 			FREE_TEXT_ARRAY(modname_array, nelt);
14250Sstevel@tonic-gate 
14260Sstevel@tonic-gate 			if ((rc = ippctl_callback(nvlp, NULL)) != 0) {
14270Sstevel@tonic-gate 				nvlist_free(nvlp);
14280Sstevel@tonic-gate 				return (rc);
14290Sstevel@tonic-gate 			}
14300Sstevel@tonic-gate 
14310Sstevel@tonic-gate 			nvlist_free(nvlp);
14320Sstevel@tonic-gate 		}
14330Sstevel@tonic-gate 	}
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate done:
14360Sstevel@tonic-gate 	/*
14370Sstevel@tonic-gate 	 * Add an nvlist containing the kernel return code to the
14380Sstevel@tonic-gate 	 * set of nvlists to pass back to libipp.
14390Sstevel@tonic-gate 	 */
14400Sstevel@tonic-gate 
14410Sstevel@tonic-gate 	if ((rc = ippctl_set_rc(ipp_rc)) != 0)
14420Sstevel@tonic-gate 		return (rc);
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate 	return (0);
14450Sstevel@tonic-gate }
14460Sstevel@tonic-gate #undef	__FN__
14470Sstevel@tonic-gate 
14480Sstevel@tonic-gate #define	__FN__	"ippctl_mod_list_actions"
14490Sstevel@tonic-gate static int
ippctl_mod_list_actions(char * modname)14500Sstevel@tonic-gate ippctl_mod_list_actions(
14510Sstevel@tonic-gate 	char		*modname)
14520Sstevel@tonic-gate {
14530Sstevel@tonic-gate 	ipp_mod_id_t	mid;
14540Sstevel@tonic-gate 	nvlist_t	*nvlp;
14550Sstevel@tonic-gate 	int		ipp_rc;
14560Sstevel@tonic-gate 	int		rc = 0;
14570Sstevel@tonic-gate 	ipp_action_id_t	*aid_array;
14580Sstevel@tonic-gate 	char		**aname_array = NULL;
14590Sstevel@tonic-gate 	int		nelt;
14600Sstevel@tonic-gate 	int		length;
14610Sstevel@tonic-gate 	int		i;
14620Sstevel@tonic-gate 
14630Sstevel@tonic-gate 	/*
14640Sstevel@tonic-gate 	 * Get the module id.
14650Sstevel@tonic-gate 	 */
14660Sstevel@tonic-gate 
14670Sstevel@tonic-gate 	mid = ipp_mod_lookup(modname);
14680Sstevel@tonic-gate 	FREE_TEXT(modname);
14690Sstevel@tonic-gate 
14700Sstevel@tonic-gate 	/*
14710Sstevel@tonic-gate 	 * Get a list of all the action ids for the module. If that succeeds,
14720Sstevel@tonic-gate 	 * translate the ids into names.
14730Sstevel@tonic-gate 	 *
14740Sstevel@tonic-gate 	 * NOTE: This translation may fail if an action is
14750Sstevel@tonic-gate 	 * destroyed during this operation. If this occurs, EAGAIN
14760Sstevel@tonic-gate 	 * will be passed back to libipp note that a transient
14770Sstevel@tonic-gate 	 * problem occured.
14780Sstevel@tonic-gate 	 */
14790Sstevel@tonic-gate 
14800Sstevel@tonic-gate 	if ((ipp_rc = ipp_mod_list_actions(mid, &aid_array, &nelt)) == 0) {
14810Sstevel@tonic-gate 
14820Sstevel@tonic-gate 		/*
14830Sstevel@tonic-gate 		 * It is possible that there are no actions defined.
14840Sstevel@tonic-gate 		 * (This is unlikely though as the module would normally
14850Sstevel@tonic-gate 		 * be auto-unloaded fairly quickly)
14860Sstevel@tonic-gate 		 */
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate 		if (nelt > 0) {
14890Sstevel@tonic-gate 			length = nelt * sizeof (char *);
14900Sstevel@tonic-gate 			aname_array = kmem_zalloc(length, KM_SLEEP);
14910Sstevel@tonic-gate 
14920Sstevel@tonic-gate 			for (i = 0; i < nelt; i++) {
14930Sstevel@tonic-gate 				if (ipp_action_name(aid_array[i],
14940Sstevel@tonic-gate 				    &aname_array[i]) != 0) {
14950Sstevel@tonic-gate 					kmem_free(aid_array, nelt *
14960Sstevel@tonic-gate 					    sizeof (ipp_action_id_t));
14970Sstevel@tonic-gate 					FREE_TEXT_ARRAY(aname_array, nelt);
14980Sstevel@tonic-gate 					ipp_rc = EAGAIN;
14990Sstevel@tonic-gate 					goto done;
15000Sstevel@tonic-gate 				}
15010Sstevel@tonic-gate 			}
15020Sstevel@tonic-gate 
15030Sstevel@tonic-gate 			kmem_free(aid_array, nelt * sizeof (ipp_action_id_t));
15040Sstevel@tonic-gate 
15050Sstevel@tonic-gate 			if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME,
15060Sstevel@tonic-gate 			    KM_SLEEP)) != 0) {
15070Sstevel@tonic-gate 				FREE_TEXT_ARRAY(aname_array, nelt);
15080Sstevel@tonic-gate 				return (rc);
15090Sstevel@tonic-gate 			}
15100Sstevel@tonic-gate 
15110Sstevel@tonic-gate 			if ((rc = ippctl_attach_aname_array(nvlp, aname_array,
15120Sstevel@tonic-gate 			    nelt)) != 0) {
15130Sstevel@tonic-gate 				FREE_TEXT_ARRAY(aname_array, nelt);
15140Sstevel@tonic-gate 				nvlist_free(nvlp);
15150Sstevel@tonic-gate 				return (rc);
15160Sstevel@tonic-gate 			}
15170Sstevel@tonic-gate 
15180Sstevel@tonic-gate 			FREE_TEXT_ARRAY(aname_array, nelt);
15190Sstevel@tonic-gate 
15200Sstevel@tonic-gate 			if ((rc = ippctl_callback(nvlp, NULL)) != 0) {
15210Sstevel@tonic-gate 				nvlist_free(nvlp);
15220Sstevel@tonic-gate 				return (rc);
15230Sstevel@tonic-gate 			}
15240Sstevel@tonic-gate 
15250Sstevel@tonic-gate 			nvlist_free(nvlp);
15260Sstevel@tonic-gate 		}
15270Sstevel@tonic-gate 	}
15280Sstevel@tonic-gate 
15290Sstevel@tonic-gate done:
15300Sstevel@tonic-gate 	/*
15310Sstevel@tonic-gate 	 * Add an nvlist containing the kernel return code to the
15320Sstevel@tonic-gate 	 * set of nvlists to pass back to libipp.
15330Sstevel@tonic-gate 	 */
15340Sstevel@tonic-gate 
15350Sstevel@tonic-gate 	if ((rc = ippctl_set_rc(ipp_rc)) != 0)
15360Sstevel@tonic-gate 		return (rc);
15370Sstevel@tonic-gate 
15380Sstevel@tonic-gate 	return (0);
15390Sstevel@tonic-gate }
15400Sstevel@tonic-gate #undef	__FN__
15410Sstevel@tonic-gate 
15420Sstevel@tonic-gate #define	__FN__	"ippctl_data"
15430Sstevel@tonic-gate static int
ippctl_data(char ** dbufp,size_t * dbuflenp,size_t * nextbuflenp)15440Sstevel@tonic-gate ippctl_data(
15450Sstevel@tonic-gate 	char	**dbufp,
15460Sstevel@tonic-gate 	size_t	*dbuflenp,
15470Sstevel@tonic-gate 	size_t	*nextbuflenp)
15480Sstevel@tonic-gate {
15490Sstevel@tonic-gate 	int	i;
15500Sstevel@tonic-gate 
15510Sstevel@tonic-gate 	DBG0(DBG_CBOPS, "called\n");
15520Sstevel@tonic-gate 
15530Sstevel@tonic-gate 	/*
15540Sstevel@tonic-gate 	 * Get the next data buffer from the array by looking at the
15550Sstevel@tonic-gate 	 * 'read index'. If this is the same as the 'write index' then
15560Sstevel@tonic-gate 	 * there's no more buffers in the array.
15570Sstevel@tonic-gate 	 */
15580Sstevel@tonic-gate 
15590Sstevel@tonic-gate 	i = ippctl_rindex;
15600Sstevel@tonic-gate 	if (i == ippctl_windex)
15610Sstevel@tonic-gate 		return (ENOENT);
15620Sstevel@tonic-gate 
15630Sstevel@tonic-gate 	/*
15640Sstevel@tonic-gate 	 * Extract the buffer details. It is a pre-packed nvlist.
15650Sstevel@tonic-gate 	 */
15660Sstevel@tonic-gate 
15670Sstevel@tonic-gate 	*dbufp = ippctl_array[i].buf;
15680Sstevel@tonic-gate 	*dbuflenp = ippctl_array[i].buflen;
15690Sstevel@tonic-gate 
15700Sstevel@tonic-gate 	DBG2(DBG_CBOPS, "accessing nvlist[%d], length %lu\n", i, *dbuflenp);
15710Sstevel@tonic-gate 	ASSERT(*dbufp != NULL);
15720Sstevel@tonic-gate 
15730Sstevel@tonic-gate 	/*
15740Sstevel@tonic-gate 	 * Advance the 'read index' and check if there's another buffer.
15750Sstevel@tonic-gate 	 * If there is then we need to pass back its length to libipp so that
15760Sstevel@tonic-gate 	 * another data ioctl will be issued.
15770Sstevel@tonic-gate 	 */
15780Sstevel@tonic-gate 
15790Sstevel@tonic-gate 	i++;
15800Sstevel@tonic-gate 	if (i < ippctl_windex)
15810Sstevel@tonic-gate 		*nextbuflenp = ippctl_array[i].buflen;
15820Sstevel@tonic-gate 	else
15830Sstevel@tonic-gate 		*nextbuflenp = 0;
15840Sstevel@tonic-gate 
15850Sstevel@tonic-gate 	ippctl_rindex = i;
15860Sstevel@tonic-gate 	return (0);
15870Sstevel@tonic-gate }
15880Sstevel@tonic-gate #undef	__FN__
15890Sstevel@tonic-gate 
15900Sstevel@tonic-gate #define	__FN__	"ippctl_flush"
15910Sstevel@tonic-gate static void
ippctl_flush(void)15920Sstevel@tonic-gate ippctl_flush(
15930Sstevel@tonic-gate 	void)
15940Sstevel@tonic-gate {
15950Sstevel@tonic-gate 	int	i;
15960Sstevel@tonic-gate 	char	*buf;
15970Sstevel@tonic-gate 	size_t	buflen;
15980Sstevel@tonic-gate 
15990Sstevel@tonic-gate 	/*
16000Sstevel@tonic-gate 	 * Free any buffers left in the array.
16010Sstevel@tonic-gate 	 */
16020Sstevel@tonic-gate 
16030Sstevel@tonic-gate 	for (i = 0; i < ippctl_limit; i++) {
16040Sstevel@tonic-gate 		if ((buflen = ippctl_array[i].buflen) > 0) {
16050Sstevel@tonic-gate 			buf = ippctl_array[i].buf;
16060Sstevel@tonic-gate 			ASSERT(buf != NULL);
16070Sstevel@tonic-gate 			kmem_free(buf, buflen);
16080Sstevel@tonic-gate 		}
16090Sstevel@tonic-gate 	}
16100Sstevel@tonic-gate 
16110Sstevel@tonic-gate 	/*
16120Sstevel@tonic-gate 	 * NULL all the entries.
16130Sstevel@tonic-gate 	 */
16140Sstevel@tonic-gate 
16150Sstevel@tonic-gate 	bzero(ippctl_array, ippctl_limit * sizeof (ippctl_buf_t));
16160Sstevel@tonic-gate 
16170Sstevel@tonic-gate 	/*
16180Sstevel@tonic-gate 	 * Reset the indexes.
16190Sstevel@tonic-gate 	 */
16200Sstevel@tonic-gate 
16210Sstevel@tonic-gate 	ippctl_rindex = 0;
16220Sstevel@tonic-gate 	ippctl_windex = 1;
16230Sstevel@tonic-gate }
16240Sstevel@tonic-gate #undef	__FN__
16250Sstevel@tonic-gate 
16260Sstevel@tonic-gate #define	__FN__	"ippctl_add_nvlist"
16270Sstevel@tonic-gate static int
ippctl_add_nvlist(nvlist_t * nvlp,int i)16280Sstevel@tonic-gate ippctl_add_nvlist(
16290Sstevel@tonic-gate 	nvlist_t	*nvlp,
16300Sstevel@tonic-gate 	int		i)
16310Sstevel@tonic-gate {
16320Sstevel@tonic-gate 	char		*buf;
16330Sstevel@tonic-gate 	size_t		buflen;
16340Sstevel@tonic-gate 	int		rc;
16350Sstevel@tonic-gate 
16360Sstevel@tonic-gate 	/*
16370Sstevel@tonic-gate 	 * NULL the buffer pointer so that a buffer is automatically
16380Sstevel@tonic-gate 	 * allocated for us.
16390Sstevel@tonic-gate 	 */
16400Sstevel@tonic-gate 
16410Sstevel@tonic-gate 	buf = NULL;
16420Sstevel@tonic-gate 
16430Sstevel@tonic-gate 	/*
16440Sstevel@tonic-gate 	 * Pack the nvlist and get back the buffer pointer and length.
16450Sstevel@tonic-gate 	 */
16460Sstevel@tonic-gate 
16470Sstevel@tonic-gate 	if ((rc = nvlist_pack(nvlp, &buf, &buflen, NV_ENCODE_NATIVE,
16480Sstevel@tonic-gate 	    KM_SLEEP)) != 0) {
16490Sstevel@tonic-gate 		ippctl_array[i].buf = NULL;
16500Sstevel@tonic-gate 		ippctl_array[i].buflen = 0;
16510Sstevel@tonic-gate 		return (rc);
16520Sstevel@tonic-gate 	}
16530Sstevel@tonic-gate 
16540Sstevel@tonic-gate 	DBG2(DBG_CBOPS, "added nvlist[%d]: length %lu\n", i, buflen);
16550Sstevel@tonic-gate 
16560Sstevel@tonic-gate 	/*
16570Sstevel@tonic-gate 	 * Store the pointer an length in the array at the given index.
16580Sstevel@tonic-gate 	 */
16590Sstevel@tonic-gate 
16600Sstevel@tonic-gate 	ippctl_array[i].buf = buf;
16610Sstevel@tonic-gate 	ippctl_array[i].buflen = buflen;
16620Sstevel@tonic-gate 
16630Sstevel@tonic-gate 	return (0);
16640Sstevel@tonic-gate }
16650Sstevel@tonic-gate #undef	__FN__
16660Sstevel@tonic-gate 
16670Sstevel@tonic-gate #define	__FN__	"ippctl_callback"
16680Sstevel@tonic-gate /*ARGSUSED*/
16690Sstevel@tonic-gate static int
ippctl_callback(nvlist_t * nvlp,void * arg)16700Sstevel@tonic-gate ippctl_callback(
16710Sstevel@tonic-gate 	nvlist_t	*nvlp,
16720Sstevel@tonic-gate 	void		*arg)
16730Sstevel@tonic-gate {
16740Sstevel@tonic-gate 	int		i;
16750Sstevel@tonic-gate 	int		rc;
16760Sstevel@tonic-gate 
16770Sstevel@tonic-gate 	/*
16780Sstevel@tonic-gate 	 * Check the 'write index' to see if there's space in the array for
16790Sstevel@tonic-gate 	 * a new entry.
16800Sstevel@tonic-gate 	 */
16810Sstevel@tonic-gate 
16820Sstevel@tonic-gate 	i = ippctl_windex;
16830Sstevel@tonic-gate 	ASSERT(i != 0);
16840Sstevel@tonic-gate 
16850Sstevel@tonic-gate 	/*
16860Sstevel@tonic-gate 	 * If there's no space, re-allocate the array (see comments in
16870Sstevel@tonic-gate 	 * ippctl_realloc() for details).
16880Sstevel@tonic-gate 	 */
16890Sstevel@tonic-gate 
16900Sstevel@tonic-gate 	if (i == ippctl_limit)
16910Sstevel@tonic-gate 		ippctl_realloc();
16920Sstevel@tonic-gate 
16930Sstevel@tonic-gate 	/*
16940Sstevel@tonic-gate 	 * Add the nvlist to the array.
16950Sstevel@tonic-gate 	 */
16960Sstevel@tonic-gate 
16970Sstevel@tonic-gate 	if ((rc = ippctl_add_nvlist(nvlp, i)) == 0)
16980Sstevel@tonic-gate 		ippctl_windex++;
16990Sstevel@tonic-gate 
17000Sstevel@tonic-gate 	return (rc);
17010Sstevel@tonic-gate }
17020Sstevel@tonic-gate #undef	__FN__
17030Sstevel@tonic-gate 
17040Sstevel@tonic-gate #define	__FN__	"ippctl_set_rc"
17050Sstevel@tonic-gate static int
ippctl_set_rc(int val)17060Sstevel@tonic-gate ippctl_set_rc(
17070Sstevel@tonic-gate 	int		val)
17080Sstevel@tonic-gate {
17090Sstevel@tonic-gate 	nvlist_t	*nvlp;
17100Sstevel@tonic-gate 	int		rc;
17110Sstevel@tonic-gate 
17120Sstevel@tonic-gate 	/*
17130Sstevel@tonic-gate 	 * Create an nvlist to store the return code,
17140Sstevel@tonic-gate 	 */
17150Sstevel@tonic-gate 
17160Sstevel@tonic-gate 	if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, KM_SLEEP)) != 0)
17170Sstevel@tonic-gate 		return (ENOMEM);
17180Sstevel@tonic-gate 
17190Sstevel@tonic-gate 	if ((rc = nvlist_add_int32(nvlp, IPPCTL_RC, val)) != 0) {
17200Sstevel@tonic-gate 		nvlist_free(nvlp);
17210Sstevel@tonic-gate 		return (rc);
17220Sstevel@tonic-gate 	}
17230Sstevel@tonic-gate 
17240Sstevel@tonic-gate 	/*
17250Sstevel@tonic-gate 	 * Add it at the beginning of the array.
17260Sstevel@tonic-gate 	 */
17270Sstevel@tonic-gate 
17280Sstevel@tonic-gate 	rc = ippctl_add_nvlist(nvlp, 0);
17290Sstevel@tonic-gate 
17300Sstevel@tonic-gate 	nvlist_free(nvlp);
17310Sstevel@tonic-gate 	return (rc);
17320Sstevel@tonic-gate }
17330Sstevel@tonic-gate #undef	__FN__
17340Sstevel@tonic-gate 
17350Sstevel@tonic-gate #define	__FN__	"ippctl_alloc"
17360Sstevel@tonic-gate static void
ippctl_alloc(int limit)17370Sstevel@tonic-gate ippctl_alloc(
17380Sstevel@tonic-gate 	int	limit)
17390Sstevel@tonic-gate {
17400Sstevel@tonic-gate 	/*
17410Sstevel@tonic-gate 	 * Allocate the data buffer array and initialize the indexes.
17420Sstevel@tonic-gate 	 */
17430Sstevel@tonic-gate 
17440Sstevel@tonic-gate 	ippctl_array = kmem_zalloc(limit * sizeof (ippctl_buf_t), KM_SLEEP);
17450Sstevel@tonic-gate 	ippctl_limit = limit;
17460Sstevel@tonic-gate 	ippctl_rindex = 0;
17470Sstevel@tonic-gate 	ippctl_windex = 1;
17480Sstevel@tonic-gate }
17490Sstevel@tonic-gate #undef	__FN__
17500Sstevel@tonic-gate 
17510Sstevel@tonic-gate #define	__FN__	"ippctl_realloc"
17520Sstevel@tonic-gate static void
ippctl_realloc(void)17530Sstevel@tonic-gate ippctl_realloc(
17540Sstevel@tonic-gate 	void)
17550Sstevel@tonic-gate {
17560Sstevel@tonic-gate 	ippctl_buf_t	*array;
17570Sstevel@tonic-gate 	int		limit;
17580Sstevel@tonic-gate 	int		i;
17590Sstevel@tonic-gate 
17600Sstevel@tonic-gate 	/*
17610Sstevel@tonic-gate 	 * Allocate a new array twice the size of the old one.
17620Sstevel@tonic-gate 	 */
17630Sstevel@tonic-gate 
17640Sstevel@tonic-gate 	limit = ippctl_limit << 1;
17650Sstevel@tonic-gate 	array = kmem_zalloc(limit * sizeof (ippctl_buf_t), KM_SLEEP);
17660Sstevel@tonic-gate 
17670Sstevel@tonic-gate 	/*
17680Sstevel@tonic-gate 	 * Copy across the information from the old array into the new one.
17690Sstevel@tonic-gate 	 */
17700Sstevel@tonic-gate 
17710Sstevel@tonic-gate 	for (i = 0; i < ippctl_limit; i++)
17720Sstevel@tonic-gate 		array[i] = ippctl_array[i];
17730Sstevel@tonic-gate 
17740Sstevel@tonic-gate 	/*
17750Sstevel@tonic-gate 	 * Free the old array.
17760Sstevel@tonic-gate 	 */
17770Sstevel@tonic-gate 
17780Sstevel@tonic-gate 	kmem_free(ippctl_array, ippctl_limit * sizeof (ippctl_buf_t));
17790Sstevel@tonic-gate 
17800Sstevel@tonic-gate 	ippctl_array = array;
17810Sstevel@tonic-gate 	ippctl_limit = limit;
17820Sstevel@tonic-gate }
17830Sstevel@tonic-gate #undef	__FN__
17840Sstevel@tonic-gate 
17850Sstevel@tonic-gate #define	__FN__	"ippctl_free"
17860Sstevel@tonic-gate static void
ippctl_free(void)17870Sstevel@tonic-gate ippctl_free(
17880Sstevel@tonic-gate 	void)
17890Sstevel@tonic-gate {
17900Sstevel@tonic-gate 	/*
17910Sstevel@tonic-gate 	 * Flush the array prior to freeing it to make sure no buffers are
17920Sstevel@tonic-gate 	 * leaked.
17930Sstevel@tonic-gate 	 */
17940Sstevel@tonic-gate 
17950Sstevel@tonic-gate 	ippctl_flush();
17960Sstevel@tonic-gate 
17970Sstevel@tonic-gate 	/*
17980Sstevel@tonic-gate 	 * Free the array.
17990Sstevel@tonic-gate 	 */
18000Sstevel@tonic-gate 
18010Sstevel@tonic-gate 	kmem_free(ippctl_array, ippctl_limit * sizeof (ippctl_buf_t));
18020Sstevel@tonic-gate 	ippctl_array = NULL;
18030Sstevel@tonic-gate 	ippctl_limit = -1;
18040Sstevel@tonic-gate 	ippctl_rindex = -1;
18050Sstevel@tonic-gate 	ippctl_windex = -1;
18060Sstevel@tonic-gate }
18070Sstevel@tonic-gate #undef	__FN__
18080Sstevel@tonic-gate 
18090Sstevel@tonic-gate #ifdef	IPPCTL_DEBUG
18100Sstevel@tonic-gate static void
ippctl_debug(uint64_t type,char * fn,char * fmt,...)18110Sstevel@tonic-gate ippctl_debug(
18120Sstevel@tonic-gate 	uint64_t	type,
18130Sstevel@tonic-gate 	char		*fn,
18140Sstevel@tonic-gate 	char		*fmt,
18150Sstevel@tonic-gate 			...)
18160Sstevel@tonic-gate {
18170Sstevel@tonic-gate 	char		buf[255];
18180Sstevel@tonic-gate 	va_list		adx;
18190Sstevel@tonic-gate 
18200Sstevel@tonic-gate 	if ((type & ippctl_debug_flags) == 0)
18210Sstevel@tonic-gate 		return;
18220Sstevel@tonic-gate 
18230Sstevel@tonic-gate 	mutex_enter(debug_mutex);
18240Sstevel@tonic-gate 	va_start(adx, fmt);
18250Sstevel@tonic-gate 	(void) vsnprintf(buf, 255, fmt, adx);
18260Sstevel@tonic-gate 	va_end(adx);
18270Sstevel@tonic-gate 
18280Sstevel@tonic-gate 	printf("%s: %s", fn, buf);
18290Sstevel@tonic-gate 	mutex_exit(debug_mutex);
18300Sstevel@tonic-gate }
18310Sstevel@tonic-gate #endif	/* IPPCTL_DBG */
1832