opensolaris_nvpair.c revision 307124
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26#include <sys/debug.h>
27#include <sys/nvpair.h>
28#include <sys/nvpair_impl.h>
29#include <rpc/types.h>
30#include <rpc/xdr.h>
31
32#if defined(_KERNEL) && !defined(_BOOT)
33#include <sys/varargs.h>
34#include <sys/sunddi.h>
35#else
36#include <stdarg.h>
37#include <stdlib.h>
38#include <string.h>
39#include <strings.h>
40#endif
41
42#ifndef	offsetof
43#define	offsetof(s, m)		((size_t)(&(((s *)0)->m)))
44#endif
45#define	skip_whitespace(p)	while ((*(p) == ' ') || (*(p) == '\t')) p++
46
47#if defined(__FreeBSD__) && !defined(_KERNEL)
48/*
49 * libnvpair is the lowest commen denominator for ZFS related libraries,
50 * defining aok here makes it usable by all ZFS related libraries
51 */
52int aok;
53#endif
54
55/*
56 * nvpair.c - Provides kernel & userland interfaces for manipulating
57 *	name-value pairs.
58 *
59 * Overview Diagram
60 *
61 *  +--------------+
62 *  |  nvlist_t    |
63 *  |--------------|
64 *  | nvl_version  |
65 *  | nvl_nvflag   |
66 *  | nvl_priv    -+-+
67 *  | nvl_flag     | |
68 *  | nvl_pad      | |
69 *  +--------------+ |
70 *                   V
71 *      +--------------+      last i_nvp in list
72 *      | nvpriv_t     |  +--------------------->
73 *      |--------------|  |
74 *   +--+- nvp_list    |  |   +------------+
75 *   |  |  nvp_last   -+--+   + nv_alloc_t |
76 *   |  |  nvp_curr    |      |------------|
77 *   |  |  nvp_nva    -+----> | nva_ops    |
78 *   |  |  nvp_stat    |      | nva_arg    |
79 *   |  +--------------+      +------------+
80 *   |
81 *   +-------+
82 *           V
83 *   +---------------------+      +-------------------+
84 *   |  i_nvp_t            |  +-->|  i_nvp_t          |  +-->
85 *   |---------------------|  |   |-------------------|  |
86 *   | nvi_next           -+--+   | nvi_next         -+--+
87 *   | nvi_prev (NULL)     | <----+ nvi_prev          |
88 *   | . . . . . . . . . . |      | . . . . . . . . . |
89 *   | nvp (nvpair_t)      |      | nvp (nvpair_t)    |
90 *   |  - nvp_size         |      |  - nvp_size       |
91 *   |  - nvp_name_sz      |      |  - nvp_name_sz    |
92 *   |  - nvp_value_elem   |      |  - nvp_value_elem |
93 *   |  - nvp_type         |      |  - nvp_type       |
94 *   |  - data ...         |      |  - data ...       |
95 *   +---------------------+      +-------------------+
96 *
97 *
98 *
99 *   +---------------------+              +---------------------+
100 *   |  i_nvp_t            |  +-->    +-->|  i_nvp_t (last)     |
101 *   |---------------------|  |       |   |---------------------|
102 *   |  nvi_next          -+--+ ... --+   | nvi_next (NULL)     |
103 * <-+- nvi_prev           |<-- ...  <----+ nvi_prev            |
104 *   | . . . . . . . . .   |              | . . . . . . . . .   |
105 *   | nvp (nvpair_t)      |              | nvp (nvpair_t)      |
106 *   |  - nvp_size         |              |  - nvp_size         |
107 *   |  - nvp_name_sz      |              |  - nvp_name_sz      |
108 *   |  - nvp_value_elem   |              |  - nvp_value_elem   |
109 *   |  - DATA_TYPE_NVLIST |              |  - nvp_type         |
110 *   |  - data (embedded)  |              |  - data ...         |
111 *   |    nvlist name      |              +---------------------+
112 *   |  +--------------+   |
113 *   |  |  nvlist_t    |   |
114 *   |  |--------------|   |
115 *   |  | nvl_version  |   |
116 *   |  | nvl_nvflag   |   |
117 *   |  | nvl_priv   --+---+---->
118 *   |  | nvl_flag     |   |
119 *   |  | nvl_pad      |   |
120 *   |  +--------------+   |
121 *   +---------------------+
122 *
123 *
124 * N.B. nvpair_t may be aligned on 4 byte boundary, so +4 will
125 * allow value to be aligned on 8 byte boundary
126 *
127 * name_len is the length of the name string including the null terminator
128 * so it must be >= 1
129 */
130#define	NVP_SIZE_CALC(name_len, data_len) \
131	(NV_ALIGN((sizeof (nvpair_t)) + name_len) + NV_ALIGN(data_len))
132
133static int i_get_value_size(data_type_t type, const void *data, uint_t nelem);
134static int nvlist_add_common(nvlist_t *nvl, const char *name, data_type_t type,
135    uint_t nelem, const void *data);
136
137#define	NV_STAT_EMBEDDED	0x1
138#define	EMBEDDED_NVL(nvp)	((nvlist_t *)(void *)NVP_VALUE(nvp))
139#define	EMBEDDED_NVL_ARRAY(nvp)	((nvlist_t **)(void *)NVP_VALUE(nvp))
140
141#define	NVP_VALOFF(nvp)	(NV_ALIGN(sizeof (nvpair_t) + (nvp)->nvp_name_sz))
142#define	NVPAIR2I_NVP(nvp) \
143	((i_nvp_t *)((size_t)(nvp) - offsetof(i_nvp_t, nvi_nvp)))
144
145
146int
147nv_alloc_init(nv_alloc_t *nva, const nv_alloc_ops_t *nvo, /* args */ ...)
148{
149	va_list valist;
150	int err = 0;
151
152	nva->nva_ops = nvo;
153	nva->nva_arg = NULL;
154
155	va_start(valist, nvo);
156	if (nva->nva_ops->nv_ao_init != NULL)
157		err = nva->nva_ops->nv_ao_init(nva, valist);
158	va_end(valist);
159
160	return (err);
161}
162
163void
164nv_alloc_reset(nv_alloc_t *nva)
165{
166	if (nva->nva_ops->nv_ao_reset != NULL)
167		nva->nva_ops->nv_ao_reset(nva);
168}
169
170void
171nv_alloc_fini(nv_alloc_t *nva)
172{
173	if (nva->nva_ops->nv_ao_fini != NULL)
174		nva->nva_ops->nv_ao_fini(nva);
175}
176
177nv_alloc_t *
178nvlist_lookup_nv_alloc(nvlist_t *nvl)
179{
180	nvpriv_t *priv;
181
182	if (nvl == NULL ||
183	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
184		return (NULL);
185
186	return (priv->nvp_nva);
187}
188
189static void *
190nv_mem_zalloc(nvpriv_t *nvp, size_t size)
191{
192	nv_alloc_t *nva = nvp->nvp_nva;
193	void *buf;
194
195	if ((buf = nva->nva_ops->nv_ao_alloc(nva, size)) != NULL)
196		bzero(buf, size);
197
198	return (buf);
199}
200
201static void
202nv_mem_free(nvpriv_t *nvp, void *buf, size_t size)
203{
204	nv_alloc_t *nva = nvp->nvp_nva;
205
206	nva->nva_ops->nv_ao_free(nva, buf, size);
207}
208
209static void
210nv_priv_init(nvpriv_t *priv, nv_alloc_t *nva, uint32_t stat)
211{
212	bzero(priv, sizeof (nvpriv_t));
213
214	priv->nvp_nva = nva;
215	priv->nvp_stat = stat;
216}
217
218static nvpriv_t *
219nv_priv_alloc(nv_alloc_t *nva)
220{
221	nvpriv_t *priv;
222
223	/*
224	 * nv_mem_alloc() cannot called here because it needs the priv
225	 * argument.
226	 */
227	if ((priv = nva->nva_ops->nv_ao_alloc(nva, sizeof (nvpriv_t))) == NULL)
228		return (NULL);
229
230	nv_priv_init(priv, nva, 0);
231
232	return (priv);
233}
234
235/*
236 * Embedded lists need their own nvpriv_t's.  We create a new
237 * nvpriv_t using the parameters and allocator from the parent
238 * list's nvpriv_t.
239 */
240static nvpriv_t *
241nv_priv_alloc_embedded(nvpriv_t *priv)
242{
243	nvpriv_t *emb_priv;
244
245	if ((emb_priv = nv_mem_zalloc(priv, sizeof (nvpriv_t))) == NULL)
246		return (NULL);
247
248	nv_priv_init(emb_priv, priv->nvp_nva, NV_STAT_EMBEDDED);
249
250	return (emb_priv);
251}
252
253static void
254nvlist_init(nvlist_t *nvl, uint32_t nvflag, nvpriv_t *priv)
255{
256	nvl->nvl_version = NV_VERSION;
257	nvl->nvl_nvflag = nvflag & (NV_UNIQUE_NAME|NV_UNIQUE_NAME_TYPE);
258	nvl->nvl_priv = (uint64_t)(uintptr_t)priv;
259	nvl->nvl_flag = 0;
260	nvl->nvl_pad = 0;
261}
262
263uint_t
264nvlist_nvflag(nvlist_t *nvl)
265{
266	return (nvl->nvl_nvflag);
267}
268
269/*
270 * nvlist_alloc - Allocate nvlist.
271 */
272/*ARGSUSED1*/
273int
274nvlist_alloc(nvlist_t **nvlp, uint_t nvflag, int kmflag)
275{
276#if defined(_KERNEL) && !defined(_BOOT)
277	return (nvlist_xalloc(nvlp, nvflag,
278	    (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep)));
279#else
280	return (nvlist_xalloc(nvlp, nvflag, nv_alloc_nosleep));
281#endif
282}
283
284int
285nvlist_xalloc(nvlist_t **nvlp, uint_t nvflag, nv_alloc_t *nva)
286{
287	nvpriv_t *priv;
288
289	if (nvlp == NULL || nva == NULL)
290		return (EINVAL);
291
292	if ((priv = nv_priv_alloc(nva)) == NULL)
293		return (ENOMEM);
294
295	if ((*nvlp = nv_mem_zalloc(priv,
296	    NV_ALIGN(sizeof (nvlist_t)))) == NULL) {
297		nv_mem_free(priv, priv, sizeof (nvpriv_t));
298		return (ENOMEM);
299	}
300
301	nvlist_init(*nvlp, nvflag, priv);
302
303	return (0);
304}
305
306/*
307 * nvp_buf_alloc - Allocate i_nvp_t for storing a new nv pair.
308 */
309static nvpair_t *
310nvp_buf_alloc(nvlist_t *nvl, size_t len)
311{
312	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
313	i_nvp_t *buf;
314	nvpair_t *nvp;
315	size_t nvsize;
316
317	/*
318	 * Allocate the buffer
319	 */
320	nvsize = len + offsetof(i_nvp_t, nvi_nvp);
321
322	if ((buf = nv_mem_zalloc(priv, nvsize)) == NULL)
323		return (NULL);
324
325	nvp = &buf->nvi_nvp;
326	nvp->nvp_size = len;
327
328	return (nvp);
329}
330
331/*
332 * nvp_buf_free - de-Allocate an i_nvp_t.
333 */
334static void
335nvp_buf_free(nvlist_t *nvl, nvpair_t *nvp)
336{
337	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
338	size_t nvsize = nvp->nvp_size + offsetof(i_nvp_t, nvi_nvp);
339
340	nv_mem_free(priv, NVPAIR2I_NVP(nvp), nvsize);
341}
342
343/*
344 * nvp_buf_link - link a new nv pair into the nvlist.
345 */
346static void
347nvp_buf_link(nvlist_t *nvl, nvpair_t *nvp)
348{
349	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
350	i_nvp_t *curr = NVPAIR2I_NVP(nvp);
351
352	/* Put element at end of nvlist */
353	if (priv->nvp_list == NULL) {
354		priv->nvp_list = priv->nvp_last = curr;
355	} else {
356		curr->nvi_prev = priv->nvp_last;
357		priv->nvp_last->nvi_next = curr;
358		priv->nvp_last = curr;
359	}
360}
361
362/*
363 * nvp_buf_unlink - unlink an removed nvpair out of the nvlist.
364 */
365static void
366nvp_buf_unlink(nvlist_t *nvl, nvpair_t *nvp)
367{
368	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
369	i_nvp_t *curr = NVPAIR2I_NVP(nvp);
370
371	/*
372	 * protect nvlist_next_nvpair() against walking on freed memory.
373	 */
374	if (priv->nvp_curr == curr)
375		priv->nvp_curr = curr->nvi_next;
376
377	if (curr == priv->nvp_list)
378		priv->nvp_list = curr->nvi_next;
379	else
380		curr->nvi_prev->nvi_next = curr->nvi_next;
381
382	if (curr == priv->nvp_last)
383		priv->nvp_last = curr->nvi_prev;
384	else
385		curr->nvi_next->nvi_prev = curr->nvi_prev;
386}
387
388/*
389 * take a nvpair type and number of elements and make sure the are valid
390 */
391static int
392i_validate_type_nelem(data_type_t type, uint_t nelem)
393{
394	switch (type) {
395	case DATA_TYPE_BOOLEAN:
396		if (nelem != 0)
397			return (EINVAL);
398		break;
399	case DATA_TYPE_BOOLEAN_VALUE:
400	case DATA_TYPE_BYTE:
401	case DATA_TYPE_INT8:
402	case DATA_TYPE_UINT8:
403	case DATA_TYPE_INT16:
404	case DATA_TYPE_UINT16:
405	case DATA_TYPE_INT32:
406	case DATA_TYPE_UINT32:
407	case DATA_TYPE_INT64:
408	case DATA_TYPE_UINT64:
409	case DATA_TYPE_STRING:
410	case DATA_TYPE_HRTIME:
411	case DATA_TYPE_NVLIST:
412#if !defined(_KERNEL)
413	case DATA_TYPE_DOUBLE:
414#endif
415		if (nelem != 1)
416			return (EINVAL);
417		break;
418	case DATA_TYPE_BOOLEAN_ARRAY:
419	case DATA_TYPE_BYTE_ARRAY:
420	case DATA_TYPE_INT8_ARRAY:
421	case DATA_TYPE_UINT8_ARRAY:
422	case DATA_TYPE_INT16_ARRAY:
423	case DATA_TYPE_UINT16_ARRAY:
424	case DATA_TYPE_INT32_ARRAY:
425	case DATA_TYPE_UINT32_ARRAY:
426	case DATA_TYPE_INT64_ARRAY:
427	case DATA_TYPE_UINT64_ARRAY:
428	case DATA_TYPE_STRING_ARRAY:
429	case DATA_TYPE_NVLIST_ARRAY:
430		/* we allow arrays with 0 elements */
431		break;
432	default:
433		return (EINVAL);
434	}
435	return (0);
436}
437
438/*
439 * Verify nvp_name_sz and check the name string length.
440 */
441static int
442i_validate_nvpair_name(nvpair_t *nvp)
443{
444	if ((nvp->nvp_name_sz <= 0) ||
445	    (nvp->nvp_size < NVP_SIZE_CALC(nvp->nvp_name_sz, 0)))
446		return (EFAULT);
447
448	/* verify the name string, make sure its terminated */
449	if (NVP_NAME(nvp)[nvp->nvp_name_sz - 1] != '\0')
450		return (EFAULT);
451
452	return (strlen(NVP_NAME(nvp)) == nvp->nvp_name_sz - 1 ? 0 : EFAULT);
453}
454
455static int
456i_validate_nvpair_value(data_type_t type, uint_t nelem, const void *data)
457{
458	switch (type) {
459	case DATA_TYPE_BOOLEAN_VALUE:
460		if (*(boolean_t *)data != B_TRUE &&
461		    *(boolean_t *)data != B_FALSE)
462			return (EINVAL);
463		break;
464	case DATA_TYPE_BOOLEAN_ARRAY: {
465		int i;
466
467		for (i = 0; i < nelem; i++)
468			if (((boolean_t *)data)[i] != B_TRUE &&
469			    ((boolean_t *)data)[i] != B_FALSE)
470				return (EINVAL);
471		break;
472	}
473	default:
474		break;
475	}
476
477	return (0);
478}
479
480/*
481 * This function takes a pointer to what should be a nvpair and it's size
482 * and then verifies that all the nvpair fields make sense and can be
483 * trusted.  This function is used when decoding packed nvpairs.
484 */
485static int
486i_validate_nvpair(nvpair_t *nvp)
487{
488	data_type_t type = NVP_TYPE(nvp);
489	int size1, size2;
490
491	/* verify nvp_name_sz, check the name string length */
492	if (i_validate_nvpair_name(nvp) != 0)
493		return (EFAULT);
494
495	if (i_validate_nvpair_value(type, NVP_NELEM(nvp), NVP_VALUE(nvp)) != 0)
496		return (EFAULT);
497
498	/*
499	 * verify nvp_type, nvp_value_elem, and also possibly
500	 * verify string values and get the value size.
501	 */
502	size2 = i_get_value_size(type, NVP_VALUE(nvp), NVP_NELEM(nvp));
503	size1 = nvp->nvp_size - NVP_VALOFF(nvp);
504	if (size2 < 0 || size1 != NV_ALIGN(size2))
505		return (EFAULT);
506
507	return (0);
508}
509
510static int
511nvlist_copy_pairs(nvlist_t *snvl, nvlist_t *dnvl)
512{
513	nvpriv_t *priv;
514	i_nvp_t *curr;
515
516	if ((priv = (nvpriv_t *)(uintptr_t)snvl->nvl_priv) == NULL)
517		return (EINVAL);
518
519	for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
520		nvpair_t *nvp = &curr->nvi_nvp;
521		int err;
522
523		if ((err = nvlist_add_common(dnvl, NVP_NAME(nvp), NVP_TYPE(nvp),
524		    NVP_NELEM(nvp), NVP_VALUE(nvp))) != 0)
525			return (err);
526	}
527
528	return (0);
529}
530
531/*
532 * Frees all memory allocated for an nvpair (like embedded lists) with
533 * the exception of the nvpair buffer itself.
534 */
535static void
536nvpair_free(nvpair_t *nvp)
537{
538	switch (NVP_TYPE(nvp)) {
539	case DATA_TYPE_NVLIST:
540		nvlist_free(EMBEDDED_NVL(nvp));
541		break;
542	case DATA_TYPE_NVLIST_ARRAY: {
543		nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);
544		int i;
545
546		for (i = 0; i < NVP_NELEM(nvp); i++)
547			nvlist_free(nvlp[i]);
548		break;
549	}
550	default:
551		break;
552	}
553}
554
555/*
556 * nvlist_free - free an unpacked nvlist
557 */
558void
559nvlist_free(nvlist_t *nvl)
560{
561	nvpriv_t *priv;
562	i_nvp_t *curr;
563
564	if (nvl == NULL ||
565	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
566		return;
567
568	/*
569	 * Unpacked nvlist are linked through i_nvp_t
570	 */
571	curr = priv->nvp_list;
572	while (curr != NULL) {
573		nvpair_t *nvp = &curr->nvi_nvp;
574		curr = curr->nvi_next;
575
576		nvpair_free(nvp);
577		nvp_buf_free(nvl, nvp);
578	}
579
580	if (!(priv->nvp_stat & NV_STAT_EMBEDDED))
581		nv_mem_free(priv, nvl, NV_ALIGN(sizeof (nvlist_t)));
582	else
583		nvl->nvl_priv = 0;
584
585	nv_mem_free(priv, priv, sizeof (nvpriv_t));
586}
587
588static int
589nvlist_contains_nvp(nvlist_t *nvl, nvpair_t *nvp)
590{
591	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
592	i_nvp_t *curr;
593
594	if (nvp == NULL)
595		return (0);
596
597	for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next)
598		if (&curr->nvi_nvp == nvp)
599			return (1);
600
601	return (0);
602}
603
604/*
605 * Make a copy of nvlist
606 */
607/*ARGSUSED1*/
608int
609nvlist_dup(nvlist_t *nvl, nvlist_t **nvlp, int kmflag)
610{
611#if defined(_KERNEL) && !defined(_BOOT)
612	return (nvlist_xdup(nvl, nvlp,
613	    (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep)));
614#else
615	return (nvlist_xdup(nvl, nvlp, nv_alloc_nosleep));
616#endif
617}
618
619int
620nvlist_xdup(nvlist_t *nvl, nvlist_t **nvlp, nv_alloc_t *nva)
621{
622	int err;
623	nvlist_t *ret;
624
625	if (nvl == NULL || nvlp == NULL)
626		return (EINVAL);
627
628	if ((err = nvlist_xalloc(&ret, nvl->nvl_nvflag, nva)) != 0)
629		return (err);
630
631	if ((err = nvlist_copy_pairs(nvl, ret)) != 0)
632		nvlist_free(ret);
633	else
634		*nvlp = ret;
635
636	return (err);
637}
638
639/*
640 * Remove all with matching name
641 */
642int
643nvlist_remove_all(nvlist_t *nvl, const char *name)
644{
645	nvpriv_t *priv;
646	i_nvp_t *curr;
647	int error = ENOENT;
648
649	if (nvl == NULL || name == NULL ||
650	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
651		return (EINVAL);
652
653	curr = priv->nvp_list;
654	while (curr != NULL) {
655		nvpair_t *nvp = &curr->nvi_nvp;
656
657		curr = curr->nvi_next;
658		if (strcmp(name, NVP_NAME(nvp)) != 0)
659			continue;
660
661		nvp_buf_unlink(nvl, nvp);
662		nvpair_free(nvp);
663		nvp_buf_free(nvl, nvp);
664
665		error = 0;
666	}
667
668	return (error);
669}
670
671/*
672 * Remove first one with matching name and type
673 */
674int
675nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type)
676{
677	nvpriv_t *priv;
678	i_nvp_t *curr;
679
680	if (nvl == NULL || name == NULL ||
681	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
682		return (EINVAL);
683
684	curr = priv->nvp_list;
685	while (curr != NULL) {
686		nvpair_t *nvp = &curr->nvi_nvp;
687
688		if (strcmp(name, NVP_NAME(nvp)) == 0 && NVP_TYPE(nvp) == type) {
689			nvp_buf_unlink(nvl, nvp);
690			nvpair_free(nvp);
691			nvp_buf_free(nvl, nvp);
692
693			return (0);
694		}
695		curr = curr->nvi_next;
696	}
697
698	return (ENOENT);
699}
700
701int
702nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp)
703{
704	if (nvl == NULL || nvp == NULL)
705		return (EINVAL);
706
707	nvp_buf_unlink(nvl, nvp);
708	nvpair_free(nvp);
709	nvp_buf_free(nvl, nvp);
710	return (0);
711}
712
713/*
714 * This function calculates the size of an nvpair value.
715 *
716 * The data argument controls the behavior in case of the data types
717 * 	DATA_TYPE_STRING    	and
718 *	DATA_TYPE_STRING_ARRAY
719 * Is data == NULL then the size of the string(s) is excluded.
720 */
721static int
722i_get_value_size(data_type_t type, const void *data, uint_t nelem)
723{
724	uint64_t value_sz;
725
726	if (i_validate_type_nelem(type, nelem) != 0)
727		return (-1);
728
729	/* Calculate required size for holding value */
730	switch (type) {
731	case DATA_TYPE_BOOLEAN:
732		value_sz = 0;
733		break;
734	case DATA_TYPE_BOOLEAN_VALUE:
735		value_sz = sizeof (boolean_t);
736		break;
737	case DATA_TYPE_BYTE:
738		value_sz = sizeof (uchar_t);
739		break;
740	case DATA_TYPE_INT8:
741		value_sz = sizeof (int8_t);
742		break;
743	case DATA_TYPE_UINT8:
744		value_sz = sizeof (uint8_t);
745		break;
746	case DATA_TYPE_INT16:
747		value_sz = sizeof (int16_t);
748		break;
749	case DATA_TYPE_UINT16:
750		value_sz = sizeof (uint16_t);
751		break;
752	case DATA_TYPE_INT32:
753		value_sz = sizeof (int32_t);
754		break;
755	case DATA_TYPE_UINT32:
756		value_sz = sizeof (uint32_t);
757		break;
758	case DATA_TYPE_INT64:
759		value_sz = sizeof (int64_t);
760		break;
761	case DATA_TYPE_UINT64:
762		value_sz = sizeof (uint64_t);
763		break;
764#if !defined(_KERNEL)
765	case DATA_TYPE_DOUBLE:
766		value_sz = sizeof (double);
767		break;
768#endif
769	case DATA_TYPE_STRING:
770		if (data == NULL)
771			value_sz = 0;
772		else
773			value_sz = strlen(data) + 1;
774		break;
775	case DATA_TYPE_BOOLEAN_ARRAY:
776		value_sz = (uint64_t)nelem * sizeof (boolean_t);
777		break;
778	case DATA_TYPE_BYTE_ARRAY:
779		value_sz = (uint64_t)nelem * sizeof (uchar_t);
780		break;
781	case DATA_TYPE_INT8_ARRAY:
782		value_sz = (uint64_t)nelem * sizeof (int8_t);
783		break;
784	case DATA_TYPE_UINT8_ARRAY:
785		value_sz = (uint64_t)nelem * sizeof (uint8_t);
786		break;
787	case DATA_TYPE_INT16_ARRAY:
788		value_sz = (uint64_t)nelem * sizeof (int16_t);
789		break;
790	case DATA_TYPE_UINT16_ARRAY:
791		value_sz = (uint64_t)nelem * sizeof (uint16_t);
792		break;
793	case DATA_TYPE_INT32_ARRAY:
794		value_sz = (uint64_t)nelem * sizeof (int32_t);
795		break;
796	case DATA_TYPE_UINT32_ARRAY:
797		value_sz = (uint64_t)nelem * sizeof (uint32_t);
798		break;
799	case DATA_TYPE_INT64_ARRAY:
800		value_sz = (uint64_t)nelem * sizeof (int64_t);
801		break;
802	case DATA_TYPE_UINT64_ARRAY:
803		value_sz = (uint64_t)nelem * sizeof (uint64_t);
804		break;
805	case DATA_TYPE_STRING_ARRAY:
806		value_sz = (uint64_t)nelem * sizeof (uint64_t);
807
808		if (data != NULL) {
809			char *const *strs = data;
810			uint_t i;
811
812			/* no alignment requirement for strings */
813			for (i = 0; i < nelem; i++) {
814				if (strs[i] == NULL)
815					return (-1);
816				value_sz += strlen(strs[i]) + 1;
817			}
818		}
819		break;
820	case DATA_TYPE_HRTIME:
821		value_sz = sizeof (hrtime_t);
822		break;
823	case DATA_TYPE_NVLIST:
824		value_sz = NV_ALIGN(sizeof (nvlist_t));
825		break;
826	case DATA_TYPE_NVLIST_ARRAY:
827		value_sz = (uint64_t)nelem * sizeof (uint64_t) +
828		    (uint64_t)nelem * NV_ALIGN(sizeof (nvlist_t));
829		break;
830	default:
831		return (-1);
832	}
833
834	return (value_sz > INT32_MAX ? -1 : (int)value_sz);
835}
836
837static int
838nvlist_copy_embedded(nvlist_t *nvl, nvlist_t *onvl, nvlist_t *emb_nvl)
839{
840	nvpriv_t *priv;
841	int err;
842
843	if ((priv = nv_priv_alloc_embedded((nvpriv_t *)(uintptr_t)
844	    nvl->nvl_priv)) == NULL)
845		return (ENOMEM);
846
847	nvlist_init(emb_nvl, onvl->nvl_nvflag, priv);
848
849	if ((err = nvlist_copy_pairs(onvl, emb_nvl)) != 0) {
850		nvlist_free(emb_nvl);
851		emb_nvl->nvl_priv = 0;
852	}
853
854	return (err);
855}
856
857/*
858 * nvlist_add_common - Add new <name,value> pair to nvlist
859 */
860static int
861nvlist_add_common(nvlist_t *nvl, const char *name,
862    data_type_t type, uint_t nelem, const void *data)
863{
864	nvpair_t *nvp;
865	uint_t i;
866
867	int nvp_sz, name_sz, value_sz;
868	int err = 0;
869
870	if (name == NULL || nvl == NULL || nvl->nvl_priv == 0)
871		return (EINVAL);
872
873	if (nelem != 0 && data == NULL)
874		return (EINVAL);
875
876	/*
877	 * Verify type and nelem and get the value size.
878	 * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY
879	 * is the size of the string(s) included.
880	 */
881	if ((value_sz = i_get_value_size(type, data, nelem)) < 0)
882		return (EINVAL);
883
884	if (i_validate_nvpair_value(type, nelem, data) != 0)
885		return (EINVAL);
886
887	/*
888	 * If we're adding an nvlist or nvlist array, ensure that we are not
889	 * adding the input nvlist to itself, which would cause recursion,
890	 * and ensure that no NULL nvlist pointers are present.
891	 */
892	switch (type) {
893	case DATA_TYPE_NVLIST:
894		if (data == nvl || data == NULL)
895			return (EINVAL);
896		break;
897	case DATA_TYPE_NVLIST_ARRAY: {
898		nvlist_t **onvlp = (nvlist_t **)data;
899		for (i = 0; i < nelem; i++) {
900			if (onvlp[i] == nvl || onvlp[i] == NULL)
901				return (EINVAL);
902		}
903		break;
904	}
905	default:
906		break;
907	}
908
909	/* calculate sizes of the nvpair elements and the nvpair itself */
910	name_sz = strlen(name) + 1;
911
912	nvp_sz = NVP_SIZE_CALC(name_sz, value_sz);
913
914	if ((nvp = nvp_buf_alloc(nvl, nvp_sz)) == NULL)
915		return (ENOMEM);
916
917	ASSERT(nvp->nvp_size == nvp_sz);
918	nvp->nvp_name_sz = name_sz;
919	nvp->nvp_value_elem = nelem;
920	nvp->nvp_type = type;
921	bcopy(name, NVP_NAME(nvp), name_sz);
922
923	switch (type) {
924	case DATA_TYPE_BOOLEAN:
925		break;
926	case DATA_TYPE_STRING_ARRAY: {
927		char *const *strs = data;
928		char *buf = NVP_VALUE(nvp);
929		char **cstrs = (void *)buf;
930
931		/* skip pre-allocated space for pointer array */
932		buf += nelem * sizeof (uint64_t);
933		for (i = 0; i < nelem; i++) {
934			int slen = strlen(strs[i]) + 1;
935			bcopy(strs[i], buf, slen);
936			cstrs[i] = buf;
937			buf += slen;
938		}
939		break;
940	}
941	case DATA_TYPE_NVLIST: {
942		nvlist_t *nnvl = EMBEDDED_NVL(nvp);
943		nvlist_t *onvl = (nvlist_t *)data;
944
945		if ((err = nvlist_copy_embedded(nvl, onvl, nnvl)) != 0) {
946			nvp_buf_free(nvl, nvp);
947			return (err);
948		}
949		break;
950	}
951	case DATA_TYPE_NVLIST_ARRAY: {
952		nvlist_t **onvlp = (nvlist_t **)data;
953		nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);
954		nvlist_t *embedded = (nvlist_t *)
955		    ((uintptr_t)nvlp + nelem * sizeof (uint64_t));
956
957		for (i = 0; i < nelem; i++) {
958			if ((err = nvlist_copy_embedded(nvl,
959			    onvlp[i], embedded)) != 0) {
960				/*
961				 * Free any successfully created lists
962				 */
963				nvpair_free(nvp);
964				nvp_buf_free(nvl, nvp);
965				return (err);
966			}
967
968			nvlp[i] = embedded++;
969		}
970		break;
971	}
972	default:
973		bcopy(data, NVP_VALUE(nvp), value_sz);
974	}
975
976	/* if unique name, remove before add */
977	if (nvl->nvl_nvflag & NV_UNIQUE_NAME)
978		(void) nvlist_remove_all(nvl, name);
979	else if (nvl->nvl_nvflag & NV_UNIQUE_NAME_TYPE)
980		(void) nvlist_remove(nvl, name, type);
981
982	nvp_buf_link(nvl, nvp);
983
984	return (0);
985}
986
987int
988nvlist_add_boolean(nvlist_t *nvl, const char *name)
989{
990	return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN, 0, NULL));
991}
992
993int
994nvlist_add_boolean_value(nvlist_t *nvl, const char *name, boolean_t val)
995{
996	return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_VALUE, 1, &val));
997}
998
999int
1000nvlist_add_byte(nvlist_t *nvl, const char *name, uchar_t val)
1001{
1002	return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE, 1, &val));
1003}
1004
1005int
1006nvlist_add_int8(nvlist_t *nvl, const char *name, int8_t val)
1007{
1008	return (nvlist_add_common(nvl, name, DATA_TYPE_INT8, 1, &val));
1009}
1010
1011int
1012nvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t val)
1013{
1014	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8, 1, &val));
1015}
1016
1017int
1018nvlist_add_int16(nvlist_t *nvl, const char *name, int16_t val)
1019{
1020	return (nvlist_add_common(nvl, name, DATA_TYPE_INT16, 1, &val));
1021}
1022
1023int
1024nvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t val)
1025{
1026	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16, 1, &val));
1027}
1028
1029int
1030nvlist_add_int32(nvlist_t *nvl, const char *name, int32_t val)
1031{
1032	return (nvlist_add_common(nvl, name, DATA_TYPE_INT32, 1, &val));
1033}
1034
1035int
1036nvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t val)
1037{
1038	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32, 1, &val));
1039}
1040
1041int
1042nvlist_add_int64(nvlist_t *nvl, const char *name, int64_t val)
1043{
1044	return (nvlist_add_common(nvl, name, DATA_TYPE_INT64, 1, &val));
1045}
1046
1047int
1048nvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t val)
1049{
1050	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64, 1, &val));
1051}
1052
1053#if !defined(_KERNEL)
1054int
1055nvlist_add_double(nvlist_t *nvl, const char *name, double val)
1056{
1057	return (nvlist_add_common(nvl, name, DATA_TYPE_DOUBLE, 1, &val));
1058}
1059#endif
1060
1061int
1062nvlist_add_string(nvlist_t *nvl, const char *name, const char *val)
1063{
1064	return (nvlist_add_common(nvl, name, DATA_TYPE_STRING, 1, (void *)val));
1065}
1066
1067int
1068nvlist_add_boolean_array(nvlist_t *nvl, const char *name,
1069    boolean_t *a, uint_t n)
1070{
1071	return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_ARRAY, n, a));
1072}
1073
1074int
1075nvlist_add_byte_array(nvlist_t *nvl, const char *name, uchar_t *a, uint_t n)
1076{
1077	return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a));
1078}
1079
1080int
1081nvlist_add_int8_array(nvlist_t *nvl, const char *name, int8_t *a, uint_t n)
1082{
1083	return (nvlist_add_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a));
1084}
1085
1086int
1087nvlist_add_uint8_array(nvlist_t *nvl, const char *name, uint8_t *a, uint_t n)
1088{
1089	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a));
1090}
1091
1092int
1093nvlist_add_int16_array(nvlist_t *nvl, const char *name, int16_t *a, uint_t n)
1094{
1095	return (nvlist_add_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a));
1096}
1097
1098int
1099nvlist_add_uint16_array(nvlist_t *nvl, const char *name, uint16_t *a, uint_t n)
1100{
1101	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a));
1102}
1103
1104int
1105nvlist_add_int32_array(nvlist_t *nvl, const char *name, int32_t *a, uint_t n)
1106{
1107	return (nvlist_add_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a));
1108}
1109
1110int
1111nvlist_add_uint32_array(nvlist_t *nvl, const char *name, uint32_t *a, uint_t n)
1112{
1113	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a));
1114}
1115
1116int
1117nvlist_add_int64_array(nvlist_t *nvl, const char *name, int64_t *a, uint_t n)
1118{
1119	return (nvlist_add_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a));
1120}
1121
1122int
1123nvlist_add_uint64_array(nvlist_t *nvl, const char *name, uint64_t *a, uint_t n)
1124{
1125	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a));
1126}
1127
1128int
1129nvlist_add_string_array(nvlist_t *nvl, const char *name,
1130    char *const *a, uint_t n)
1131{
1132	return (nvlist_add_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a));
1133}
1134
1135int
1136nvlist_add_hrtime(nvlist_t *nvl, const char *name, hrtime_t val)
1137{
1138	return (nvlist_add_common(nvl, name, DATA_TYPE_HRTIME, 1, &val));
1139}
1140
1141int
1142nvlist_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val)
1143{
1144	return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST, 1, val));
1145}
1146
1147int
1148nvlist_add_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **a, uint_t n)
1149{
1150	return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a));
1151}
1152
1153/* reading name-value pairs */
1154nvpair_t *
1155nvlist_next_nvpair(nvlist_t *nvl, nvpair_t *nvp)
1156{
1157	nvpriv_t *priv;
1158	i_nvp_t *curr;
1159
1160	if (nvl == NULL ||
1161	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
1162		return (NULL);
1163
1164	curr = NVPAIR2I_NVP(nvp);
1165
1166	/*
1167	 * Ensure that nvp is a valid nvpair on this nvlist.
1168	 * NB: nvp_curr is used only as a hint so that we don't always
1169	 * have to walk the list to determine if nvp is still on the list.
1170	 */
1171	if (nvp == NULL)
1172		curr = priv->nvp_list;
1173	else if (priv->nvp_curr == curr || nvlist_contains_nvp(nvl, nvp))
1174		curr = curr->nvi_next;
1175	else
1176		curr = NULL;
1177
1178	priv->nvp_curr = curr;
1179
1180	return (curr != NULL ? &curr->nvi_nvp : NULL);
1181}
1182
1183nvpair_t *
1184nvlist_prev_nvpair(nvlist_t *nvl, nvpair_t *nvp)
1185{
1186	nvpriv_t *priv;
1187	i_nvp_t *curr;
1188
1189	if (nvl == NULL ||
1190	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
1191		return (NULL);
1192
1193	curr = NVPAIR2I_NVP(nvp);
1194
1195	if (nvp == NULL)
1196		curr = priv->nvp_last;
1197	else if (priv->nvp_curr == curr || nvlist_contains_nvp(nvl, nvp))
1198		curr = curr->nvi_prev;
1199	else
1200		curr = NULL;
1201
1202	priv->nvp_curr = curr;
1203
1204	return (curr != NULL ? &curr->nvi_nvp : NULL);
1205}
1206
1207boolean_t
1208nvlist_empty(nvlist_t *nvl)
1209{
1210	nvpriv_t *priv;
1211
1212	if (nvl == NULL ||
1213	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
1214		return (B_TRUE);
1215
1216	return (priv->nvp_list == NULL);
1217}
1218
1219char *
1220nvpair_name(nvpair_t *nvp)
1221{
1222	return (NVP_NAME(nvp));
1223}
1224
1225data_type_t
1226nvpair_type(nvpair_t *nvp)
1227{
1228	return (NVP_TYPE(nvp));
1229}
1230
1231int
1232nvpair_type_is_array(nvpair_t *nvp)
1233{
1234	data_type_t type = NVP_TYPE(nvp);
1235
1236	if ((type == DATA_TYPE_BYTE_ARRAY) ||
1237	    (type == DATA_TYPE_INT8_ARRAY) ||
1238	    (type == DATA_TYPE_UINT8_ARRAY) ||
1239	    (type == DATA_TYPE_INT16_ARRAY) ||
1240	    (type == DATA_TYPE_UINT16_ARRAY) ||
1241	    (type == DATA_TYPE_INT32_ARRAY) ||
1242	    (type == DATA_TYPE_UINT32_ARRAY) ||
1243	    (type == DATA_TYPE_INT64_ARRAY) ||
1244	    (type == DATA_TYPE_UINT64_ARRAY) ||
1245	    (type == DATA_TYPE_BOOLEAN_ARRAY) ||
1246	    (type == DATA_TYPE_STRING_ARRAY) ||
1247	    (type == DATA_TYPE_NVLIST_ARRAY))
1248		return (1);
1249	return (0);
1250
1251}
1252
1253static int
1254nvpair_value_common(nvpair_t *nvp, data_type_t type, uint_t *nelem, void *data)
1255{
1256	if (nvp == NULL || nvpair_type(nvp) != type)
1257		return (EINVAL);
1258
1259	/*
1260	 * For non-array types, we copy the data.
1261	 * For array types (including string), we set a pointer.
1262	 */
1263	switch (type) {
1264	case DATA_TYPE_BOOLEAN:
1265		if (nelem != NULL)
1266			*nelem = 0;
1267		break;
1268
1269	case DATA_TYPE_BOOLEAN_VALUE:
1270	case DATA_TYPE_BYTE:
1271	case DATA_TYPE_INT8:
1272	case DATA_TYPE_UINT8:
1273	case DATA_TYPE_INT16:
1274	case DATA_TYPE_UINT16:
1275	case DATA_TYPE_INT32:
1276	case DATA_TYPE_UINT32:
1277	case DATA_TYPE_INT64:
1278	case DATA_TYPE_UINT64:
1279	case DATA_TYPE_HRTIME:
1280#if !defined(_KERNEL)
1281	case DATA_TYPE_DOUBLE:
1282#endif
1283		if (data == NULL)
1284			return (EINVAL);
1285		bcopy(NVP_VALUE(nvp), data,
1286		    (size_t)i_get_value_size(type, NULL, 1));
1287		if (nelem != NULL)
1288			*nelem = 1;
1289		break;
1290
1291	case DATA_TYPE_NVLIST:
1292	case DATA_TYPE_STRING:
1293		if (data == NULL)
1294			return (EINVAL);
1295		*(void **)data = (void *)NVP_VALUE(nvp);
1296		if (nelem != NULL)
1297			*nelem = 1;
1298		break;
1299
1300	case DATA_TYPE_BOOLEAN_ARRAY:
1301	case DATA_TYPE_BYTE_ARRAY:
1302	case DATA_TYPE_INT8_ARRAY:
1303	case DATA_TYPE_UINT8_ARRAY:
1304	case DATA_TYPE_INT16_ARRAY:
1305	case DATA_TYPE_UINT16_ARRAY:
1306	case DATA_TYPE_INT32_ARRAY:
1307	case DATA_TYPE_UINT32_ARRAY:
1308	case DATA_TYPE_INT64_ARRAY:
1309	case DATA_TYPE_UINT64_ARRAY:
1310	case DATA_TYPE_STRING_ARRAY:
1311	case DATA_TYPE_NVLIST_ARRAY:
1312		if (nelem == NULL || data == NULL)
1313			return (EINVAL);
1314		if ((*nelem = NVP_NELEM(nvp)) != 0)
1315			*(void **)data = (void *)NVP_VALUE(nvp);
1316		else
1317			*(void **)data = NULL;
1318		break;
1319
1320	default:
1321		return (ENOTSUP);
1322	}
1323
1324	return (0);
1325}
1326
1327static int
1328nvlist_lookup_common(nvlist_t *nvl, const char *name, data_type_t type,
1329    uint_t *nelem, void *data)
1330{
1331	nvpriv_t *priv;
1332	nvpair_t *nvp;
1333	i_nvp_t *curr;
1334
1335	if (name == NULL || nvl == NULL ||
1336	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
1337		return (EINVAL);
1338
1339	if (!(nvl->nvl_nvflag & (NV_UNIQUE_NAME | NV_UNIQUE_NAME_TYPE)))
1340		return (ENOTSUP);
1341
1342	for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
1343		nvp = &curr->nvi_nvp;
1344
1345		if (strcmp(name, NVP_NAME(nvp)) == 0 && NVP_TYPE(nvp) == type)
1346			return (nvpair_value_common(nvp, type, nelem, data));
1347	}
1348
1349	return (ENOENT);
1350}
1351
1352int
1353nvlist_lookup_boolean(nvlist_t *nvl, const char *name)
1354{
1355	return (nvlist_lookup_common(nvl, name, DATA_TYPE_BOOLEAN, NULL, NULL));
1356}
1357
1358int
1359nvlist_lookup_boolean_value(nvlist_t *nvl, const char *name, boolean_t *val)
1360{
1361	return (nvlist_lookup_common(nvl, name,
1362	    DATA_TYPE_BOOLEAN_VALUE, NULL, val));
1363}
1364
1365int
1366nvlist_lookup_byte(nvlist_t *nvl, const char *name, uchar_t *val)
1367{
1368	return (nvlist_lookup_common(nvl, name, DATA_TYPE_BYTE, NULL, val));
1369}
1370
1371int
1372nvlist_lookup_int8(nvlist_t *nvl, const char *name, int8_t *val)
1373{
1374	return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT8, NULL, val));
1375}
1376
1377int
1378nvlist_lookup_uint8(nvlist_t *nvl, const char *name, uint8_t *val)
1379{
1380	return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT8, NULL, val));
1381}
1382
1383int
1384nvlist_lookup_int16(nvlist_t *nvl, const char *name, int16_t *val)
1385{
1386	return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT16, NULL, val));
1387}
1388
1389int
1390nvlist_lookup_uint16(nvlist_t *nvl, const char *name, uint16_t *val)
1391{
1392	return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT16, NULL, val));
1393}
1394
1395int
1396nvlist_lookup_int32(nvlist_t *nvl, const char *name, int32_t *val)
1397{
1398	return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT32, NULL, val));
1399}
1400
1401int
1402nvlist_lookup_uint32(nvlist_t *nvl, const char *name, uint32_t *val)
1403{
1404	return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT32, NULL, val));
1405}
1406
1407int
1408nvlist_lookup_int64(nvlist_t *nvl, const char *name, int64_t *val)
1409{
1410	return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT64, NULL, val));
1411}
1412
1413int
1414nvlist_lookup_uint64(nvlist_t *nvl, const char *name, uint64_t *val)
1415{
1416	return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT64, NULL, val));
1417}
1418
1419#if !defined(_KERNEL)
1420int
1421nvlist_lookup_double(nvlist_t *nvl, const char *name, double *val)
1422{
1423	return (nvlist_lookup_common(nvl, name, DATA_TYPE_DOUBLE, NULL, val));
1424}
1425#endif
1426
1427int
1428nvlist_lookup_string(nvlist_t *nvl, const char *name, char **val)
1429{
1430	return (nvlist_lookup_common(nvl, name, DATA_TYPE_STRING, NULL, val));
1431}
1432
1433int
1434nvlist_lookup_nvlist(nvlist_t *nvl, const char *name, nvlist_t **val)
1435{
1436	return (nvlist_lookup_common(nvl, name, DATA_TYPE_NVLIST, NULL, val));
1437}
1438
1439int
1440nvlist_lookup_boolean_array(nvlist_t *nvl, const char *name,
1441    boolean_t **a, uint_t *n)
1442{
1443	return (nvlist_lookup_common(nvl, name,
1444	    DATA_TYPE_BOOLEAN_ARRAY, n, a));
1445}
1446
1447int
1448nvlist_lookup_byte_array(nvlist_t *nvl, const char *name,
1449    uchar_t **a, uint_t *n)
1450{
1451	return (nvlist_lookup_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a));
1452}
1453
1454int
1455nvlist_lookup_int8_array(nvlist_t *nvl, const char *name, int8_t **a, uint_t *n)
1456{
1457	return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a));
1458}
1459
1460int
1461nvlist_lookup_uint8_array(nvlist_t *nvl, const char *name,
1462    uint8_t **a, uint_t *n)
1463{
1464	return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a));
1465}
1466
1467int
1468nvlist_lookup_int16_array(nvlist_t *nvl, const char *name,
1469    int16_t **a, uint_t *n)
1470{
1471	return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a));
1472}
1473
1474int
1475nvlist_lookup_uint16_array(nvlist_t *nvl, const char *name,
1476    uint16_t **a, uint_t *n)
1477{
1478	return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a));
1479}
1480
1481int
1482nvlist_lookup_int32_array(nvlist_t *nvl, const char *name,
1483    int32_t **a, uint_t *n)
1484{
1485	return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a));
1486}
1487
1488int
1489nvlist_lookup_uint32_array(nvlist_t *nvl, const char *name,
1490    uint32_t **a, uint_t *n)
1491{
1492	return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a));
1493}
1494
1495int
1496nvlist_lookup_int64_array(nvlist_t *nvl, const char *name,
1497    int64_t **a, uint_t *n)
1498{
1499	return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a));
1500}
1501
1502int
1503nvlist_lookup_uint64_array(nvlist_t *nvl, const char *name,
1504    uint64_t **a, uint_t *n)
1505{
1506	return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a));
1507}
1508
1509int
1510nvlist_lookup_string_array(nvlist_t *nvl, const char *name,
1511    char ***a, uint_t *n)
1512{
1513	return (nvlist_lookup_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a));
1514}
1515
1516int
1517nvlist_lookup_nvlist_array(nvlist_t *nvl, const char *name,
1518    nvlist_t ***a, uint_t *n)
1519{
1520	return (nvlist_lookup_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a));
1521}
1522
1523int
1524nvlist_lookup_hrtime(nvlist_t *nvl, const char *name, hrtime_t *val)
1525{
1526	return (nvlist_lookup_common(nvl, name, DATA_TYPE_HRTIME, NULL, val));
1527}
1528
1529int
1530nvlist_lookup_pairs(nvlist_t *nvl, int flag, ...)
1531{
1532	va_list ap;
1533	char *name;
1534	int noentok = (flag & NV_FLAG_NOENTOK ? 1 : 0);
1535	int ret = 0;
1536
1537	va_start(ap, flag);
1538	while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
1539		data_type_t type;
1540		void *val;
1541		uint_t *nelem;
1542
1543		switch (type = va_arg(ap, data_type_t)) {
1544		case DATA_TYPE_BOOLEAN:
1545			ret = nvlist_lookup_common(nvl, name, type, NULL, NULL);
1546			break;
1547
1548		case DATA_TYPE_BOOLEAN_VALUE:
1549		case DATA_TYPE_BYTE:
1550		case DATA_TYPE_INT8:
1551		case DATA_TYPE_UINT8:
1552		case DATA_TYPE_INT16:
1553		case DATA_TYPE_UINT16:
1554		case DATA_TYPE_INT32:
1555		case DATA_TYPE_UINT32:
1556		case DATA_TYPE_INT64:
1557		case DATA_TYPE_UINT64:
1558		case DATA_TYPE_HRTIME:
1559		case DATA_TYPE_STRING:
1560		case DATA_TYPE_NVLIST:
1561#if !defined(_KERNEL)
1562		case DATA_TYPE_DOUBLE:
1563#endif
1564			val = va_arg(ap, void *);
1565			ret = nvlist_lookup_common(nvl, name, type, NULL, val);
1566			break;
1567
1568		case DATA_TYPE_BYTE_ARRAY:
1569		case DATA_TYPE_BOOLEAN_ARRAY:
1570		case DATA_TYPE_INT8_ARRAY:
1571		case DATA_TYPE_UINT8_ARRAY:
1572		case DATA_TYPE_INT16_ARRAY:
1573		case DATA_TYPE_UINT16_ARRAY:
1574		case DATA_TYPE_INT32_ARRAY:
1575		case DATA_TYPE_UINT32_ARRAY:
1576		case DATA_TYPE_INT64_ARRAY:
1577		case DATA_TYPE_UINT64_ARRAY:
1578		case DATA_TYPE_STRING_ARRAY:
1579		case DATA_TYPE_NVLIST_ARRAY:
1580			val = va_arg(ap, void *);
1581			nelem = va_arg(ap, uint_t *);
1582			ret = nvlist_lookup_common(nvl, name, type, nelem, val);
1583			break;
1584
1585		default:
1586			ret = EINVAL;
1587		}
1588
1589		if (ret == ENOENT && noentok)
1590			ret = 0;
1591	}
1592	va_end(ap);
1593
1594	return (ret);
1595}
1596
1597/*
1598 * Find the 'name'ed nvpair in the nvlist 'nvl'. If 'name' found, the function
1599 * returns zero and a pointer to the matching nvpair is returned in '*ret'
1600 * (given 'ret' is non-NULL). If 'sep' is specified then 'name' will penitrate
1601 * multiple levels of embedded nvlists, with 'sep' as the separator. As an
1602 * example, if sep is '.', name might look like: "a" or "a.b" or "a.c[3]" or
1603 * "a.d[3].e[1]".  This matches the C syntax for array embed (for convience,
1604 * code also supports "a.d[3]e[1]" syntax).
1605 *
1606 * If 'ip' is non-NULL and the last name component is an array, return the
1607 * value of the "...[index]" array index in *ip. For an array reference that
1608 * is not indexed, *ip will be returned as -1. If there is a syntax error in
1609 * 'name', and 'ep' is non-NULL then *ep will be set to point to the location
1610 * inside the 'name' string where the syntax error was detected.
1611 */
1612static int
1613nvlist_lookup_nvpair_ei_sep(nvlist_t *nvl, const char *name, const char sep,
1614    nvpair_t **ret, int *ip, char **ep)
1615{
1616	nvpair_t	*nvp;
1617	const char	*np;
1618	char		*sepp;
1619	char		*idxp, *idxep;
1620	nvlist_t	**nva;
1621	long		idx;
1622	int		n;
1623
1624	if (ip)
1625		*ip = -1;			/* not indexed */
1626	if (ep)
1627		*ep = NULL;
1628
1629	if ((nvl == NULL) || (name == NULL))
1630		return (EINVAL);
1631
1632	sepp = NULL;
1633	idx = 0;
1634	/* step through components of name */
1635	for (np = name; np && *np; np = sepp) {
1636		/* ensure unique names */
1637		if (!(nvl->nvl_nvflag & NV_UNIQUE_NAME))
1638			return (ENOTSUP);
1639
1640		/* skip white space */
1641		skip_whitespace(np);
1642		if (*np == 0)
1643			break;
1644
1645		/* set 'sepp' to end of current component 'np' */
1646		if (sep)
1647			sepp = strchr(np, sep);
1648		else
1649			sepp = NULL;
1650
1651		/* find start of next "[ index ]..." */
1652		idxp = strchr(np, '[');
1653
1654		/* if sepp comes first, set idxp to NULL */
1655		if (sepp && idxp && (sepp < idxp))
1656			idxp = NULL;
1657
1658		/*
1659		 * At this point 'idxp' is set if there is an index
1660		 * expected for the current component.
1661		 */
1662		if (idxp) {
1663			/* set 'n' to length of current 'np' name component */
1664			n = idxp++ - np;
1665
1666			/* keep sepp up to date for *ep use as we advance */
1667			skip_whitespace(idxp);
1668			sepp = idxp;
1669
1670			/* determine the index value */
1671#if defined(_KERNEL) && !defined(_BOOT)
1672			if (ddi_strtol(idxp, &idxep, 0, &idx))
1673				goto fail;
1674#else
1675			idx = strtol(idxp, &idxep, 0);
1676#endif
1677			if (idxep == idxp)
1678				goto fail;
1679
1680			/* keep sepp up to date for *ep use as we advance */
1681			sepp = idxep;
1682
1683			/* skip white space index value and check for ']' */
1684			skip_whitespace(sepp);
1685			if (*sepp++ != ']')
1686				goto fail;
1687
1688			/* for embedded arrays, support C syntax: "a[1].b" */
1689			skip_whitespace(sepp);
1690			if (sep && (*sepp == sep))
1691				sepp++;
1692		} else if (sepp) {
1693			n = sepp++ - np;
1694		} else {
1695			n = strlen(np);
1696		}
1697
1698		/* trim trailing whitespace by reducing length of 'np' */
1699		if (n == 0)
1700			goto fail;
1701		for (n--; (np[n] == ' ') || (np[n] == '\t'); n--)
1702			;
1703		n++;
1704
1705		/* skip whitespace, and set sepp to NULL if complete */
1706		if (sepp) {
1707			skip_whitespace(sepp);
1708			if (*sepp == 0)
1709				sepp = NULL;
1710		}
1711
1712		/*
1713		 * At this point:
1714		 * o  'n' is the length of current 'np' component.
1715		 * o  'idxp' is set if there was an index, and value 'idx'.
1716		 * o  'sepp' is set to the beginning of the next component,
1717		 *    and set to NULL if we have no more components.
1718		 *
1719		 * Search for nvpair with matching component name.
1720		 */
1721		for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
1722		    nvp = nvlist_next_nvpair(nvl, nvp)) {
1723
1724			/* continue if no match on name */
1725			if (strncmp(np, nvpair_name(nvp), n) ||
1726			    (strlen(nvpair_name(nvp)) != n))
1727				continue;
1728
1729			/* if indexed, verify type is array oriented */
1730			if (idxp && !nvpair_type_is_array(nvp))
1731				goto fail;
1732
1733			/*
1734			 * Full match found, return nvp and idx if this
1735			 * was the last component.
1736			 */
1737			if (sepp == NULL) {
1738				if (ret)
1739					*ret = nvp;
1740				if (ip && idxp)
1741					*ip = (int)idx;	/* return index */
1742				return (0);		/* found */
1743			}
1744
1745			/*
1746			 * More components: current match must be
1747			 * of DATA_TYPE_NVLIST or DATA_TYPE_NVLIST_ARRAY
1748			 * to support going deeper.
1749			 */
1750			if (nvpair_type(nvp) == DATA_TYPE_NVLIST) {
1751				nvl = EMBEDDED_NVL(nvp);
1752				break;
1753			} else if (nvpair_type(nvp) == DATA_TYPE_NVLIST_ARRAY) {
1754				(void) nvpair_value_nvlist_array(nvp,
1755				    &nva, (uint_t *)&n);
1756				if ((n < 0) || (idx >= n))
1757					goto fail;
1758				nvl = nva[idx];
1759				break;
1760			}
1761
1762			/* type does not support more levels */
1763			goto fail;
1764		}
1765		if (nvp == NULL)
1766			goto fail;		/* 'name' not found */
1767
1768		/* search for match of next component in embedded 'nvl' list */
1769	}
1770
1771fail:	if (ep && sepp)
1772		*ep = sepp;
1773	return (EINVAL);
1774}
1775
1776/*
1777 * Return pointer to nvpair with specified 'name'.
1778 */
1779int
1780nvlist_lookup_nvpair(nvlist_t *nvl, const char *name, nvpair_t **ret)
1781{
1782	return (nvlist_lookup_nvpair_ei_sep(nvl, name, 0, ret, NULL, NULL));
1783}
1784
1785/*
1786 * Determine if named nvpair exists in nvlist (use embedded separator of '.'
1787 * and return array index).  See nvlist_lookup_nvpair_ei_sep for more detailed
1788 * description.
1789 */
1790int nvlist_lookup_nvpair_embedded_index(nvlist_t *nvl,
1791    const char *name, nvpair_t **ret, int *ip, char **ep)
1792{
1793	return (nvlist_lookup_nvpair_ei_sep(nvl, name, '.', ret, ip, ep));
1794}
1795
1796boolean_t
1797nvlist_exists(nvlist_t *nvl, const char *name)
1798{
1799	nvpriv_t *priv;
1800	nvpair_t *nvp;
1801	i_nvp_t *curr;
1802
1803	if (name == NULL || nvl == NULL ||
1804	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
1805		return (B_FALSE);
1806
1807	for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
1808		nvp = &curr->nvi_nvp;
1809
1810		if (strcmp(name, NVP_NAME(nvp)) == 0)
1811			return (B_TRUE);
1812	}
1813
1814	return (B_FALSE);
1815}
1816
1817int
1818nvpair_value_boolean_value(nvpair_t *nvp, boolean_t *val)
1819{
1820	return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_VALUE, NULL, val));
1821}
1822
1823int
1824nvpair_value_byte(nvpair_t *nvp, uchar_t *val)
1825{
1826	return (nvpair_value_common(nvp, DATA_TYPE_BYTE, NULL, val));
1827}
1828
1829int
1830nvpair_value_int8(nvpair_t *nvp, int8_t *val)
1831{
1832	return (nvpair_value_common(nvp, DATA_TYPE_INT8, NULL, val));
1833}
1834
1835int
1836nvpair_value_uint8(nvpair_t *nvp, uint8_t *val)
1837{
1838	return (nvpair_value_common(nvp, DATA_TYPE_UINT8, NULL, val));
1839}
1840
1841int
1842nvpair_value_int16(nvpair_t *nvp, int16_t *val)
1843{
1844	return (nvpair_value_common(nvp, DATA_TYPE_INT16, NULL, val));
1845}
1846
1847int
1848nvpair_value_uint16(nvpair_t *nvp, uint16_t *val)
1849{
1850	return (nvpair_value_common(nvp, DATA_TYPE_UINT16, NULL, val));
1851}
1852
1853int
1854nvpair_value_int32(nvpair_t *nvp, int32_t *val)
1855{
1856	return (nvpair_value_common(nvp, DATA_TYPE_INT32, NULL, val));
1857}
1858
1859int
1860nvpair_value_uint32(nvpair_t *nvp, uint32_t *val)
1861{
1862	return (nvpair_value_common(nvp, DATA_TYPE_UINT32, NULL, val));
1863}
1864
1865int
1866nvpair_value_int64(nvpair_t *nvp, int64_t *val)
1867{
1868	return (nvpair_value_common(nvp, DATA_TYPE_INT64, NULL, val));
1869}
1870
1871int
1872nvpair_value_uint64(nvpair_t *nvp, uint64_t *val)
1873{
1874	return (nvpair_value_common(nvp, DATA_TYPE_UINT64, NULL, val));
1875}
1876
1877#if !defined(_KERNEL)
1878int
1879nvpair_value_double(nvpair_t *nvp, double *val)
1880{
1881	return (nvpair_value_common(nvp, DATA_TYPE_DOUBLE, NULL, val));
1882}
1883#endif
1884
1885int
1886nvpair_value_string(nvpair_t *nvp, char **val)
1887{
1888	return (nvpair_value_common(nvp, DATA_TYPE_STRING, NULL, val));
1889}
1890
1891int
1892nvpair_value_nvlist(nvpair_t *nvp, nvlist_t **val)
1893{
1894	return (nvpair_value_common(nvp, DATA_TYPE_NVLIST, NULL, val));
1895}
1896
1897int
1898nvpair_value_boolean_array(nvpair_t *nvp, boolean_t **val, uint_t *nelem)
1899{
1900	return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_ARRAY, nelem, val));
1901}
1902
1903int
1904nvpair_value_byte_array(nvpair_t *nvp, uchar_t **val, uint_t *nelem)
1905{
1906	return (nvpair_value_common(nvp, DATA_TYPE_BYTE_ARRAY, nelem, val));
1907}
1908
1909int
1910nvpair_value_int8_array(nvpair_t *nvp, int8_t **val, uint_t *nelem)
1911{
1912	return (nvpair_value_common(nvp, DATA_TYPE_INT8_ARRAY, nelem, val));
1913}
1914
1915int
1916nvpair_value_uint8_array(nvpair_t *nvp, uint8_t **val, uint_t *nelem)
1917{
1918	return (nvpair_value_common(nvp, DATA_TYPE_UINT8_ARRAY, nelem, val));
1919}
1920
1921int
1922nvpair_value_int16_array(nvpair_t *nvp, int16_t **val, uint_t *nelem)
1923{
1924	return (nvpair_value_common(nvp, DATA_TYPE_INT16_ARRAY, nelem, val));
1925}
1926
1927int
1928nvpair_value_uint16_array(nvpair_t *nvp, uint16_t **val, uint_t *nelem)
1929{
1930	return (nvpair_value_common(nvp, DATA_TYPE_UINT16_ARRAY, nelem, val));
1931}
1932
1933int
1934nvpair_value_int32_array(nvpair_t *nvp, int32_t **val, uint_t *nelem)
1935{
1936	return (nvpair_value_common(nvp, DATA_TYPE_INT32_ARRAY, nelem, val));
1937}
1938
1939int
1940nvpair_value_uint32_array(nvpair_t *nvp, uint32_t **val, uint_t *nelem)
1941{
1942	return (nvpair_value_common(nvp, DATA_TYPE_UINT32_ARRAY, nelem, val));
1943}
1944
1945int
1946nvpair_value_int64_array(nvpair_t *nvp, int64_t **val, uint_t *nelem)
1947{
1948	return (nvpair_value_common(nvp, DATA_TYPE_INT64_ARRAY, nelem, val));
1949}
1950
1951int
1952nvpair_value_uint64_array(nvpair_t *nvp, uint64_t **val, uint_t *nelem)
1953{
1954	return (nvpair_value_common(nvp, DATA_TYPE_UINT64_ARRAY, nelem, val));
1955}
1956
1957int
1958nvpair_value_string_array(nvpair_t *nvp, char ***val, uint_t *nelem)
1959{
1960	return (nvpair_value_common(nvp, DATA_TYPE_STRING_ARRAY, nelem, val));
1961}
1962
1963int
1964nvpair_value_nvlist_array(nvpair_t *nvp, nvlist_t ***val, uint_t *nelem)
1965{
1966	return (nvpair_value_common(nvp, DATA_TYPE_NVLIST_ARRAY, nelem, val));
1967}
1968
1969int
1970nvpair_value_hrtime(nvpair_t *nvp, hrtime_t *val)
1971{
1972	return (nvpair_value_common(nvp, DATA_TYPE_HRTIME, NULL, val));
1973}
1974
1975/*
1976 * Add specified pair to the list.
1977 */
1978int
1979nvlist_add_nvpair(nvlist_t *nvl, nvpair_t *nvp)
1980{
1981	if (nvl == NULL || nvp == NULL)
1982		return (EINVAL);
1983
1984	return (nvlist_add_common(nvl, NVP_NAME(nvp), NVP_TYPE(nvp),
1985	    NVP_NELEM(nvp), NVP_VALUE(nvp)));
1986}
1987
1988/*
1989 * Merge the supplied nvlists and put the result in dst.
1990 * The merged list will contain all names specified in both lists,
1991 * the values are taken from nvl in the case of duplicates.
1992 * Return 0 on success.
1993 */
1994/*ARGSUSED*/
1995int
1996nvlist_merge(nvlist_t *dst, nvlist_t *nvl, int flag)
1997{
1998	if (nvl == NULL || dst == NULL)
1999		return (EINVAL);
2000
2001	if (dst != nvl)
2002		return (nvlist_copy_pairs(nvl, dst));
2003
2004	return (0);
2005}
2006
2007/*
2008 * Encoding related routines
2009 */
2010#define	NVS_OP_ENCODE	0
2011#define	NVS_OP_DECODE	1
2012#define	NVS_OP_GETSIZE	2
2013
2014typedef struct nvs_ops nvs_ops_t;
2015
2016typedef struct {
2017	int		nvs_op;
2018	const nvs_ops_t	*nvs_ops;
2019	void		*nvs_private;
2020	nvpriv_t	*nvs_priv;
2021} nvstream_t;
2022
2023/*
2024 * nvs operations are:
2025 *   - nvs_nvlist
2026 *     encoding / decoding of a nvlist header (nvlist_t)
2027 *     calculates the size used for header and end detection
2028 *
2029 *   - nvs_nvpair
2030 *     responsible for the first part of encoding / decoding of an nvpair
2031 *     calculates the decoded size of an nvpair
2032 *
2033 *   - nvs_nvp_op
2034 *     second part of encoding / decoding of an nvpair
2035 *
2036 *   - nvs_nvp_size
2037 *     calculates the encoding size of an nvpair
2038 *
2039 *   - nvs_nvl_fini
2040 *     encodes the end detection mark (zeros).
2041 */
2042struct nvs_ops {
2043	int (*nvs_nvlist)(nvstream_t *, nvlist_t *, size_t *);
2044	int (*nvs_nvpair)(nvstream_t *, nvpair_t *, size_t *);
2045	int (*nvs_nvp_op)(nvstream_t *, nvpair_t *);
2046	int (*nvs_nvp_size)(nvstream_t *, nvpair_t *, size_t *);
2047	int (*nvs_nvl_fini)(nvstream_t *);
2048};
2049
2050typedef struct {
2051	char	nvh_encoding;	/* nvs encoding method */
2052	char	nvh_endian;	/* nvs endian */
2053	char	nvh_reserved1;	/* reserved for future use */
2054	char	nvh_reserved2;	/* reserved for future use */
2055} nvs_header_t;
2056
2057static int
2058nvs_encode_pairs(nvstream_t *nvs, nvlist_t *nvl)
2059{
2060	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
2061	i_nvp_t *curr;
2062
2063	/*
2064	 * Walk nvpair in list and encode each nvpair
2065	 */
2066	for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next)
2067		if (nvs->nvs_ops->nvs_nvpair(nvs, &curr->nvi_nvp, NULL) != 0)
2068			return (EFAULT);
2069
2070	return (nvs->nvs_ops->nvs_nvl_fini(nvs));
2071}
2072
2073static int
2074nvs_decode_pairs(nvstream_t *nvs, nvlist_t *nvl)
2075{
2076	nvpair_t *nvp;
2077	size_t nvsize;
2078	int err;
2079
2080	/*
2081	 * Get decoded size of next pair in stream, alloc
2082	 * memory for nvpair_t, then decode the nvpair
2083	 */
2084	while ((err = nvs->nvs_ops->nvs_nvpair(nvs, NULL, &nvsize)) == 0) {
2085		if (nvsize == 0) /* end of list */
2086			break;
2087
2088		/* make sure len makes sense */
2089		if (nvsize < NVP_SIZE_CALC(1, 0))
2090			return (EFAULT);
2091
2092		if ((nvp = nvp_buf_alloc(nvl, nvsize)) == NULL)
2093			return (ENOMEM);
2094
2095		if ((err = nvs->nvs_ops->nvs_nvp_op(nvs, nvp)) != 0) {
2096			nvp_buf_free(nvl, nvp);
2097			return (err);
2098		}
2099
2100		if (i_validate_nvpair(nvp) != 0) {
2101			nvpair_free(nvp);
2102			nvp_buf_free(nvl, nvp);
2103			return (EFAULT);
2104		}
2105
2106		nvp_buf_link(nvl, nvp);
2107	}
2108	return (err);
2109}
2110
2111static int
2112nvs_getsize_pairs(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen)
2113{
2114	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
2115	i_nvp_t *curr;
2116	uint64_t nvsize = *buflen;
2117	size_t size;
2118
2119	/*
2120	 * Get encoded size of nvpairs in nvlist
2121	 */
2122	for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
2123		if (nvs->nvs_ops->nvs_nvp_size(nvs, &curr->nvi_nvp, &size) != 0)
2124			return (EINVAL);
2125
2126		if ((nvsize += size) > INT32_MAX)
2127			return (EINVAL);
2128	}
2129
2130	*buflen = nvsize;
2131	return (0);
2132}
2133
2134static int
2135nvs_operation(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen)
2136{
2137	int err;
2138
2139	if (nvl->nvl_priv == 0)
2140		return (EFAULT);
2141
2142	/*
2143	 * Perform the operation, starting with header, then each nvpair
2144	 */
2145	if ((err = nvs->nvs_ops->nvs_nvlist(nvs, nvl, buflen)) != 0)
2146		return (err);
2147
2148	switch (nvs->nvs_op) {
2149	case NVS_OP_ENCODE:
2150		err = nvs_encode_pairs(nvs, nvl);
2151		break;
2152
2153	case NVS_OP_DECODE:
2154		err = nvs_decode_pairs(nvs, nvl);
2155		break;
2156
2157	case NVS_OP_GETSIZE:
2158		err = nvs_getsize_pairs(nvs, nvl, buflen);
2159		break;
2160
2161	default:
2162		err = EINVAL;
2163	}
2164
2165	return (err);
2166}
2167
2168static int
2169nvs_embedded(nvstream_t *nvs, nvlist_t *embedded)
2170{
2171	switch (nvs->nvs_op) {
2172	case NVS_OP_ENCODE:
2173		return (nvs_operation(nvs, embedded, NULL));
2174
2175	case NVS_OP_DECODE: {
2176		nvpriv_t *priv;
2177		int err;
2178
2179		if (embedded->nvl_version != NV_VERSION)
2180			return (ENOTSUP);
2181
2182		if ((priv = nv_priv_alloc_embedded(nvs->nvs_priv)) == NULL)
2183			return (ENOMEM);
2184
2185		nvlist_init(embedded, embedded->nvl_nvflag, priv);
2186
2187		if ((err = nvs_operation(nvs, embedded, NULL)) != 0)
2188			nvlist_free(embedded);
2189		return (err);
2190	}
2191	default:
2192		break;
2193	}
2194
2195	return (EINVAL);
2196}
2197
2198static int
2199nvs_embedded_nvl_array(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
2200{
2201	size_t nelem = NVP_NELEM(nvp);
2202	nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);
2203	int i;
2204
2205	switch (nvs->nvs_op) {
2206	case NVS_OP_ENCODE:
2207		for (i = 0; i < nelem; i++)
2208			if (nvs_embedded(nvs, nvlp[i]) != 0)
2209				return (EFAULT);
2210		break;
2211
2212	case NVS_OP_DECODE: {
2213		size_t len = nelem * sizeof (uint64_t);
2214		nvlist_t *embedded = (nvlist_t *)((uintptr_t)nvlp + len);
2215
2216		bzero(nvlp, len);	/* don't trust packed data */
2217		for (i = 0; i < nelem; i++) {
2218			if (nvs_embedded(nvs, embedded) != 0) {
2219				nvpair_free(nvp);
2220				return (EFAULT);
2221			}
2222
2223			nvlp[i] = embedded++;
2224		}
2225		break;
2226	}
2227	case NVS_OP_GETSIZE: {
2228		uint64_t nvsize = 0;
2229
2230		for (i = 0; i < nelem; i++) {
2231			size_t nvp_sz = 0;
2232
2233			if (nvs_operation(nvs, nvlp[i], &nvp_sz) != 0)
2234				return (EINVAL);
2235
2236			if ((nvsize += nvp_sz) > INT32_MAX)
2237				return (EINVAL);
2238		}
2239
2240		*size = nvsize;
2241		break;
2242	}
2243	default:
2244		return (EINVAL);
2245	}
2246
2247	return (0);
2248}
2249
2250static int nvs_native(nvstream_t *, nvlist_t *, char *, size_t *);
2251static int nvs_xdr(nvstream_t *, nvlist_t *, char *, size_t *);
2252
2253/*
2254 * Common routine for nvlist operations:
2255 * encode, decode, getsize (encoded size).
2256 */
2257static int
2258nvlist_common(nvlist_t *nvl, char *buf, size_t *buflen, int encoding,
2259    int nvs_op)
2260{
2261	int err = 0;
2262	nvstream_t nvs;
2263	int nvl_endian;
2264#if BYTE_ORDER == _LITTLE_ENDIAN
2265	int host_endian = 1;
2266#else
2267	int host_endian = 0;
2268#endif	/* _LITTLE_ENDIAN */
2269	nvs_header_t *nvh = (void *)buf;
2270
2271	if (buflen == NULL || nvl == NULL ||
2272	    (nvs.nvs_priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
2273		return (EINVAL);
2274
2275	nvs.nvs_op = nvs_op;
2276
2277	/*
2278	 * For NVS_OP_ENCODE and NVS_OP_DECODE make sure an nvlist and
2279	 * a buffer is allocated.  The first 4 bytes in the buffer are
2280	 * used for encoding method and host endian.
2281	 */
2282	switch (nvs_op) {
2283	case NVS_OP_ENCODE:
2284		if (buf == NULL || *buflen < sizeof (nvs_header_t))
2285			return (EINVAL);
2286
2287		nvh->nvh_encoding = encoding;
2288		nvh->nvh_endian = nvl_endian = host_endian;
2289		nvh->nvh_reserved1 = 0;
2290		nvh->nvh_reserved2 = 0;
2291		break;
2292
2293	case NVS_OP_DECODE:
2294		if (buf == NULL || *buflen < sizeof (nvs_header_t))
2295			return (EINVAL);
2296
2297		/* get method of encoding from first byte */
2298		encoding = nvh->nvh_encoding;
2299		nvl_endian = nvh->nvh_endian;
2300		break;
2301
2302	case NVS_OP_GETSIZE:
2303		nvl_endian = host_endian;
2304
2305		/*
2306		 * add the size for encoding
2307		 */
2308		*buflen = sizeof (nvs_header_t);
2309		break;
2310
2311	default:
2312		return (ENOTSUP);
2313	}
2314
2315	/*
2316	 * Create an nvstream with proper encoding method
2317	 */
2318	switch (encoding) {
2319	case NV_ENCODE_NATIVE:
2320		/*
2321		 * check endianness, in case we are unpacking
2322		 * from a file
2323		 */
2324		if (nvl_endian != host_endian)
2325			return (ENOTSUP);
2326		err = nvs_native(&nvs, nvl, buf, buflen);
2327		break;
2328	case NV_ENCODE_XDR:
2329		err = nvs_xdr(&nvs, nvl, buf, buflen);
2330		break;
2331	default:
2332		err = ENOTSUP;
2333		break;
2334	}
2335
2336	return (err);
2337}
2338
2339int
2340nvlist_size(nvlist_t *nvl, size_t *size, int encoding)
2341{
2342	return (nvlist_common(nvl, NULL, size, encoding, NVS_OP_GETSIZE));
2343}
2344
2345/*
2346 * Pack nvlist into contiguous memory
2347 */
2348/*ARGSUSED1*/
2349int
2350nvlist_pack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding,
2351    int kmflag)
2352{
2353#if defined(_KERNEL) && !defined(_BOOT)
2354	return (nvlist_xpack(nvl, bufp, buflen, encoding,
2355	    (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep)));
2356#else
2357	return (nvlist_xpack(nvl, bufp, buflen, encoding, nv_alloc_nosleep));
2358#endif
2359}
2360
2361int
2362nvlist_xpack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding,
2363    nv_alloc_t *nva)
2364{
2365	nvpriv_t nvpriv;
2366	size_t alloc_size;
2367	char *buf;
2368	int err;
2369
2370	if (nva == NULL || nvl == NULL || bufp == NULL || buflen == NULL)
2371		return (EINVAL);
2372
2373	if (*bufp != NULL)
2374		return (nvlist_common(nvl, *bufp, buflen, encoding,
2375		    NVS_OP_ENCODE));
2376
2377	/*
2378	 * Here is a difficult situation:
2379	 * 1. The nvlist has fixed allocator properties.
2380	 *    All other nvlist routines (like nvlist_add_*, ...) use
2381	 *    these properties.
2382	 * 2. When using nvlist_pack() the user can specify his own
2383	 *    allocator properties (e.g. by using KM_NOSLEEP).
2384	 *
2385	 * We use the user specified properties (2). A clearer solution
2386	 * will be to remove the kmflag from nvlist_pack(), but we will
2387	 * not change the interface.
2388	 */
2389	nv_priv_init(&nvpriv, nva, 0);
2390
2391	if ((err = nvlist_size(nvl, &alloc_size, encoding)))
2392		return (err);
2393
2394	if ((buf = nv_mem_zalloc(&nvpriv, alloc_size)) == NULL)
2395		return (ENOMEM);
2396
2397	if ((err = nvlist_common(nvl, buf, &alloc_size, encoding,
2398	    NVS_OP_ENCODE)) != 0) {
2399		nv_mem_free(&nvpriv, buf, alloc_size);
2400	} else {
2401		*buflen = alloc_size;
2402		*bufp = buf;
2403	}
2404
2405	return (err);
2406}
2407
2408/*
2409 * Unpack buf into an nvlist_t
2410 */
2411/*ARGSUSED1*/
2412int
2413nvlist_unpack(char *buf, size_t buflen, nvlist_t **nvlp, int kmflag)
2414{
2415#if defined(_KERNEL) && !defined(_BOOT)
2416	return (nvlist_xunpack(buf, buflen, nvlp,
2417	    (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep)));
2418#else
2419	return (nvlist_xunpack(buf, buflen, nvlp, nv_alloc_nosleep));
2420#endif
2421}
2422
2423int
2424nvlist_xunpack(char *buf, size_t buflen, nvlist_t **nvlp, nv_alloc_t *nva)
2425{
2426	nvlist_t *nvl;
2427	int err;
2428
2429	if (nvlp == NULL)
2430		return (EINVAL);
2431
2432	if ((err = nvlist_xalloc(&nvl, 0, nva)) != 0)
2433		return (err);
2434
2435	if ((err = nvlist_common(nvl, buf, &buflen, 0, NVS_OP_DECODE)) != 0)
2436		nvlist_free(nvl);
2437	else
2438		*nvlp = nvl;
2439
2440	return (err);
2441}
2442
2443/*
2444 * Native encoding functions
2445 */
2446typedef struct {
2447	/*
2448	 * This structure is used when decoding a packed nvpair in
2449	 * the native format.  n_base points to a buffer containing the
2450	 * packed nvpair.  n_end is a pointer to the end of the buffer.
2451	 * (n_end actually points to the first byte past the end of the
2452	 * buffer.)  n_curr is a pointer that lies between n_base and n_end.
2453	 * It points to the current data that we are decoding.
2454	 * The amount of data left in the buffer is equal to n_end - n_curr.
2455	 * n_flag is used to recognize a packed embedded list.
2456	 */
2457	caddr_t n_base;
2458	caddr_t n_end;
2459	caddr_t n_curr;
2460	uint_t  n_flag;
2461} nvs_native_t;
2462
2463static int
2464nvs_native_create(nvstream_t *nvs, nvs_native_t *native, char *buf,
2465    size_t buflen)
2466{
2467	switch (nvs->nvs_op) {
2468	case NVS_OP_ENCODE:
2469	case NVS_OP_DECODE:
2470		nvs->nvs_private = native;
2471		native->n_curr = native->n_base = buf;
2472		native->n_end = buf + buflen;
2473		native->n_flag = 0;
2474		return (0);
2475
2476	case NVS_OP_GETSIZE:
2477		nvs->nvs_private = native;
2478		native->n_curr = native->n_base = native->n_end = NULL;
2479		native->n_flag = 0;
2480		return (0);
2481	default:
2482		return (EINVAL);
2483	}
2484}
2485
2486/*ARGSUSED*/
2487static void
2488nvs_native_destroy(nvstream_t *nvs)
2489{
2490}
2491
2492static int
2493native_cp(nvstream_t *nvs, void *buf, size_t size)
2494{
2495	nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
2496
2497	if (native->n_curr + size > native->n_end)
2498		return (EFAULT);
2499
2500	/*
2501	 * The bcopy() below eliminates alignment requirement
2502	 * on the buffer (stream) and is preferred over direct access.
2503	 */
2504	switch (nvs->nvs_op) {
2505	case NVS_OP_ENCODE:
2506		bcopy(buf, native->n_curr, size);
2507		break;
2508	case NVS_OP_DECODE:
2509		bcopy(native->n_curr, buf, size);
2510		break;
2511	default:
2512		return (EINVAL);
2513	}
2514
2515	native->n_curr += size;
2516	return (0);
2517}
2518
2519/*
2520 * operate on nvlist_t header
2521 */
2522static int
2523nvs_native_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size)
2524{
2525	nvs_native_t *native = nvs->nvs_private;
2526
2527	switch (nvs->nvs_op) {
2528	case NVS_OP_ENCODE:
2529	case NVS_OP_DECODE:
2530		if (native->n_flag)
2531			return (0);	/* packed embedded list */
2532
2533		native->n_flag = 1;
2534
2535		/* copy version and nvflag of the nvlist_t */
2536		if (native_cp(nvs, &nvl->nvl_version, sizeof (int32_t)) != 0 ||
2537		    native_cp(nvs, &nvl->nvl_nvflag, sizeof (int32_t)) != 0)
2538			return (EFAULT);
2539
2540		return (0);
2541
2542	case NVS_OP_GETSIZE:
2543		/*
2544		 * if calculate for packed embedded list
2545		 * 	4 for end of the embedded list
2546		 * else
2547		 * 	2 * sizeof (int32_t) for nvl_version and nvl_nvflag
2548		 * 	and 4 for end of the entire list
2549		 */
2550		if (native->n_flag) {
2551			*size += 4;
2552		} else {
2553			native->n_flag = 1;
2554			*size += 2 * sizeof (int32_t) + 4;
2555		}
2556
2557		return (0);
2558
2559	default:
2560		return (EINVAL);
2561	}
2562}
2563
2564static int
2565nvs_native_nvl_fini(nvstream_t *nvs)
2566{
2567	if (nvs->nvs_op == NVS_OP_ENCODE) {
2568		nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
2569		/*
2570		 * Add 4 zero bytes at end of nvlist. They are used
2571		 * for end detection by the decode routine.
2572		 */
2573		if (native->n_curr + sizeof (int) > native->n_end)
2574			return (EFAULT);
2575
2576		bzero(native->n_curr, sizeof (int));
2577		native->n_curr += sizeof (int);
2578	}
2579
2580	return (0);
2581}
2582
2583static int
2584nvpair_native_embedded(nvstream_t *nvs, nvpair_t *nvp)
2585{
2586	if (nvs->nvs_op == NVS_OP_ENCODE) {
2587		nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
2588		char *packed = (void *)
2589		    (native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp));
2590		/*
2591		 * Null out the pointer that is meaningless in the packed
2592		 * structure. The address may not be aligned, so we have
2593		 * to use bzero.
2594		 */
2595		bzero(packed + offsetof(nvlist_t, nvl_priv),
2596		    sizeof(((nvlist_t *)NULL)->nvl_priv));
2597	}
2598
2599	return (nvs_embedded(nvs, EMBEDDED_NVL(nvp)));
2600}
2601
2602static int
2603nvpair_native_embedded_array(nvstream_t *nvs, nvpair_t *nvp)
2604{
2605	if (nvs->nvs_op == NVS_OP_ENCODE) {
2606		nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
2607		char *value = native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp);
2608		size_t len = NVP_NELEM(nvp) * sizeof (uint64_t);
2609		int i;
2610		/*
2611		 * Null out pointers that are meaningless in the packed
2612		 * structure. The addresses may not be aligned, so we have
2613		 * to use bzero.
2614		 */
2615		bzero(value, len);
2616
2617		value += len;
2618		for (i = 0; i < NVP_NELEM(nvp); i++) {
2619			/*
2620			 * Null out the pointer that is meaningless in the
2621			 * packed structure. The address may not be aligned,
2622			 * so we have to use bzero.
2623			 */
2624			bzero(value + offsetof(nvlist_t, nvl_priv),
2625			    sizeof(((nvlist_t *)NULL)->nvl_priv));
2626			value += sizeof(nvlist_t);
2627		}
2628	}
2629
2630	return (nvs_embedded_nvl_array(nvs, nvp, NULL));
2631}
2632
2633static void
2634nvpair_native_string_array(nvstream_t *nvs, nvpair_t *nvp)
2635{
2636	switch (nvs->nvs_op) {
2637	case NVS_OP_ENCODE: {
2638		nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
2639		uint64_t *strp = (void *)
2640		    (native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp));
2641		/*
2642		 * Null out pointers that are meaningless in the packed
2643		 * structure. The addresses may not be aligned, so we have
2644		 * to use bzero.
2645		 */
2646		bzero(strp, NVP_NELEM(nvp) * sizeof (uint64_t));
2647		break;
2648	}
2649	case NVS_OP_DECODE: {
2650		char **strp = (void *)NVP_VALUE(nvp);
2651		char *buf = ((char *)strp + NVP_NELEM(nvp) * sizeof (uint64_t));
2652		int i;
2653
2654		for (i = 0; i < NVP_NELEM(nvp); i++) {
2655			strp[i] = buf;
2656			buf += strlen(buf) + 1;
2657		}
2658		break;
2659	}
2660	}
2661}
2662
2663static int
2664nvs_native_nvp_op(nvstream_t *nvs, nvpair_t *nvp)
2665{
2666	data_type_t type;
2667	int value_sz;
2668	int ret = 0;
2669
2670	/*
2671	 * We do the initial bcopy of the data before we look at
2672	 * the nvpair type, because when we're decoding, we won't
2673	 * have the correct values for the pair until we do the bcopy.
2674	 */
2675	switch (nvs->nvs_op) {
2676	case NVS_OP_ENCODE:
2677	case NVS_OP_DECODE:
2678		if (native_cp(nvs, nvp, nvp->nvp_size) != 0)
2679			return (EFAULT);
2680		break;
2681	default:
2682		return (EINVAL);
2683	}
2684
2685	/* verify nvp_name_sz, check the name string length */
2686	if (i_validate_nvpair_name(nvp) != 0)
2687		return (EFAULT);
2688
2689	type = NVP_TYPE(nvp);
2690
2691	/*
2692	 * Verify type and nelem and get the value size.
2693	 * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY
2694	 * is the size of the string(s) excluded.
2695	 */
2696	if ((value_sz = i_get_value_size(type, NULL, NVP_NELEM(nvp))) < 0)
2697		return (EFAULT);
2698
2699	if (NVP_SIZE_CALC(nvp->nvp_name_sz, value_sz) > nvp->nvp_size)
2700		return (EFAULT);
2701
2702	switch (type) {
2703	case DATA_TYPE_NVLIST:
2704		ret = nvpair_native_embedded(nvs, nvp);
2705		break;
2706	case DATA_TYPE_NVLIST_ARRAY:
2707		ret = nvpair_native_embedded_array(nvs, nvp);
2708		break;
2709	case DATA_TYPE_STRING_ARRAY:
2710		nvpair_native_string_array(nvs, nvp);
2711		break;
2712	default:
2713		break;
2714	}
2715
2716	return (ret);
2717}
2718
2719static int
2720nvs_native_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
2721{
2722	uint64_t nvp_sz = nvp->nvp_size;
2723
2724	switch (NVP_TYPE(nvp)) {
2725	case DATA_TYPE_NVLIST: {
2726		size_t nvsize = 0;
2727
2728		if (nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize) != 0)
2729			return (EINVAL);
2730
2731		nvp_sz += nvsize;
2732		break;
2733	}
2734	case DATA_TYPE_NVLIST_ARRAY: {
2735		size_t nvsize;
2736
2737		if (nvs_embedded_nvl_array(nvs, nvp, &nvsize) != 0)
2738			return (EINVAL);
2739
2740		nvp_sz += nvsize;
2741		break;
2742	}
2743	default:
2744		break;
2745	}
2746
2747	if (nvp_sz > INT32_MAX)
2748		return (EINVAL);
2749
2750	*size = nvp_sz;
2751
2752	return (0);
2753}
2754
2755static int
2756nvs_native_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
2757{
2758	switch (nvs->nvs_op) {
2759	case NVS_OP_ENCODE:
2760		return (nvs_native_nvp_op(nvs, nvp));
2761
2762	case NVS_OP_DECODE: {
2763		nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
2764		int32_t decode_len;
2765
2766		/* try to read the size value from the stream */
2767		if (native->n_curr + sizeof (int32_t) > native->n_end)
2768			return (EFAULT);
2769		bcopy(native->n_curr, &decode_len, sizeof (int32_t));
2770
2771		/* sanity check the size value */
2772		if (decode_len < 0 ||
2773		    decode_len > native->n_end - native->n_curr)
2774			return (EFAULT);
2775
2776		*size = decode_len;
2777
2778		/*
2779		 * If at the end of the stream then move the cursor
2780		 * forward, otherwise nvpair_native_op() will read
2781		 * the entire nvpair at the same cursor position.
2782		 */
2783		if (*size == 0)
2784			native->n_curr += sizeof (int32_t);
2785		break;
2786	}
2787
2788	default:
2789		return (EINVAL);
2790	}
2791
2792	return (0);
2793}
2794
2795static const nvs_ops_t nvs_native_ops = {
2796	nvs_native_nvlist,
2797	nvs_native_nvpair,
2798	nvs_native_nvp_op,
2799	nvs_native_nvp_size,
2800	nvs_native_nvl_fini
2801};
2802
2803static int
2804nvs_native(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen)
2805{
2806	nvs_native_t native;
2807	int err;
2808
2809	nvs->nvs_ops = &nvs_native_ops;
2810
2811	if ((err = nvs_native_create(nvs, &native, buf + sizeof (nvs_header_t),
2812	    *buflen - sizeof (nvs_header_t))) != 0)
2813		return (err);
2814
2815	err = nvs_operation(nvs, nvl, buflen);
2816
2817	nvs_native_destroy(nvs);
2818
2819	return (err);
2820}
2821
2822/*
2823 * XDR encoding functions
2824 *
2825 * An xdr packed nvlist is encoded as:
2826 *
2827 *  - encoding methode and host endian (4 bytes)
2828 *  - nvl_version (4 bytes)
2829 *  - nvl_nvflag (4 bytes)
2830 *
2831 *  - encoded nvpairs, the format of one xdr encoded nvpair is:
2832 *	- encoded size of the nvpair (4 bytes)
2833 *	- decoded size of the nvpair (4 bytes)
2834 *	- name string, (4 + sizeof(NV_ALIGN4(string))
2835 *	  a string is coded as size (4 bytes) and data
2836 *	- data type (4 bytes)
2837 *	- number of elements in the nvpair (4 bytes)
2838 *	- data
2839 *
2840 *  - 2 zero's for end of the entire list (8 bytes)
2841 */
2842static int
2843nvs_xdr_create(nvstream_t *nvs, XDR *xdr, char *buf, size_t buflen)
2844{
2845	/* xdr data must be 4 byte aligned */
2846	if ((ulong_t)buf % 4 != 0)
2847		return (EFAULT);
2848
2849	switch (nvs->nvs_op) {
2850	case NVS_OP_ENCODE:
2851		xdrmem_create(xdr, buf, (uint_t)buflen, XDR_ENCODE);
2852		nvs->nvs_private = xdr;
2853		return (0);
2854	case NVS_OP_DECODE:
2855		xdrmem_create(xdr, buf, (uint_t)buflen, XDR_DECODE);
2856		nvs->nvs_private = xdr;
2857		return (0);
2858	case NVS_OP_GETSIZE:
2859		nvs->nvs_private = NULL;
2860		return (0);
2861	default:
2862		return (EINVAL);
2863	}
2864}
2865
2866static void
2867nvs_xdr_destroy(nvstream_t *nvs)
2868{
2869	switch (nvs->nvs_op) {
2870	case NVS_OP_ENCODE:
2871	case NVS_OP_DECODE:
2872		xdr_destroy((XDR *)nvs->nvs_private);
2873		break;
2874	default:
2875		break;
2876	}
2877}
2878
2879static int
2880nvs_xdr_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size)
2881{
2882	switch (nvs->nvs_op) {
2883	case NVS_OP_ENCODE:
2884	case NVS_OP_DECODE: {
2885		XDR 	*xdr = nvs->nvs_private;
2886
2887		if (!xdr_int(xdr, &nvl->nvl_version) ||
2888		    !xdr_u_int(xdr, &nvl->nvl_nvflag))
2889			return (EFAULT);
2890		break;
2891	}
2892	case NVS_OP_GETSIZE: {
2893		/*
2894		 * 2 * 4 for nvl_version + nvl_nvflag
2895		 * and 8 for end of the entire list
2896		 */
2897		*size += 2 * 4 + 8;
2898		break;
2899	}
2900	default:
2901		return (EINVAL);
2902	}
2903	return (0);
2904}
2905
2906static int
2907nvs_xdr_nvl_fini(nvstream_t *nvs)
2908{
2909	if (nvs->nvs_op == NVS_OP_ENCODE) {
2910		XDR *xdr = nvs->nvs_private;
2911		int zero = 0;
2912
2913		if (!xdr_int(xdr, &zero) || !xdr_int(xdr, &zero))
2914			return (EFAULT);
2915	}
2916
2917	return (0);
2918}
2919
2920/*
2921 * The format of xdr encoded nvpair is:
2922 * encode_size, decode_size, name string, data type, nelem, data
2923 */
2924static int
2925nvs_xdr_nvp_op(nvstream_t *nvs, nvpair_t *nvp)
2926{
2927	data_type_t type;
2928	char	*buf;
2929	char	*buf_end = (char *)nvp + nvp->nvp_size;
2930	int	value_sz;
2931	uint_t	nelem, buflen;
2932	bool_t	ret = FALSE;
2933	XDR	*xdr = nvs->nvs_private;
2934
2935	ASSERT(xdr != NULL && nvp != NULL);
2936
2937	/* name string */
2938	if ((buf = NVP_NAME(nvp)) >= buf_end)
2939		return (EFAULT);
2940	buflen = buf_end - buf;
2941
2942	if (!xdr_string(xdr, &buf, buflen - 1))
2943		return (EFAULT);
2944	nvp->nvp_name_sz = strlen(buf) + 1;
2945
2946	/* type and nelem */
2947	if (!xdr_int(xdr, (int *)&nvp->nvp_type) ||
2948	    !xdr_int(xdr, &nvp->nvp_value_elem))
2949		return (EFAULT);
2950
2951	type = NVP_TYPE(nvp);
2952	nelem = nvp->nvp_value_elem;
2953
2954	/*
2955	 * Verify type and nelem and get the value size.
2956	 * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY
2957	 * is the size of the string(s) excluded.
2958	 */
2959	if ((value_sz = i_get_value_size(type, NULL, nelem)) < 0)
2960		return (EFAULT);
2961
2962	/* if there is no data to extract then return */
2963	if (nelem == 0)
2964		return (0);
2965
2966	/* value */
2967	if ((buf = NVP_VALUE(nvp)) >= buf_end)
2968		return (EFAULT);
2969	buflen = buf_end - buf;
2970
2971	if (buflen < value_sz)
2972		return (EFAULT);
2973
2974	switch (type) {
2975	case DATA_TYPE_NVLIST:
2976		if (nvs_embedded(nvs, (void *)buf) == 0)
2977			return (0);
2978		break;
2979
2980	case DATA_TYPE_NVLIST_ARRAY:
2981		if (nvs_embedded_nvl_array(nvs, nvp, NULL) == 0)
2982			return (0);
2983		break;
2984
2985	case DATA_TYPE_BOOLEAN:
2986		ret = TRUE;
2987		break;
2988
2989	case DATA_TYPE_BYTE:
2990	case DATA_TYPE_INT8:
2991	case DATA_TYPE_UINT8:
2992		ret = xdr_char(xdr, buf);
2993		break;
2994
2995	case DATA_TYPE_INT16:
2996		ret = xdr_short(xdr, (void *)buf);
2997		break;
2998
2999	case DATA_TYPE_UINT16:
3000		ret = xdr_u_short(xdr, (void *)buf);
3001		break;
3002
3003	case DATA_TYPE_BOOLEAN_VALUE:
3004	case DATA_TYPE_INT32:
3005		ret = xdr_int(xdr, (void *)buf);
3006		break;
3007
3008	case DATA_TYPE_UINT32:
3009		ret = xdr_u_int(xdr, (void *)buf);
3010		break;
3011
3012	case DATA_TYPE_INT64:
3013		ret = xdr_longlong_t(xdr, (void *)buf);
3014		break;
3015
3016	case DATA_TYPE_UINT64:
3017		ret = xdr_u_longlong_t(xdr, (void *)buf);
3018		break;
3019
3020	case DATA_TYPE_HRTIME:
3021		/*
3022		 * NOTE: must expose the definition of hrtime_t here
3023		 */
3024		ret = xdr_longlong_t(xdr, (void *)buf);
3025		break;
3026#if !defined(_KERNEL)
3027	case DATA_TYPE_DOUBLE:
3028		ret = xdr_double(xdr, (void *)buf);
3029		break;
3030#endif
3031	case DATA_TYPE_STRING:
3032		ret = xdr_string(xdr, &buf, buflen - 1);
3033		break;
3034
3035	case DATA_TYPE_BYTE_ARRAY:
3036		ret = xdr_opaque(xdr, buf, nelem);
3037		break;
3038
3039	case DATA_TYPE_INT8_ARRAY:
3040	case DATA_TYPE_UINT8_ARRAY:
3041		ret = xdr_array(xdr, &buf, &nelem, buflen, sizeof (int8_t),
3042		    (xdrproc_t)xdr_char);
3043		break;
3044
3045	case DATA_TYPE_INT16_ARRAY:
3046		ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int16_t),
3047		    sizeof (int16_t), (xdrproc_t)xdr_short);
3048		break;
3049
3050	case DATA_TYPE_UINT16_ARRAY:
3051		ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint16_t),
3052		    sizeof (uint16_t), (xdrproc_t)xdr_u_short);
3053		break;
3054
3055	case DATA_TYPE_BOOLEAN_ARRAY:
3056	case DATA_TYPE_INT32_ARRAY:
3057		ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int32_t),
3058		    sizeof (int32_t), (xdrproc_t)xdr_int);
3059		break;
3060
3061	case DATA_TYPE_UINT32_ARRAY:
3062		ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint32_t),
3063		    sizeof (uint32_t), (xdrproc_t)xdr_u_int);
3064		break;
3065
3066	case DATA_TYPE_INT64_ARRAY:
3067		ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int64_t),
3068		    sizeof (int64_t), (xdrproc_t)xdr_longlong_t);
3069		break;
3070
3071	case DATA_TYPE_UINT64_ARRAY:
3072		ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint64_t),
3073		    sizeof (uint64_t), (xdrproc_t)xdr_u_longlong_t);
3074		break;
3075
3076	case DATA_TYPE_STRING_ARRAY: {
3077		size_t len = nelem * sizeof (uint64_t);
3078		char **strp = (void *)buf;
3079		int i;
3080
3081		if (nvs->nvs_op == NVS_OP_DECODE)
3082			bzero(buf, len);	/* don't trust packed data */
3083
3084		for (i = 0; i < nelem; i++) {
3085			if (buflen <= len)
3086				return (EFAULT);
3087
3088			buf += len;
3089			buflen -= len;
3090
3091			if (xdr_string(xdr, &buf, buflen - 1) != TRUE)
3092				return (EFAULT);
3093
3094			if (nvs->nvs_op == NVS_OP_DECODE)
3095				strp[i] = buf;
3096			len = strlen(buf) + 1;
3097		}
3098		ret = TRUE;
3099		break;
3100	}
3101	default:
3102		break;
3103	}
3104
3105	return (ret == TRUE ? 0 : EFAULT);
3106}
3107
3108static int
3109nvs_xdr_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
3110{
3111	data_type_t type = NVP_TYPE(nvp);
3112	/*
3113	 * encode_size + decode_size + name string size + data type + nelem
3114	 * where name string size = 4 + NV_ALIGN4(strlen(NVP_NAME(nvp)))
3115	 */
3116	uint64_t nvp_sz = 4 + 4 + 4 + NV_ALIGN4(strlen(NVP_NAME(nvp))) + 4 + 4;
3117
3118	switch (type) {
3119	case DATA_TYPE_BOOLEAN:
3120		break;
3121
3122	case DATA_TYPE_BOOLEAN_VALUE:
3123	case DATA_TYPE_BYTE:
3124	case DATA_TYPE_INT8:
3125	case DATA_TYPE_UINT8:
3126	case DATA_TYPE_INT16:
3127	case DATA_TYPE_UINT16:
3128	case DATA_TYPE_INT32:
3129	case DATA_TYPE_UINT32:
3130		nvp_sz += 4;	/* 4 is the minimum xdr unit */
3131		break;
3132
3133	case DATA_TYPE_INT64:
3134	case DATA_TYPE_UINT64:
3135	case DATA_TYPE_HRTIME:
3136#if !defined(_KERNEL)
3137	case DATA_TYPE_DOUBLE:
3138#endif
3139		nvp_sz += 8;
3140		break;
3141
3142	case DATA_TYPE_STRING:
3143		nvp_sz += 4 + NV_ALIGN4(strlen((char *)NVP_VALUE(nvp)));
3144		break;
3145
3146	case DATA_TYPE_BYTE_ARRAY:
3147		nvp_sz += NV_ALIGN4(NVP_NELEM(nvp));
3148		break;
3149
3150	case DATA_TYPE_BOOLEAN_ARRAY:
3151	case DATA_TYPE_INT8_ARRAY:
3152	case DATA_TYPE_UINT8_ARRAY:
3153	case DATA_TYPE_INT16_ARRAY:
3154	case DATA_TYPE_UINT16_ARRAY:
3155	case DATA_TYPE_INT32_ARRAY:
3156	case DATA_TYPE_UINT32_ARRAY:
3157		nvp_sz += 4 + 4 * (uint64_t)NVP_NELEM(nvp);
3158		break;
3159
3160	case DATA_TYPE_INT64_ARRAY:
3161	case DATA_TYPE_UINT64_ARRAY:
3162		nvp_sz += 4 + 8 * (uint64_t)NVP_NELEM(nvp);
3163		break;
3164
3165	case DATA_TYPE_STRING_ARRAY: {
3166		int i;
3167		char **strs = (void *)NVP_VALUE(nvp);
3168
3169		for (i = 0; i < NVP_NELEM(nvp); i++)
3170			nvp_sz += 4 + NV_ALIGN4(strlen(strs[i]));
3171
3172		break;
3173	}
3174
3175	case DATA_TYPE_NVLIST:
3176	case DATA_TYPE_NVLIST_ARRAY: {
3177		size_t nvsize = 0;
3178		int old_nvs_op = nvs->nvs_op;
3179		int err;
3180
3181		nvs->nvs_op = NVS_OP_GETSIZE;
3182		if (type == DATA_TYPE_NVLIST)
3183			err = nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize);
3184		else
3185			err = nvs_embedded_nvl_array(nvs, nvp, &nvsize);
3186		nvs->nvs_op = old_nvs_op;
3187
3188		if (err != 0)
3189			return (EINVAL);
3190
3191		nvp_sz += nvsize;
3192		break;
3193	}
3194
3195	default:
3196		return (EINVAL);
3197	}
3198
3199	if (nvp_sz > INT32_MAX)
3200		return (EINVAL);
3201
3202	*size = nvp_sz;
3203
3204	return (0);
3205}
3206
3207
3208/*
3209 * The NVS_XDR_MAX_LEN macro takes a packed xdr buffer of size x and estimates
3210 * the largest nvpair that could be encoded in the buffer.
3211 *
3212 * See comments above nvpair_xdr_op() for the format of xdr encoding.
3213 * The size of a xdr packed nvpair without any data is 5 words.
3214 *
3215 * Using the size of the data directly as an estimate would be ok
3216 * in all cases except one.  If the data type is of DATA_TYPE_STRING_ARRAY
3217 * then the actual nvpair has space for an array of pointers to index
3218 * the strings.  These pointers are not encoded into the packed xdr buffer.
3219 *
3220 * If the data is of type DATA_TYPE_STRING_ARRAY and all the strings are
3221 * of length 0, then each string is endcoded in xdr format as a single word.
3222 * Therefore when expanded to an nvpair there will be 2.25 word used for
3223 * each string.  (a int64_t allocated for pointer usage, and a single char
3224 * for the null termination.)
3225 *
3226 * This is the calculation performed by the NVS_XDR_MAX_LEN macro.
3227 */
3228#define	NVS_XDR_HDR_LEN		((size_t)(5 * 4))
3229#define	NVS_XDR_DATA_LEN(y)	(((size_t)(y) <= NVS_XDR_HDR_LEN) ? \
3230					0 : ((size_t)(y) - NVS_XDR_HDR_LEN))
3231#define	NVS_XDR_MAX_LEN(x)	(NVP_SIZE_CALC(1, 0) + \
3232					(NVS_XDR_DATA_LEN(x) * 2) + \
3233					NV_ALIGN4((NVS_XDR_DATA_LEN(x) / 4)))
3234
3235static int
3236nvs_xdr_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
3237{
3238	XDR 	*xdr = nvs->nvs_private;
3239	int32_t	encode_len, decode_len;
3240
3241	switch (nvs->nvs_op) {
3242	case NVS_OP_ENCODE: {
3243		size_t nvsize;
3244
3245		if (nvs_xdr_nvp_size(nvs, nvp, &nvsize) != 0)
3246			return (EFAULT);
3247
3248		decode_len = nvp->nvp_size;
3249		encode_len = nvsize;
3250		if (!xdr_int(xdr, &encode_len) || !xdr_int(xdr, &decode_len))
3251			return (EFAULT);
3252
3253		return (nvs_xdr_nvp_op(nvs, nvp));
3254	}
3255	case NVS_OP_DECODE: {
3256		struct xdr_bytesrec bytesrec;
3257
3258		/* get the encode and decode size */
3259		if (!xdr_int(xdr, &encode_len) || !xdr_int(xdr, &decode_len))
3260			return (EFAULT);
3261		*size = decode_len;
3262
3263		/* are we at the end of the stream? */
3264		if (*size == 0)
3265			return (0);
3266
3267		/* sanity check the size parameter */
3268		if (!xdr_control(xdr, XDR_GET_BYTES_AVAIL, &bytesrec))
3269			return (EFAULT);
3270
3271		if (*size > NVS_XDR_MAX_LEN(bytesrec.xc_num_avail))
3272			return (EFAULT);
3273		break;
3274	}
3275
3276	default:
3277		return (EINVAL);
3278	}
3279	return (0);
3280}
3281
3282static const struct nvs_ops nvs_xdr_ops = {
3283	nvs_xdr_nvlist,
3284	nvs_xdr_nvpair,
3285	nvs_xdr_nvp_op,
3286	nvs_xdr_nvp_size,
3287	nvs_xdr_nvl_fini
3288};
3289
3290static int
3291nvs_xdr(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen)
3292{
3293	XDR xdr;
3294	int err;
3295
3296	nvs->nvs_ops = &nvs_xdr_ops;
3297
3298	if ((err = nvs_xdr_create(nvs, &xdr, buf + sizeof (nvs_header_t),
3299	    *buflen - sizeof (nvs_header_t))) != 0)
3300		return (err);
3301
3302	err = nvs_operation(nvs, nvl, buflen);
3303
3304	nvs_xdr_destroy(nvs);
3305
3306	return (err);
3307}
3308