xref: /onnv-gate/usr/src/uts/common/ipp/dscpmk/dscpmkddi.c (revision 7862:f8b6a07acfd6)
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*7862SRichard.Bean@Sun.COM  * Common Development and Distribution License (the "License").
6*7862SRichard.Bean@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*7862SRichard.Bean@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 #include <sys/types.h>
270Sstevel@tonic-gate #include <sys/systm.h>
280Sstevel@tonic-gate #include <sys/socket.h>
290Sstevel@tonic-gate #include <netinet/in.h>
300Sstevel@tonic-gate #include <sys/modctl.h>
310Sstevel@tonic-gate #include <sys/sunddi.h>
320Sstevel@tonic-gate #include <ipp/ipp.h>
330Sstevel@tonic-gate #include <ipp/ipp_config.h>
340Sstevel@tonic-gate #include <inet/common.h>
350Sstevel@tonic-gate #include <ipp/dscpmk/dscpmk_impl.h>
360Sstevel@tonic-gate 
370Sstevel@tonic-gate #define	D_SM_COMMENT	"IPP dscpmk marker module"
380Sstevel@tonic-gate 
390Sstevel@tonic-gate /* DDI file for dscpmk ipp module */
400Sstevel@tonic-gate 
410Sstevel@tonic-gate /* default dscp map - dscp unchanged */
420Sstevel@tonic-gate uint8_t default_dscp_map[DSCPMK_ARRAY_COUNT] = {
430Sstevel@tonic-gate 	0,	1,	2,	3,
440Sstevel@tonic-gate 	4,	5,	6,	7,
450Sstevel@tonic-gate 	8,	9,	10,	11,
460Sstevel@tonic-gate 	12,	13,	14,	15,
470Sstevel@tonic-gate 	16,	17,	18,	19,
480Sstevel@tonic-gate 	20,	21,	22,	23,
490Sstevel@tonic-gate 	24,	25,	26,	27,
500Sstevel@tonic-gate 	28,	29,	30,	31,
510Sstevel@tonic-gate 	32,	33,	34,	35,
520Sstevel@tonic-gate 	36,	37,	38,	39,
530Sstevel@tonic-gate 	40,	41,	42,	43,
540Sstevel@tonic-gate 	44,	45,	46,	47,
550Sstevel@tonic-gate 	48,	49,	50,	51,
560Sstevel@tonic-gate 	52,	53,	54,	55,
570Sstevel@tonic-gate 	56,	57,	58,	59,
580Sstevel@tonic-gate 	60,	61,	62,	63
590Sstevel@tonic-gate };
600Sstevel@tonic-gate 
610Sstevel@tonic-gate static int dscpmk_create_action(ipp_action_id_t, nvlist_t **, ipp_flags_t);
620Sstevel@tonic-gate static int dscpmk_modify_action(ipp_action_id_t, nvlist_t **, ipp_flags_t);
630Sstevel@tonic-gate static int dscpmk_destroy_action(ipp_action_id_t, ipp_flags_t);
640Sstevel@tonic-gate static int dscpmk_info(ipp_action_id_t, int (*)(nvlist_t *, void *), void *,
650Sstevel@tonic-gate     ipp_flags_t);
660Sstevel@tonic-gate static int dscpmk_invoke_action(ipp_action_id_t, ipp_packet_t *);
670Sstevel@tonic-gate 
680Sstevel@tonic-gate /* Creating and updating summary stats */
690Sstevel@tonic-gate static int dscpmk_summ_statinit(ipp_action_id_t, dscpmk_data_t *);
700Sstevel@tonic-gate static int dscpmk_update_stats(ipp_stat_t *, void *, int);
710Sstevel@tonic-gate 
720Sstevel@tonic-gate /* Creating and updating per-dscp stats */
730Sstevel@tonic-gate static int dscpmk_det_statinit(ipp_action_id_t, dscpmk_data_t *, int);
740Sstevel@tonic-gate static int dscpmk_update_det_stats(ipp_stat_t *, void *, int);
750Sstevel@tonic-gate 
760Sstevel@tonic-gate /* Entry points for this IPP module */
770Sstevel@tonic-gate ipp_ops_t dscpmk_ops = {
780Sstevel@tonic-gate 	IPPO_REV,
790Sstevel@tonic-gate 	dscpmk_create_action,	/* ippo_action_create */
800Sstevel@tonic-gate 	dscpmk_modify_action,	/* ippo_action_modify */
810Sstevel@tonic-gate 	dscpmk_destroy_action,	/* ippo_action_destroy */
820Sstevel@tonic-gate 	dscpmk_info,		/* ippo_action_info */
830Sstevel@tonic-gate 	dscpmk_invoke_action	/* ippo_action_invoke */
840Sstevel@tonic-gate };
850Sstevel@tonic-gate 
860Sstevel@tonic-gate extern struct mod_ops mod_ippops;
870Sstevel@tonic-gate 
880Sstevel@tonic-gate /*
890Sstevel@tonic-gate  * Module linkage information for the kernel.
900Sstevel@tonic-gate  */
910Sstevel@tonic-gate static struct modlipp modlipp = {
920Sstevel@tonic-gate 	&mod_ippops,
93*7862SRichard.Bean@Sun.COM 	D_SM_COMMENT,
940Sstevel@tonic-gate 	&dscpmk_ops
950Sstevel@tonic-gate };
960Sstevel@tonic-gate 
970Sstevel@tonic-gate static struct modlinkage modlinkage = {
980Sstevel@tonic-gate 	MODREV_1,
990Sstevel@tonic-gate 	(void *)&modlipp,
1000Sstevel@tonic-gate 	NULL
1010Sstevel@tonic-gate };
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate int
_init(void)1050Sstevel@tonic-gate _init(void)
1060Sstevel@tonic-gate {
1070Sstevel@tonic-gate 	return (mod_install(&modlinkage));
1080Sstevel@tonic-gate }
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate int
_fini(void)1110Sstevel@tonic-gate _fini(void)
1120Sstevel@tonic-gate {
1130Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
1140Sstevel@tonic-gate }
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1170Sstevel@tonic-gate _info(struct modinfo *modinfop)
1180Sstevel@tonic-gate {
1190Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1200Sstevel@tonic-gate }
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate static int
dscpmk_create_action(ipp_action_id_t aid,nvlist_t ** nvlpp,ipp_flags_t flags)1230Sstevel@tonic-gate dscpmk_create_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags)
1240Sstevel@tonic-gate {
1250Sstevel@tonic-gate 	nvlist_t *nvlp;
1260Sstevel@tonic-gate 	dscpmk_data_t *dscpmk_data;
1270Sstevel@tonic-gate 	char *next_action;
1280Sstevel@tonic-gate 	int err, cnt;
1290Sstevel@tonic-gate 	int32_t *tbl;
1300Sstevel@tonic-gate 	uint_t nelem = DSCPMK_ARRAY_COUNT;
1310Sstevel@tonic-gate 	uint32_t bstats;
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate 	ASSERT((nvlpp != NULL) && (*nvlpp != NULL));
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 	nvlp = *nvlpp;
1360Sstevel@tonic-gate 	*nvlpp = NULL;		/* nvlist should be NULL on return */
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	if ((dscpmk_data = kmem_zalloc(DSCPMK_DATA_SZ, KM_NOSLEEP)) == NULL) {
1390Sstevel@tonic-gate 		nvlist_free(nvlp);
1400Sstevel@tonic-gate 		return (ENOMEM);
1410Sstevel@tonic-gate 	}
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 	/* parse next action name */
1440Sstevel@tonic-gate 	if ((err = nvlist_lookup_string(nvlp, DSCPMK_NEXT_ACTION_NAME,
1450Sstevel@tonic-gate 	    &next_action)) != 0) {
1460Sstevel@tonic-gate 		nvlist_free(nvlp);
1470Sstevel@tonic-gate 		dscpmk0dbg(("dscpmk_create_action: invalid config, " \
1480Sstevel@tonic-gate 		    "next_action name missing\n"));
1490Sstevel@tonic-gate 		kmem_free(dscpmk_data, DSCPMK_DATA_SZ);
1500Sstevel@tonic-gate 		return (err);
1510Sstevel@tonic-gate 	}
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	if ((dscpmk_data->next_action = ipp_action_lookup(next_action))
1540Sstevel@tonic-gate 	    == IPP_ACTION_INVAL) {
1550Sstevel@tonic-gate 		nvlist_free(nvlp);
1560Sstevel@tonic-gate 		dscpmk0dbg(("dscpmk_create_action: next_action "\
1570Sstevel@tonic-gate 		    "invalid\n"));
1580Sstevel@tonic-gate 		kmem_free(dscpmk_data, DSCPMK_DATA_SZ);
1590Sstevel@tonic-gate 		return (EINVAL);
1600Sstevel@tonic-gate 	}
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 	/* Fill in the default value */
1630Sstevel@tonic-gate 	bcopy(default_dscp_map, dscpmk_data->dscp_map,
1640Sstevel@tonic-gate 	    sizeof (default_dscp_map));
1650Sstevel@tonic-gate 	/*
1660Sstevel@tonic-gate 	 * parse dscp_map, if present. Note that the module gets
1670Sstevel@tonic-gate 	 * the entire array with unchanged entries marked with -1.
1680Sstevel@tonic-gate 	 */
1690Sstevel@tonic-gate 	if ((err = nvlist_lookup_int32_array(nvlp, DSCPMK_DSCP_MAP,
1700Sstevel@tonic-gate 	    &tbl, &nelem)) == 0) {
1710Sstevel@tonic-gate 		for (cnt = 0; cnt < DSCPMK_ARRAY_COUNT; cnt++) {
1720Sstevel@tonic-gate 			if ((tbl[cnt] != DSCPMK_UNCHANGED_DSCP) && (tbl[cnt] !=
1730Sstevel@tonic-gate 			    dscpmk_data->dscp_map[cnt])) {
1740Sstevel@tonic-gate 				dscpmk_data->dscp_map[cnt] = tbl[cnt];
1750Sstevel@tonic-gate 			}
1760Sstevel@tonic-gate 		}
1770Sstevel@tonic-gate 	}
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	/* parse summary_stats boolean */
1810Sstevel@tonic-gate 	if ((err = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, &bstats))
1820Sstevel@tonic-gate 	    != 0) {
1830Sstevel@tonic-gate 		dscpmk_data->summary_stats = B_FALSE;
1840Sstevel@tonic-gate 	} else {
1850Sstevel@tonic-gate 		dscpmk_data->summary_stats = (bstats != 0) ? B_TRUE : B_FALSE;
1860Sstevel@tonic-gate 		/* If stats is needed, initialize the stats structure */
1870Sstevel@tonic-gate 		if (dscpmk_data->summary_stats) {
1880Sstevel@tonic-gate 			if ((err = dscpmk_summ_statinit(aid, dscpmk_data))
1890Sstevel@tonic-gate 			    != 0) {
1900Sstevel@tonic-gate 				nvlist_free(nvlp);
1910Sstevel@tonic-gate 				kmem_free(dscpmk_data, DSCPMK_DATA_SZ);
1920Sstevel@tonic-gate 				return (err);
1930Sstevel@tonic-gate 			}
1940Sstevel@tonic-gate 		}
1950Sstevel@tonic-gate 	}
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 	/*
1980Sstevel@tonic-gate 	 * Initialize per-dscp stats; B_FALSE in present indicates a dscp
1990Sstevel@tonic-gate 	 * with this value (count) is not present in the map.
2000Sstevel@tonic-gate 	 */
2010Sstevel@tonic-gate 	for (cnt = 0; cnt < DSCPMK_ARRAY_COUNT; cnt++) {
2020Sstevel@tonic-gate 		dscpmk_data->dscp_stats[cnt].present = B_FALSE;
2030Sstevel@tonic-gate 		dscpmk_data->dscp_stats[cnt].npackets = 0;
2040Sstevel@tonic-gate 	}
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	/* parse detailed_stats boolean */
2070Sstevel@tonic-gate 	if ((err = nvlist_lookup_uint32(nvlp, DSCPMK_DETAILED_STATS, &bstats))
2080Sstevel@tonic-gate 	    != 0) {
2090Sstevel@tonic-gate 		dscpmk_data->detailed_stats = B_FALSE;
2100Sstevel@tonic-gate 	} else {
2110Sstevel@tonic-gate 		dscpmk_data->detailed_stats = (bstats != 0) ? B_TRUE : B_FALSE;
2120Sstevel@tonic-gate 		/* If stats is needed, initialize the stats structure */
2130Sstevel@tonic-gate 		if (dscpmk_data->detailed_stats) {
2140Sstevel@tonic-gate 			for (cnt = 0; cnt < DSCPMK_ARRAY_COUNT; cnt++) {
2150Sstevel@tonic-gate 				int val = dscpmk_data->dscp_map[cnt];
2160Sstevel@tonic-gate 				if (dscpmk_data->dscp_stats[val].present) {
2170Sstevel@tonic-gate 					continue;
2180Sstevel@tonic-gate 				}
2190Sstevel@tonic-gate 				dscpmk_data->dscp_stats[val].present = B_TRUE;
2200Sstevel@tonic-gate 				if ((err = dscpmk_det_statinit(aid, dscpmk_data,
2210Sstevel@tonic-gate 				    val)) != 0) {
2220Sstevel@tonic-gate 					nvlist_free(nvlp);
2230Sstevel@tonic-gate 					kmem_free(dscpmk_data, DSCPMK_DATA_SZ);
2240Sstevel@tonic-gate 					return (err);
225*7862SRichard.Bean@Sun.COM 				}
2260Sstevel@tonic-gate 			}
2270Sstevel@tonic-gate 		}
2280Sstevel@tonic-gate 	}
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	/* Free the nvlist */
2310Sstevel@tonic-gate 	nvlist_free(nvlp);
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 	/* set action chain reference */
2340Sstevel@tonic-gate 	if ((err = ipp_action_ref(aid, dscpmk_data->next_action, flags)) != 0) {
2350Sstevel@tonic-gate 		dscpmk0dbg(("dscpmk_create_action: ipp_action_ref " \
2360Sstevel@tonic-gate 		    "returned with error %d\n", err));
2370Sstevel@tonic-gate 		if (dscpmk_data->summary_stats) {
2380Sstevel@tonic-gate 			ipp_stat_destroy(dscpmk_data->stats);
2390Sstevel@tonic-gate 		}
2400Sstevel@tonic-gate 		if (dscpmk_data->detailed_stats) {
2410Sstevel@tonic-gate 			for (cnt = 0; cnt < DSCPMK_ARRAY_COUNT; cnt++) {
2420Sstevel@tonic-gate 				if (dscpmk_data->dscp_stats[cnt].present) {
2430Sstevel@tonic-gate 					ipp_stat_destroy(
2440Sstevel@tonic-gate 					    dscpmk_data->dscp_stats[cnt].stats);
2450Sstevel@tonic-gate 				}
2460Sstevel@tonic-gate 			}
2470Sstevel@tonic-gate 		}
2480Sstevel@tonic-gate 		kmem_free(dscpmk_data, DSCPMK_DATA_SZ);
2490Sstevel@tonic-gate 		return (err);
2500Sstevel@tonic-gate 	}
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 	ipp_action_set_ptr(aid, (void *)dscpmk_data);
2530Sstevel@tonic-gate 	return (0);
2540Sstevel@tonic-gate }
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate static int
dscpmk_modify_action(ipp_action_id_t aid,nvlist_t ** nvlpp,ipp_flags_t flags)2570Sstevel@tonic-gate dscpmk_modify_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags)
2580Sstevel@tonic-gate {
2590Sstevel@tonic-gate 	nvlist_t *nvlp;
2600Sstevel@tonic-gate 	int err = 0, cnt;
2610Sstevel@tonic-gate 	uint8_t config_type;
2620Sstevel@tonic-gate 	char *next_action_name;
2630Sstevel@tonic-gate 	uint32_t bstats;
2640Sstevel@tonic-gate 	uint_t nelem = DSCPMK_ARRAY_COUNT;
2650Sstevel@tonic-gate 	int32_t *tbl;
2660Sstevel@tonic-gate 	ipp_action_id_t next_action;
2670Sstevel@tonic-gate 	dscpmk_data_t *dscpmk_data;
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	ASSERT((nvlpp != NULL) && (*nvlpp != NULL));
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	nvlp = *nvlpp;
2720Sstevel@tonic-gate 	*nvlpp = NULL;		/* nvlist should be NULL when this returns */
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	if ((err = nvlist_lookup_byte(nvlp, IPP_CONFIG_TYPE, &config_type))
2750Sstevel@tonic-gate 	    != 0) {
2760Sstevel@tonic-gate 		nvlist_free(nvlp);
2770Sstevel@tonic-gate 		dscpmk0dbg(("dscpmk_modify_action: invalid cfg. type\n"));
2780Sstevel@tonic-gate 		return (err);
2790Sstevel@tonic-gate 	}
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	if (config_type != IPP_SET) {
2820Sstevel@tonic-gate 		nvlist_free(nvlp);
2830Sstevel@tonic-gate 		dscpmk0dbg(("dscpmk_modify_action: invalid cfg. type " \
2840Sstevel@tonic-gate 		    "%d\n", config_type));
2850Sstevel@tonic-gate 		return (EINVAL);
2860Sstevel@tonic-gate 	}
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	dscpmk_data = (dscpmk_data_t *)ipp_action_get_ptr(aid);
2890Sstevel@tonic-gate 	ASSERT(dscpmk_data != NULL);
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	/* parse next action name, if present */
2920Sstevel@tonic-gate 	if ((err = nvlist_lookup_string(nvlp, DSCPMK_NEXT_ACTION_NAME,
2930Sstevel@tonic-gate 	    &next_action_name)) == 0) {
2940Sstevel@tonic-gate 		/* lookup action name to get action id */
2950Sstevel@tonic-gate 		if ((next_action = ipp_action_lookup(next_action_name))
2960Sstevel@tonic-gate 		    == IPP_ACTION_INVAL) {
2970Sstevel@tonic-gate 			nvlist_free(nvlp);
2980Sstevel@tonic-gate 			dscpmk0dbg(("dscpmk_modify_action: next_action "\
2990Sstevel@tonic-gate 			    "invalid\n"));
3000Sstevel@tonic-gate 			return (EINVAL);
3010Sstevel@tonic-gate 		}
3020Sstevel@tonic-gate 		/* reference new action */
3030Sstevel@tonic-gate 		if ((err = ipp_action_ref(aid, next_action, flags)) != 0) {
3040Sstevel@tonic-gate 			nvlist_free(nvlp);
3050Sstevel@tonic-gate 			dscpmk0dbg(("dscpmk_modify_action: ipp_action_ref " \
3060Sstevel@tonic-gate 			    "returned with error %d\n", err));
3070Sstevel@tonic-gate 			return (err);
3080Sstevel@tonic-gate 		}
3090Sstevel@tonic-gate 		/* unref old action */
3100Sstevel@tonic-gate 		err = ipp_action_unref(aid, dscpmk_data->next_action, flags);
3110Sstevel@tonic-gate 		ASSERT(err == 0);
3120Sstevel@tonic-gate 		dscpmk_data->next_action = next_action;
3130Sstevel@tonic-gate 	}
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 	/*
3160Sstevel@tonic-gate 	 * parse dscp_map, if present. Note that the module gets
3170Sstevel@tonic-gate 	 * the entire array with unchanged entries marked with -1.
3180Sstevel@tonic-gate 	 * If this array is absent during modification, it means revert to
3190Sstevel@tonic-gate 	 * the default table.
3200Sstevel@tonic-gate 	 */
3210Sstevel@tonic-gate 	if ((err = nvlist_lookup_int32_array(nvlp, DSCPMK_DSCP_MAP,
3220Sstevel@tonic-gate 	    &tbl, &nelem)) == 0) {
3230Sstevel@tonic-gate 		for (cnt = 0; cnt < DSCPMK_ARRAY_COUNT; cnt++) {
3240Sstevel@tonic-gate 			if ((tbl[cnt] != DSCPMK_UNCHANGED_DSCP) && (tbl[cnt] !=
3250Sstevel@tonic-gate 			    dscpmk_data->dscp_map[cnt])) {
3260Sstevel@tonic-gate 				dscpmk_data->dscp_map[cnt] = tbl[cnt];
3270Sstevel@tonic-gate 			}
3280Sstevel@tonic-gate 		}
3290Sstevel@tonic-gate 	} else {
3300Sstevel@tonic-gate 		bcopy(default_dscp_map, dscpmk_data->dscp_map,
3310Sstevel@tonic-gate 		    sizeof (default_dscp_map));
3320Sstevel@tonic-gate 	}
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	/* parse summary_stats boolean, if present */
3350Sstevel@tonic-gate 	if ((err = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, &bstats))
3360Sstevel@tonic-gate 	    == 0) {
3370Sstevel@tonic-gate 		boolean_t val = (bstats != 0) ? B_TRUE : B_FALSE;
3380Sstevel@tonic-gate 		/* Turning on stats */
3390Sstevel@tonic-gate 		if (!dscpmk_data->summary_stats && val) {
3400Sstevel@tonic-gate 			if ((err = dscpmk_summ_statinit(aid, dscpmk_data))
3410Sstevel@tonic-gate 			    != 0) {
3420Sstevel@tonic-gate 				nvlist_free(nvlp);
3430Sstevel@tonic-gate 				return (err);
3440Sstevel@tonic-gate 			}
3450Sstevel@tonic-gate 		/* Turning off stats */
3460Sstevel@tonic-gate 		} else if (!val && dscpmk_data->summary_stats) {
3470Sstevel@tonic-gate 			ipp_stat_destroy(dscpmk_data->stats);
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 		}
3500Sstevel@tonic-gate 		dscpmk_data->summary_stats = val;
3510Sstevel@tonic-gate 	}
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	/* parse detailed_stats boolean */
3540Sstevel@tonic-gate 	if ((err = nvlist_lookup_uint32(nvlp, DSCPMK_DETAILED_STATS, &bstats))
3550Sstevel@tonic-gate 	    == 0) {
3560Sstevel@tonic-gate 		boolean_t val = (bstats != 0) ? B_TRUE : B_FALSE;
3570Sstevel@tonic-gate 		if (dscpmk_data->detailed_stats && !val) {
3580Sstevel@tonic-gate 			for (cnt = 0; cnt < DSCPMK_ARRAY_COUNT; cnt++) {
3590Sstevel@tonic-gate 				if (dscpmk_data->dscp_stats[cnt].present) {
3600Sstevel@tonic-gate 					dscpmk_data->dscp_stats[cnt].present =
3610Sstevel@tonic-gate 					    B_FALSE;
3620Sstevel@tonic-gate 					ipp_stat_destroy(dscpmk_data->
3630Sstevel@tonic-gate 					    dscp_stats[cnt].stats);
3640Sstevel@tonic-gate 				}
3650Sstevel@tonic-gate 			}
3660Sstevel@tonic-gate 		}
3670Sstevel@tonic-gate 		dscpmk_data->detailed_stats = val;
3680Sstevel@tonic-gate 	}
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	/* The map might have changed */
3710Sstevel@tonic-gate 	if (dscpmk_data->detailed_stats) {
3720Sstevel@tonic-gate 		for (cnt = 0; cnt < DSCPMK_ARRAY_COUNT; cnt++) {
3730Sstevel@tonic-gate 			int val = dscpmk_data->dscp_map[cnt];
3740Sstevel@tonic-gate 			if (!dscpmk_data->dscp_stats[val].present) {
3750Sstevel@tonic-gate 				dscpmk_data->dscp_stats[val].present = B_TRUE;
3760Sstevel@tonic-gate 				if ((err = dscpmk_det_statinit(aid, dscpmk_data,
3770Sstevel@tonic-gate 				    val)) != 0) {
3780Sstevel@tonic-gate 					nvlist_free(nvlp);
3790Sstevel@tonic-gate 					return (err);
3800Sstevel@tonic-gate 				}
3810Sstevel@tonic-gate 			}
3820Sstevel@tonic-gate 		}
3830Sstevel@tonic-gate 	}
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 	/* Free the nvlist */
3860Sstevel@tonic-gate 	nvlist_free(nvlp);
3870Sstevel@tonic-gate 	return (0);
3880Sstevel@tonic-gate }
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate static int
dscpmk_destroy_action(ipp_action_id_t aid,ipp_flags_t flags)3910Sstevel@tonic-gate dscpmk_destroy_action(ipp_action_id_t aid, ipp_flags_t flags)
3920Sstevel@tonic-gate {
3930Sstevel@tonic-gate 	dscpmk_data_t *dscpmk_data;
3940Sstevel@tonic-gate 	int err, cnt;
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	dscpmk_data = (dscpmk_data_t *)ipp_action_get_ptr(aid);
3970Sstevel@tonic-gate 	ASSERT(dscpmk_data != NULL);
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	/* Destroy stats, if gathered */
4000Sstevel@tonic-gate 	if (dscpmk_data->summary_stats) {
4010Sstevel@tonic-gate 		ipp_stat_destroy(dscpmk_data->stats);
4020Sstevel@tonic-gate 	}
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 	if (dscpmk_data->detailed_stats) {
4050Sstevel@tonic-gate 		for (cnt = 0; cnt < DSCPMK_ARRAY_COUNT; cnt++) {
4060Sstevel@tonic-gate 			if (dscpmk_data->dscp_stats[cnt].present) {
4070Sstevel@tonic-gate 				ipp_stat_destroy(dscpmk_data->dscp_stats[cnt].
4080Sstevel@tonic-gate 				    stats);
4090Sstevel@tonic-gate 			}
4100Sstevel@tonic-gate 		}
4110Sstevel@tonic-gate 	}
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 	/* unreference the action */
4140Sstevel@tonic-gate 	err = ipp_action_unref(aid, dscpmk_data->next_action, flags);
4150Sstevel@tonic-gate 	ASSERT(err == 0);
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 	kmem_free(dscpmk_data, DSCPMK_DATA_SZ);
4180Sstevel@tonic-gate 	return (0);
4190Sstevel@tonic-gate }
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate static int
dscpmk_invoke_action(ipp_action_id_t aid,ipp_packet_t * packet)4220Sstevel@tonic-gate dscpmk_invoke_action(ipp_action_id_t aid, ipp_packet_t *packet)
4230Sstevel@tonic-gate {
4240Sstevel@tonic-gate 	dscpmk_data_t *dscpmk_data;
4250Sstevel@tonic-gate 	mblk_t *mp = NULL;
4260Sstevel@tonic-gate 	ip_priv_t *priv;
4270Sstevel@tonic-gate 	int err;
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	ASSERT(packet != NULL);
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 	/* get mblk from ipp_packet structure */
4320Sstevel@tonic-gate 	mp = ipp_packet_get_data(packet);
4330Sstevel@tonic-gate 	priv = (ip_priv_t *)ipp_packet_get_private(packet);
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	dscpmk_data = (dscpmk_data_t *)ipp_action_get_ptr(aid);
4360Sstevel@tonic-gate 	ASSERT(dscpmk_data != NULL);
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 	/* dscpmk packet as configured */
4390Sstevel@tonic-gate 	if ((err = dscpmk_process(&mp, dscpmk_data, priv->proc)) != 0) {
4400Sstevel@tonic-gate 		return (err);
4410Sstevel@tonic-gate 	} else {
4420Sstevel@tonic-gate 		/* return packet with next action set */
4430Sstevel@tonic-gate 		return (ipp_packet_next(packet, dscpmk_data->next_action));
4440Sstevel@tonic-gate 	}
4450Sstevel@tonic-gate }
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate static int
dscpmk_det_statinit(ipp_action_id_t aid,dscpmk_data_t * dscpmk_data,int val)4480Sstevel@tonic-gate dscpmk_det_statinit(ipp_action_id_t aid, dscpmk_data_t *dscpmk_data, int val)
4490Sstevel@tonic-gate {
4500Sstevel@tonic-gate 	int err = 0;
4510Sstevel@tonic-gate 	dscpmk_dscp_stats_t *statp;
4520Sstevel@tonic-gate 	char stats_string[15];
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	(void) sprintf(stats_string, "dscpmk_dscp0x%x", val);
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 	/* install stats entry */
4570Sstevel@tonic-gate 	if ((err = ipp_stat_create(aid, stats_string, DSCPMK_DSCP_STATS_COUNT,
4580Sstevel@tonic-gate 	    dscpmk_update_det_stats, dscpmk_data,
4590Sstevel@tonic-gate 	    &dscpmk_data->dscp_stats[val].stats)) != 0) {
4600Sstevel@tonic-gate 		dscpmk0dbg(("dscpmk_det_statinit: ipp_stat_create returned "\
4610Sstevel@tonic-gate 		    "with error %d\n", err));
4620Sstevel@tonic-gate 		return (err);
4630Sstevel@tonic-gate 	}
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	statp = (dscpmk_dscp_stats_t *)
4660Sstevel@tonic-gate 	    (dscpmk_data->dscp_stats[val].stats)->ipps_data;
4670Sstevel@tonic-gate 	ASSERT(statp != NULL);
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	if ((err = ipp_stat_named_init(dscpmk_data->dscp_stats[val].stats,
4700Sstevel@tonic-gate 	    "dscp", IPP_STAT_UINT32, &statp->dscp)) != 0) {
4710Sstevel@tonic-gate 		dscpmk0dbg(("dscpmk_det_statinit: ipp_stat_named_init "\
4720Sstevel@tonic-gate 		    "returned with error %d\n", err));
4730Sstevel@tonic-gate 		return (err);
4740Sstevel@tonic-gate 	}
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 	if ((err = ipp_stat_named_init(dscpmk_data->dscp_stats[val].stats,
4770Sstevel@tonic-gate 	    "npackets", IPP_STAT_UINT64, &statp->npackets)) != 0) {
4780Sstevel@tonic-gate 		dscpmk0dbg(("dscpmk_det_statinit: ipp_stat_named_init "\
4790Sstevel@tonic-gate 		    "returned with error %d\n", err));
4800Sstevel@tonic-gate 		return (err);
4810Sstevel@tonic-gate 	}
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 	ipp_stat_install(dscpmk_data->dscp_stats[val].stats);
4840Sstevel@tonic-gate 	return (0);
4850Sstevel@tonic-gate }
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate static int
dscpmk_summ_statinit(ipp_action_id_t aid,dscpmk_data_t * dscpmk_data)4890Sstevel@tonic-gate dscpmk_summ_statinit(ipp_action_id_t aid, dscpmk_data_t *dscpmk_data)
4900Sstevel@tonic-gate {
4910Sstevel@tonic-gate 	int err = 0;
4920Sstevel@tonic-gate 	dscpmk_stat_t *statp;
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 	/* install stats entry */
4950Sstevel@tonic-gate 	if ((err = ipp_stat_create(aid, DSCPMK_STATS_STRING, DSCPMK_STATS_COUNT,
4960Sstevel@tonic-gate 	    dscpmk_update_stats, dscpmk_data, &dscpmk_data->stats)) != 0) {
4970Sstevel@tonic-gate 		dscpmk0dbg(("dscpmk_create_action: ipp_stat_create returned " \
4980Sstevel@tonic-gate 		    "with error %d\n", err));
4990Sstevel@tonic-gate 		return (err);
5000Sstevel@tonic-gate 	}
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	statp = (dscpmk_stat_t *)(dscpmk_data->stats)->ipps_data;
5030Sstevel@tonic-gate 	ASSERT(statp != NULL);
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	if ((err = ipp_stat_named_init(dscpmk_data->stats, "npackets",
5060Sstevel@tonic-gate 	    IPP_STAT_UINT64, &statp->npackets)) != 0) {
5070Sstevel@tonic-gate 		dscpmk0dbg(("dscpmk_summ_statinit: ipp_stat_named_init " \
5080Sstevel@tonic-gate 		    "returned with error %d\n", err));
5090Sstevel@tonic-gate 		return (err);
5100Sstevel@tonic-gate 	}
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	if ((err = ipp_stat_named_init(dscpmk_data->stats, "dscp_changed",
5130Sstevel@tonic-gate 	    IPP_STAT_UINT64, &statp->dscp_changed)) != 0) {
5140Sstevel@tonic-gate 		dscpmk0dbg(("dscpmk_summ_statinit: ipp_stat_named_init " \
5150Sstevel@tonic-gate 		    "returned with error %d\n", err));
5160Sstevel@tonic-gate 		return (err);
5170Sstevel@tonic-gate 	}
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 	if ((err = ipp_stat_named_init(dscpmk_data->stats, "dscp_unchanged",
5200Sstevel@tonic-gate 	    IPP_STAT_UINT64, &statp->dscp_unchanged)) != 0) {
5210Sstevel@tonic-gate 		dscpmk0dbg(("dscpmk_summ_statinit: ipp_stat_named_init " \
5220Sstevel@tonic-gate 		    "returned with error %d\n", err));
5230Sstevel@tonic-gate 		return (err);
5240Sstevel@tonic-gate 	}
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 	if ((err = ipp_stat_named_init(dscpmk_data->stats, "ipackets",
5270Sstevel@tonic-gate 	    IPP_STAT_UINT64, &statp->ipackets)) != 0) {
5280Sstevel@tonic-gate 		dscpmk0dbg(("dscpmk_summ_statinit: ipp_stat_named_init " \
5290Sstevel@tonic-gate 		    "returned with error %d\n", err));
5300Sstevel@tonic-gate 		return (err);
5310Sstevel@tonic-gate 	}
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 	if ((err = ipp_stat_named_init(dscpmk_data->stats, "epackets",
5340Sstevel@tonic-gate 	    IPP_STAT_UINT64, &statp->epackets)) != 0) {
5350Sstevel@tonic-gate 		dscpmk0dbg(("dscpmk_summ_statinit: ipp_stat_named_init " \
5360Sstevel@tonic-gate 		    "returned with error %d\n", err));
5370Sstevel@tonic-gate 		return (err);
5380Sstevel@tonic-gate 	}
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 	ipp_stat_install(dscpmk_data->stats);
5410Sstevel@tonic-gate 	return (0);
5420Sstevel@tonic-gate }
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate /* ARGSUSED */
5450Sstevel@tonic-gate static int
dscpmk_update_det_stats(ipp_stat_t * sp,void * arg,int rw)5460Sstevel@tonic-gate dscpmk_update_det_stats(ipp_stat_t *sp, void *arg, int rw)
5470Sstevel@tonic-gate {
5480Sstevel@tonic-gate 	dscpmk_data_t *dscpmk_data = (dscpmk_data_t *)arg;
5490Sstevel@tonic-gate 	dscpmk_dscp_stats_t *statp;
5500Sstevel@tonic-gate 	uint32_t count;
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 	for (count = 0; count < DSCPMK_ARRAY_COUNT; count++) {
5530Sstevel@tonic-gate 		if (!dscpmk_data->dscp_stats[count].present)
5540Sstevel@tonic-gate 			continue;
5550Sstevel@tonic-gate 		statp = (dscpmk_dscp_stats_t *)
5560Sstevel@tonic-gate 		    (dscpmk_data->dscp_stats[count].stats)->ipps_data;
5570Sstevel@tonic-gate 		ASSERT(statp != NULL);
5580Sstevel@tonic-gate 		(void) ipp_stat_named_op(&statp->npackets,
5590Sstevel@tonic-gate 		    &dscpmk_data->dscp_stats[count].npackets, rw);
5600Sstevel@tonic-gate 		(void) ipp_stat_named_op(&statp->dscp, &count, rw);
5610Sstevel@tonic-gate 	}
5620Sstevel@tonic-gate 	return (0);
5630Sstevel@tonic-gate }
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate static int
dscpmk_update_stats(ipp_stat_t * sp,void * arg,int rw)5660Sstevel@tonic-gate dscpmk_update_stats(ipp_stat_t *sp, void *arg, int rw)
5670Sstevel@tonic-gate {
5680Sstevel@tonic-gate 	dscpmk_data_t *dscpmk_data = (dscpmk_data_t *)arg;
5690Sstevel@tonic-gate 	dscpmk_stat_t *snames = (dscpmk_stat_t *)sp->ipps_data;
5700Sstevel@tonic-gate 	ASSERT(dscpmk_data != NULL);
5710Sstevel@tonic-gate 	ASSERT(snames != NULL);
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	(void) ipp_stat_named_op(&snames->npackets, &dscpmk_data->npackets, rw);
5740Sstevel@tonic-gate 	(void) ipp_stat_named_op(&snames->dscp_changed, &dscpmk_data->changed,
5750Sstevel@tonic-gate 	    rw);
5760Sstevel@tonic-gate 	(void) ipp_stat_named_op(&snames->dscp_unchanged,
5770Sstevel@tonic-gate 	    &dscpmk_data->unchanged, rw);
5780Sstevel@tonic-gate 	(void) ipp_stat_named_op(&snames->ipackets, &dscpmk_data->ipackets, rw);
5790Sstevel@tonic-gate 	(void) ipp_stat_named_op(&snames->epackets, &dscpmk_data->epackets, rw);
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 	return (0);
5820Sstevel@tonic-gate }
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate /* ARGSUSED */
5850Sstevel@tonic-gate static int
dscpmk_info(ipp_action_id_t aid,int (* fn)(nvlist_t *,void *),void * arg,ipp_flags_t flags)5860Sstevel@tonic-gate dscpmk_info(ipp_action_id_t aid, int (*fn)(nvlist_t *, void *), void *arg,
5870Sstevel@tonic-gate     ipp_flags_t flags)
5880Sstevel@tonic-gate {
5890Sstevel@tonic-gate 	nvlist_t *nvlp;
5900Sstevel@tonic-gate 	dscpmk_data_t *dscpmk_data;
5910Sstevel@tonic-gate 	char *next_action;
5920Sstevel@tonic-gate 	int err, cnt;
5930Sstevel@tonic-gate 	int32_t dscp_map[DSCPMK_ARRAY_COUNT];
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate 	ASSERT(fn != NULL);
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate 	dscpmk_data = (dscpmk_data_t *)ipp_action_get_ptr(aid);
5980Sstevel@tonic-gate 	ASSERT(dscpmk_data != NULL);
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	/* allocate nvlist to be passed back */
6010Sstevel@tonic-gate 	if ((err = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, KM_NOSLEEP)) != 0) {
6020Sstevel@tonic-gate 		dscpmk0dbg(("dscpmk_info: error allocating memory\n"));
6030Sstevel@tonic-gate 		return (err);
6040Sstevel@tonic-gate 	}
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 	/* look up next action with the next action id */
6070Sstevel@tonic-gate 	if ((err = ipp_action_name(dscpmk_data->next_action,
6080Sstevel@tonic-gate 	    &next_action)) != 0) {
6090Sstevel@tonic-gate 		dscpmk0dbg(("dscpmk_info: next action not available\n"));
6100Sstevel@tonic-gate 		nvlist_free(nvlp);
6110Sstevel@tonic-gate 		return (err);
6120Sstevel@tonic-gate 	}
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 	/* add next action name */
6150Sstevel@tonic-gate 	if ((err = nvlist_add_string(nvlp, DSCPMK_NEXT_ACTION_NAME,
6160Sstevel@tonic-gate 	    next_action)) != 0) {
6170Sstevel@tonic-gate 		dscpmk0dbg(("dscpmk_info: error adding next action\n"));
6180Sstevel@tonic-gate 		nvlist_free(nvlp);
6190Sstevel@tonic-gate 		kmem_free(next_action, (strlen(next_action) + 1));
6200Sstevel@tonic-gate 		return (err);
6210Sstevel@tonic-gate 	}
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 	/* free action name */
6240Sstevel@tonic-gate 	kmem_free(next_action, (strlen(next_action) + 1));
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	/* add config type */
6270Sstevel@tonic-gate 	if ((err = nvlist_add_byte(nvlp, IPP_CONFIG_TYPE, IPP_SET)) != 0) {
6280Sstevel@tonic-gate 		dscpmk0dbg(("dscpmk_info: error adding config type\n"));
6290Sstevel@tonic-gate 		nvlist_free(nvlp);
6300Sstevel@tonic-gate 		return (err);
6310Sstevel@tonic-gate 	}
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 	/* add dscp map */
6340Sstevel@tonic-gate 	bcopy(dscpmk_data->dscp_map, dscp_map, sizeof (dscp_map));
6350Sstevel@tonic-gate 	for (cnt = 0; cnt < DSCPMK_ARRAY_COUNT; cnt++) {
636*7862SRichard.Bean@Sun.COM 		dscp_map[cnt] = dscpmk_data->dscp_map[cnt];
6370Sstevel@tonic-gate 	}
6380Sstevel@tonic-gate 	if ((err = nvlist_add_int32_array(nvlp, DSCPMK_DSCP_MAP,
6390Sstevel@tonic-gate 	    dscp_map, DSCPMK_ARRAY_COUNT)) != 0) {
6400Sstevel@tonic-gate 		dscpmk0dbg(("dscpmk_info: error adding dscp map\n"));
6410Sstevel@tonic-gate 		nvlist_free(nvlp);
6420Sstevel@tonic-gate 		return (err);
6430Sstevel@tonic-gate 	}
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 	/* add summary stats boolean */
6460Sstevel@tonic-gate 	if ((err = nvlist_add_uint32(nvlp, IPP_ACTION_STATS_ENABLE,
6470Sstevel@tonic-gate 	    (dscpmk_data->summary_stats ? 1 : 0))) != 0) {
6480Sstevel@tonic-gate 		dscpmk0dbg(("dscpmk_info: error adding stats status\n"));
6490Sstevel@tonic-gate 		nvlist_free(nvlp);
6500Sstevel@tonic-gate 		return (err);
6510Sstevel@tonic-gate 	}
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate 	/* add detailed stats boolean */
6540Sstevel@tonic-gate 	if ((err = nvlist_add_uint32(nvlp, DSCPMK_DETAILED_STATS,
6550Sstevel@tonic-gate 	    (dscpmk_data->detailed_stats ? 1 : 0))) != 0) {
6560Sstevel@tonic-gate 		dscpmk0dbg(("dscpmk_info: error adding det stats status\n"));
6570Sstevel@tonic-gate 		nvlist_free(nvlp);
6580Sstevel@tonic-gate 		return (err);
6590Sstevel@tonic-gate 	}
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate 	/* call back with nvlist */
6620Sstevel@tonic-gate 	err = fn(nvlp, arg);
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 	nvlist_free(nvlp);
6650Sstevel@tonic-gate 	return (err);
6660Sstevel@tonic-gate }
667