opensolaris_nvpair.c revision 297115
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	/* step through components of name */
1633	for (np = name; np && *np; np = sepp) {
1634		/* ensure unique names */
1635		if (!(nvl->nvl_nvflag & NV_UNIQUE_NAME))
1636			return (ENOTSUP);
1637
1638		/* skip white space */
1639		skip_whitespace(np);
1640		if (*np == 0)
1641			break;
1642
1643		/* set 'sepp' to end of current component 'np' */
1644		if (sep)
1645			sepp = strchr(np, sep);
1646		else
1647			sepp = NULL;
1648
1649		/* find start of next "[ index ]..." */
1650		idxp = strchr(np, '[');
1651
1652		/* if sepp comes first, set idxp to NULL */
1653		if (sepp && idxp && (sepp < idxp))
1654			idxp = NULL;
1655
1656		/*
1657		 * At this point 'idxp' is set if there is an index
1658		 * expected for the current component.
1659		 */
1660		if (idxp) {
1661			/* set 'n' to length of current 'np' name component */
1662			n = idxp++ - np;
1663
1664			/* keep sepp up to date for *ep use as we advance */
1665			skip_whitespace(idxp);
1666			sepp = idxp;
1667
1668			/* determine the index value */
1669#if defined(_KERNEL) && !defined(_BOOT)
1670			if (ddi_strtol(idxp, &idxep, 0, &idx))
1671				goto fail;
1672#else
1673			idx = strtol(idxp, &idxep, 0);
1674#endif
1675			if (idxep == idxp)
1676				goto fail;
1677
1678			/* keep sepp up to date for *ep use as we advance */
1679			sepp = idxep;
1680
1681			/* skip white space index value and check for ']' */
1682			skip_whitespace(sepp);
1683			if (*sepp++ != ']')
1684				goto fail;
1685
1686			/* for embedded arrays, support C syntax: "a[1].b" */
1687			skip_whitespace(sepp);
1688			if (sep && (*sepp == sep))
1689				sepp++;
1690		} else if (sepp) {
1691			n = sepp++ - np;
1692		} else {
1693			n = strlen(np);
1694		}
1695
1696		/* trim trailing whitespace by reducing length of 'np' */
1697		if (n == 0)
1698			goto fail;
1699		for (n--; (np[n] == ' ') || (np[n] == '\t'); n--)
1700			;
1701		n++;
1702
1703		/* skip whitespace, and set sepp to NULL if complete */
1704		if (sepp) {
1705			skip_whitespace(sepp);
1706			if (*sepp == 0)
1707				sepp = NULL;
1708		}
1709
1710		/*
1711		 * At this point:
1712		 * o  'n' is the length of current 'np' component.
1713		 * o  'idxp' is set if there was an index, and value 'idx'.
1714		 * o  'sepp' is set to the beginning of the next component,
1715		 *    and set to NULL if we have no more components.
1716		 *
1717		 * Search for nvpair with matching component name.
1718		 */
1719		for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
1720		    nvp = nvlist_next_nvpair(nvl, nvp)) {
1721
1722			/* continue if no match on name */
1723			if (strncmp(np, nvpair_name(nvp), n) ||
1724			    (strlen(nvpair_name(nvp)) != n))
1725				continue;
1726
1727			/* if indexed, verify type is array oriented */
1728			if (idxp && !nvpair_type_is_array(nvp))
1729				goto fail;
1730
1731			/*
1732			 * Full match found, return nvp and idx if this
1733			 * was the last component.
1734			 */
1735			if (sepp == NULL) {
1736				if (ret)
1737					*ret = nvp;
1738				if (ip && idxp)
1739					*ip = (int)idx;	/* return index */
1740				return (0);		/* found */
1741			}
1742
1743			/*
1744			 * More components: current match must be
1745			 * of DATA_TYPE_NVLIST or DATA_TYPE_NVLIST_ARRAY
1746			 * to support going deeper.
1747			 */
1748			if (nvpair_type(nvp) == DATA_TYPE_NVLIST) {
1749				nvl = EMBEDDED_NVL(nvp);
1750				break;
1751			} else if (nvpair_type(nvp) == DATA_TYPE_NVLIST_ARRAY) {
1752				(void) nvpair_value_nvlist_array(nvp,
1753				    &nva, (uint_t *)&n);
1754				if ((n < 0) || (idx >= n))
1755					goto fail;
1756				nvl = nva[idx];
1757				break;
1758			}
1759
1760			/* type does not support more levels */
1761			goto fail;
1762		}
1763		if (nvp == NULL)
1764			goto fail;		/* 'name' not found */
1765
1766		/* search for match of next component in embedded 'nvl' list */
1767	}
1768
1769fail:	if (ep && sepp)
1770		*ep = sepp;
1771	return (EINVAL);
1772}
1773
1774/*
1775 * Return pointer to nvpair with specified 'name'.
1776 */
1777int
1778nvlist_lookup_nvpair(nvlist_t *nvl, const char *name, nvpair_t **ret)
1779{
1780	return (nvlist_lookup_nvpair_ei_sep(nvl, name, 0, ret, NULL, NULL));
1781}
1782
1783/*
1784 * Determine if named nvpair exists in nvlist (use embedded separator of '.'
1785 * and return array index).  See nvlist_lookup_nvpair_ei_sep for more detailed
1786 * description.
1787 */
1788int nvlist_lookup_nvpair_embedded_index(nvlist_t *nvl,
1789    const char *name, nvpair_t **ret, int *ip, char **ep)
1790{
1791	return (nvlist_lookup_nvpair_ei_sep(nvl, name, '.', ret, ip, ep));
1792}
1793
1794boolean_t
1795nvlist_exists(nvlist_t *nvl, const char *name)
1796{
1797	nvpriv_t *priv;
1798	nvpair_t *nvp;
1799	i_nvp_t *curr;
1800
1801	if (name == NULL || nvl == NULL ||
1802	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
1803		return (B_FALSE);
1804
1805	for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
1806		nvp = &curr->nvi_nvp;
1807
1808		if (strcmp(name, NVP_NAME(nvp)) == 0)
1809			return (B_TRUE);
1810	}
1811
1812	return (B_FALSE);
1813}
1814
1815int
1816nvpair_value_boolean_value(nvpair_t *nvp, boolean_t *val)
1817{
1818	return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_VALUE, NULL, val));
1819}
1820
1821int
1822nvpair_value_byte(nvpair_t *nvp, uchar_t *val)
1823{
1824	return (nvpair_value_common(nvp, DATA_TYPE_BYTE, NULL, val));
1825}
1826
1827int
1828nvpair_value_int8(nvpair_t *nvp, int8_t *val)
1829{
1830	return (nvpair_value_common(nvp, DATA_TYPE_INT8, NULL, val));
1831}
1832
1833int
1834nvpair_value_uint8(nvpair_t *nvp, uint8_t *val)
1835{
1836	return (nvpair_value_common(nvp, DATA_TYPE_UINT8, NULL, val));
1837}
1838
1839int
1840nvpair_value_int16(nvpair_t *nvp, int16_t *val)
1841{
1842	return (nvpair_value_common(nvp, DATA_TYPE_INT16, NULL, val));
1843}
1844
1845int
1846nvpair_value_uint16(nvpair_t *nvp, uint16_t *val)
1847{
1848	return (nvpair_value_common(nvp, DATA_TYPE_UINT16, NULL, val));
1849}
1850
1851int
1852nvpair_value_int32(nvpair_t *nvp, int32_t *val)
1853{
1854	return (nvpair_value_common(nvp, DATA_TYPE_INT32, NULL, val));
1855}
1856
1857int
1858nvpair_value_uint32(nvpair_t *nvp, uint32_t *val)
1859{
1860	return (nvpair_value_common(nvp, DATA_TYPE_UINT32, NULL, val));
1861}
1862
1863int
1864nvpair_value_int64(nvpair_t *nvp, int64_t *val)
1865{
1866	return (nvpair_value_common(nvp, DATA_TYPE_INT64, NULL, val));
1867}
1868
1869int
1870nvpair_value_uint64(nvpair_t *nvp, uint64_t *val)
1871{
1872	return (nvpair_value_common(nvp, DATA_TYPE_UINT64, NULL, val));
1873}
1874
1875#if !defined(_KERNEL)
1876int
1877nvpair_value_double(nvpair_t *nvp, double *val)
1878{
1879	return (nvpair_value_common(nvp, DATA_TYPE_DOUBLE, NULL, val));
1880}
1881#endif
1882
1883int
1884nvpair_value_string(nvpair_t *nvp, char **val)
1885{
1886	return (nvpair_value_common(nvp, DATA_TYPE_STRING, NULL, val));
1887}
1888
1889int
1890nvpair_value_nvlist(nvpair_t *nvp, nvlist_t **val)
1891{
1892	return (nvpair_value_common(nvp, DATA_TYPE_NVLIST, NULL, val));
1893}
1894
1895int
1896nvpair_value_boolean_array(nvpair_t *nvp, boolean_t **val, uint_t *nelem)
1897{
1898	return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_ARRAY, nelem, val));
1899}
1900
1901int
1902nvpair_value_byte_array(nvpair_t *nvp, uchar_t **val, uint_t *nelem)
1903{
1904	return (nvpair_value_common(nvp, DATA_TYPE_BYTE_ARRAY, nelem, val));
1905}
1906
1907int
1908nvpair_value_int8_array(nvpair_t *nvp, int8_t **val, uint_t *nelem)
1909{
1910	return (nvpair_value_common(nvp, DATA_TYPE_INT8_ARRAY, nelem, val));
1911}
1912
1913int
1914nvpair_value_uint8_array(nvpair_t *nvp, uint8_t **val, uint_t *nelem)
1915{
1916	return (nvpair_value_common(nvp, DATA_TYPE_UINT8_ARRAY, nelem, val));
1917}
1918
1919int
1920nvpair_value_int16_array(nvpair_t *nvp, int16_t **val, uint_t *nelem)
1921{
1922	return (nvpair_value_common(nvp, DATA_TYPE_INT16_ARRAY, nelem, val));
1923}
1924
1925int
1926nvpair_value_uint16_array(nvpair_t *nvp, uint16_t **val, uint_t *nelem)
1927{
1928	return (nvpair_value_common(nvp, DATA_TYPE_UINT16_ARRAY, nelem, val));
1929}
1930
1931int
1932nvpair_value_int32_array(nvpair_t *nvp, int32_t **val, uint_t *nelem)
1933{
1934	return (nvpair_value_common(nvp, DATA_TYPE_INT32_ARRAY, nelem, val));
1935}
1936
1937int
1938nvpair_value_uint32_array(nvpair_t *nvp, uint32_t **val, uint_t *nelem)
1939{
1940	return (nvpair_value_common(nvp, DATA_TYPE_UINT32_ARRAY, nelem, val));
1941}
1942
1943int
1944nvpair_value_int64_array(nvpair_t *nvp, int64_t **val, uint_t *nelem)
1945{
1946	return (nvpair_value_common(nvp, DATA_TYPE_INT64_ARRAY, nelem, val));
1947}
1948
1949int
1950nvpair_value_uint64_array(nvpair_t *nvp, uint64_t **val, uint_t *nelem)
1951{
1952	return (nvpair_value_common(nvp, DATA_TYPE_UINT64_ARRAY, nelem, val));
1953}
1954
1955int
1956nvpair_value_string_array(nvpair_t *nvp, char ***val, uint_t *nelem)
1957{
1958	return (nvpair_value_common(nvp, DATA_TYPE_STRING_ARRAY, nelem, val));
1959}
1960
1961int
1962nvpair_value_nvlist_array(nvpair_t *nvp, nvlist_t ***val, uint_t *nelem)
1963{
1964	return (nvpair_value_common(nvp, DATA_TYPE_NVLIST_ARRAY, nelem, val));
1965}
1966
1967int
1968nvpair_value_hrtime(nvpair_t *nvp, hrtime_t *val)
1969{
1970	return (nvpair_value_common(nvp, DATA_TYPE_HRTIME, NULL, val));
1971}
1972
1973/*
1974 * Add specified pair to the list.
1975 */
1976int
1977nvlist_add_nvpair(nvlist_t *nvl, nvpair_t *nvp)
1978{
1979	if (nvl == NULL || nvp == NULL)
1980		return (EINVAL);
1981
1982	return (nvlist_add_common(nvl, NVP_NAME(nvp), NVP_TYPE(nvp),
1983	    NVP_NELEM(nvp), NVP_VALUE(nvp)));
1984}
1985
1986/*
1987 * Merge the supplied nvlists and put the result in dst.
1988 * The merged list will contain all names specified in both lists,
1989 * the values are taken from nvl in the case of duplicates.
1990 * Return 0 on success.
1991 */
1992/*ARGSUSED*/
1993int
1994nvlist_merge(nvlist_t *dst, nvlist_t *nvl, int flag)
1995{
1996	if (nvl == NULL || dst == NULL)
1997		return (EINVAL);
1998
1999	if (dst != nvl)
2000		return (nvlist_copy_pairs(nvl, dst));
2001
2002	return (0);
2003}
2004
2005/*
2006 * Encoding related routines
2007 */
2008#define	NVS_OP_ENCODE	0
2009#define	NVS_OP_DECODE	1
2010#define	NVS_OP_GETSIZE	2
2011
2012typedef struct nvs_ops nvs_ops_t;
2013
2014typedef struct {
2015	int		nvs_op;
2016	const nvs_ops_t	*nvs_ops;
2017	void		*nvs_private;
2018	nvpriv_t	*nvs_priv;
2019} nvstream_t;
2020
2021/*
2022 * nvs operations are:
2023 *   - nvs_nvlist
2024 *     encoding / decoding of a nvlist header (nvlist_t)
2025 *     calculates the size used for header and end detection
2026 *
2027 *   - nvs_nvpair
2028 *     responsible for the first part of encoding / decoding of an nvpair
2029 *     calculates the decoded size of an nvpair
2030 *
2031 *   - nvs_nvp_op
2032 *     second part of encoding / decoding of an nvpair
2033 *
2034 *   - nvs_nvp_size
2035 *     calculates the encoding size of an nvpair
2036 *
2037 *   - nvs_nvl_fini
2038 *     encodes the end detection mark (zeros).
2039 */
2040struct nvs_ops {
2041	int (*nvs_nvlist)(nvstream_t *, nvlist_t *, size_t *);
2042	int (*nvs_nvpair)(nvstream_t *, nvpair_t *, size_t *);
2043	int (*nvs_nvp_op)(nvstream_t *, nvpair_t *);
2044	int (*nvs_nvp_size)(nvstream_t *, nvpair_t *, size_t *);
2045	int (*nvs_nvl_fini)(nvstream_t *);
2046};
2047
2048typedef struct {
2049	char	nvh_encoding;	/* nvs encoding method */
2050	char	nvh_endian;	/* nvs endian */
2051	char	nvh_reserved1;	/* reserved for future use */
2052	char	nvh_reserved2;	/* reserved for future use */
2053} nvs_header_t;
2054
2055static int
2056nvs_encode_pairs(nvstream_t *nvs, nvlist_t *nvl)
2057{
2058	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
2059	i_nvp_t *curr;
2060
2061	/*
2062	 * Walk nvpair in list and encode each nvpair
2063	 */
2064	for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next)
2065		if (nvs->nvs_ops->nvs_nvpair(nvs, &curr->nvi_nvp, NULL) != 0)
2066			return (EFAULT);
2067
2068	return (nvs->nvs_ops->nvs_nvl_fini(nvs));
2069}
2070
2071static int
2072nvs_decode_pairs(nvstream_t *nvs, nvlist_t *nvl)
2073{
2074	nvpair_t *nvp;
2075	size_t nvsize;
2076	int err;
2077
2078	/*
2079	 * Get decoded size of next pair in stream, alloc
2080	 * memory for nvpair_t, then decode the nvpair
2081	 */
2082	while ((err = nvs->nvs_ops->nvs_nvpair(nvs, NULL, &nvsize)) == 0) {
2083		if (nvsize == 0) /* end of list */
2084			break;
2085
2086		/* make sure len makes sense */
2087		if (nvsize < NVP_SIZE_CALC(1, 0))
2088			return (EFAULT);
2089
2090		if ((nvp = nvp_buf_alloc(nvl, nvsize)) == NULL)
2091			return (ENOMEM);
2092
2093		if ((err = nvs->nvs_ops->nvs_nvp_op(nvs, nvp)) != 0) {
2094			nvp_buf_free(nvl, nvp);
2095			return (err);
2096		}
2097
2098		if (i_validate_nvpair(nvp) != 0) {
2099			nvpair_free(nvp);
2100			nvp_buf_free(nvl, nvp);
2101			return (EFAULT);
2102		}
2103
2104		nvp_buf_link(nvl, nvp);
2105	}
2106	return (err);
2107}
2108
2109static int
2110nvs_getsize_pairs(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen)
2111{
2112	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
2113	i_nvp_t *curr;
2114	uint64_t nvsize = *buflen;
2115	size_t size;
2116
2117	/*
2118	 * Get encoded size of nvpairs in nvlist
2119	 */
2120	for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
2121		if (nvs->nvs_ops->nvs_nvp_size(nvs, &curr->nvi_nvp, &size) != 0)
2122			return (EINVAL);
2123
2124		if ((nvsize += size) > INT32_MAX)
2125			return (EINVAL);
2126	}
2127
2128	*buflen = nvsize;
2129	return (0);
2130}
2131
2132static int
2133nvs_operation(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen)
2134{
2135	int err;
2136
2137	if (nvl->nvl_priv == 0)
2138		return (EFAULT);
2139
2140	/*
2141	 * Perform the operation, starting with header, then each nvpair
2142	 */
2143	if ((err = nvs->nvs_ops->nvs_nvlist(nvs, nvl, buflen)) != 0)
2144		return (err);
2145
2146	switch (nvs->nvs_op) {
2147	case NVS_OP_ENCODE:
2148		err = nvs_encode_pairs(nvs, nvl);
2149		break;
2150
2151	case NVS_OP_DECODE:
2152		err = nvs_decode_pairs(nvs, nvl);
2153		break;
2154
2155	case NVS_OP_GETSIZE:
2156		err = nvs_getsize_pairs(nvs, nvl, buflen);
2157		break;
2158
2159	default:
2160		err = EINVAL;
2161	}
2162
2163	return (err);
2164}
2165
2166static int
2167nvs_embedded(nvstream_t *nvs, nvlist_t *embedded)
2168{
2169	switch (nvs->nvs_op) {
2170	case NVS_OP_ENCODE:
2171		return (nvs_operation(nvs, embedded, NULL));
2172
2173	case NVS_OP_DECODE: {
2174		nvpriv_t *priv;
2175		int err;
2176
2177		if (embedded->nvl_version != NV_VERSION)
2178			return (ENOTSUP);
2179
2180		if ((priv = nv_priv_alloc_embedded(nvs->nvs_priv)) == NULL)
2181			return (ENOMEM);
2182
2183		nvlist_init(embedded, embedded->nvl_nvflag, priv);
2184
2185		if ((err = nvs_operation(nvs, embedded, NULL)) != 0)
2186			nvlist_free(embedded);
2187		return (err);
2188	}
2189	default:
2190		break;
2191	}
2192
2193	return (EINVAL);
2194}
2195
2196static int
2197nvs_embedded_nvl_array(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
2198{
2199	size_t nelem = NVP_NELEM(nvp);
2200	nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);
2201	int i;
2202
2203	switch (nvs->nvs_op) {
2204	case NVS_OP_ENCODE:
2205		for (i = 0; i < nelem; i++)
2206			if (nvs_embedded(nvs, nvlp[i]) != 0)
2207				return (EFAULT);
2208		break;
2209
2210	case NVS_OP_DECODE: {
2211		size_t len = nelem * sizeof (uint64_t);
2212		nvlist_t *embedded = (nvlist_t *)((uintptr_t)nvlp + len);
2213
2214		bzero(nvlp, len);	/* don't trust packed data */
2215		for (i = 0; i < nelem; i++) {
2216			if (nvs_embedded(nvs, embedded) != 0) {
2217				nvpair_free(nvp);
2218				return (EFAULT);
2219			}
2220
2221			nvlp[i] = embedded++;
2222		}
2223		break;
2224	}
2225	case NVS_OP_GETSIZE: {
2226		uint64_t nvsize = 0;
2227
2228		for (i = 0; i < nelem; i++) {
2229			size_t nvp_sz = 0;
2230
2231			if (nvs_operation(nvs, nvlp[i], &nvp_sz) != 0)
2232				return (EINVAL);
2233
2234			if ((nvsize += nvp_sz) > INT32_MAX)
2235				return (EINVAL);
2236		}
2237
2238		*size = nvsize;
2239		break;
2240	}
2241	default:
2242		return (EINVAL);
2243	}
2244
2245	return (0);
2246}
2247
2248static int nvs_native(nvstream_t *, nvlist_t *, char *, size_t *);
2249static int nvs_xdr(nvstream_t *, nvlist_t *, char *, size_t *);
2250
2251/*
2252 * Common routine for nvlist operations:
2253 * encode, decode, getsize (encoded size).
2254 */
2255static int
2256nvlist_common(nvlist_t *nvl, char *buf, size_t *buflen, int encoding,
2257    int nvs_op)
2258{
2259	int err = 0;
2260	nvstream_t nvs;
2261	int nvl_endian;
2262#if BYTE_ORDER == _LITTLE_ENDIAN
2263	int host_endian = 1;
2264#else
2265	int host_endian = 0;
2266#endif	/* _LITTLE_ENDIAN */
2267	nvs_header_t *nvh = (void *)buf;
2268
2269	if (buflen == NULL || nvl == NULL ||
2270	    (nvs.nvs_priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
2271		return (EINVAL);
2272
2273	nvs.nvs_op = nvs_op;
2274
2275	/*
2276	 * For NVS_OP_ENCODE and NVS_OP_DECODE make sure an nvlist and
2277	 * a buffer is allocated.  The first 4 bytes in the buffer are
2278	 * used for encoding method and host endian.
2279	 */
2280	switch (nvs_op) {
2281	case NVS_OP_ENCODE:
2282		if (buf == NULL || *buflen < sizeof (nvs_header_t))
2283			return (EINVAL);
2284
2285		nvh->nvh_encoding = encoding;
2286		nvh->nvh_endian = nvl_endian = host_endian;
2287		nvh->nvh_reserved1 = 0;
2288		nvh->nvh_reserved2 = 0;
2289		break;
2290
2291	case NVS_OP_DECODE:
2292		if (buf == NULL || *buflen < sizeof (nvs_header_t))
2293			return (EINVAL);
2294
2295		/* get method of encoding from first byte */
2296		encoding = nvh->nvh_encoding;
2297		nvl_endian = nvh->nvh_endian;
2298		break;
2299
2300	case NVS_OP_GETSIZE:
2301		nvl_endian = host_endian;
2302
2303		/*
2304		 * add the size for encoding
2305		 */
2306		*buflen = sizeof (nvs_header_t);
2307		break;
2308
2309	default:
2310		return (ENOTSUP);
2311	}
2312
2313	/*
2314	 * Create an nvstream with proper encoding method
2315	 */
2316	switch (encoding) {
2317	case NV_ENCODE_NATIVE:
2318		/*
2319		 * check endianness, in case we are unpacking
2320		 * from a file
2321		 */
2322		if (nvl_endian != host_endian)
2323			return (ENOTSUP);
2324		err = nvs_native(&nvs, nvl, buf, buflen);
2325		break;
2326	case NV_ENCODE_XDR:
2327		err = nvs_xdr(&nvs, nvl, buf, buflen);
2328		break;
2329	default:
2330		err = ENOTSUP;
2331		break;
2332	}
2333
2334	return (err);
2335}
2336
2337int
2338nvlist_size(nvlist_t *nvl, size_t *size, int encoding)
2339{
2340	return (nvlist_common(nvl, NULL, size, encoding, NVS_OP_GETSIZE));
2341}
2342
2343/*
2344 * Pack nvlist into contiguous memory
2345 */
2346/*ARGSUSED1*/
2347int
2348nvlist_pack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding,
2349    int kmflag)
2350{
2351#if defined(_KERNEL) && !defined(_BOOT)
2352	return (nvlist_xpack(nvl, bufp, buflen, encoding,
2353	    (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep)));
2354#else
2355	return (nvlist_xpack(nvl, bufp, buflen, encoding, nv_alloc_nosleep));
2356#endif
2357}
2358
2359int
2360nvlist_xpack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding,
2361    nv_alloc_t *nva)
2362{
2363	nvpriv_t nvpriv;
2364	size_t alloc_size;
2365	char *buf;
2366	int err;
2367
2368	if (nva == NULL || nvl == NULL || bufp == NULL || buflen == NULL)
2369		return (EINVAL);
2370
2371	if (*bufp != NULL)
2372		return (nvlist_common(nvl, *bufp, buflen, encoding,
2373		    NVS_OP_ENCODE));
2374
2375	/*
2376	 * Here is a difficult situation:
2377	 * 1. The nvlist has fixed allocator properties.
2378	 *    All other nvlist routines (like nvlist_add_*, ...) use
2379	 *    these properties.
2380	 * 2. When using nvlist_pack() the user can specify his own
2381	 *    allocator properties (e.g. by using KM_NOSLEEP).
2382	 *
2383	 * We use the user specified properties (2). A clearer solution
2384	 * will be to remove the kmflag from nvlist_pack(), but we will
2385	 * not change the interface.
2386	 */
2387	nv_priv_init(&nvpriv, nva, 0);
2388
2389	if (err = nvlist_size(nvl, &alloc_size, encoding))
2390		return (err);
2391
2392	if ((buf = nv_mem_zalloc(&nvpriv, alloc_size)) == NULL)
2393		return (ENOMEM);
2394
2395	if ((err = nvlist_common(nvl, buf, &alloc_size, encoding,
2396	    NVS_OP_ENCODE)) != 0) {
2397		nv_mem_free(&nvpriv, buf, alloc_size);
2398	} else {
2399		*buflen = alloc_size;
2400		*bufp = buf;
2401	}
2402
2403	return (err);
2404}
2405
2406/*
2407 * Unpack buf into an nvlist_t
2408 */
2409/*ARGSUSED1*/
2410int
2411nvlist_unpack(char *buf, size_t buflen, nvlist_t **nvlp, int kmflag)
2412{
2413#if defined(_KERNEL) && !defined(_BOOT)
2414	return (nvlist_xunpack(buf, buflen, nvlp,
2415	    (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep)));
2416#else
2417	return (nvlist_xunpack(buf, buflen, nvlp, nv_alloc_nosleep));
2418#endif
2419}
2420
2421int
2422nvlist_xunpack(char *buf, size_t buflen, nvlist_t **nvlp, nv_alloc_t *nva)
2423{
2424	nvlist_t *nvl;
2425	int err;
2426
2427	if (nvlp == NULL)
2428		return (EINVAL);
2429
2430	if ((err = nvlist_xalloc(&nvl, 0, nva)) != 0)
2431		return (err);
2432
2433	if ((err = nvlist_common(nvl, buf, &buflen, 0, NVS_OP_DECODE)) != 0)
2434		nvlist_free(nvl);
2435	else
2436		*nvlp = nvl;
2437
2438	return (err);
2439}
2440
2441/*
2442 * Native encoding functions
2443 */
2444typedef struct {
2445	/*
2446	 * This structure is used when decoding a packed nvpair in
2447	 * the native format.  n_base points to a buffer containing the
2448	 * packed nvpair.  n_end is a pointer to the end of the buffer.
2449	 * (n_end actually points to the first byte past the end of the
2450	 * buffer.)  n_curr is a pointer that lies between n_base and n_end.
2451	 * It points to the current data that we are decoding.
2452	 * The amount of data left in the buffer is equal to n_end - n_curr.
2453	 * n_flag is used to recognize a packed embedded list.
2454	 */
2455	caddr_t n_base;
2456	caddr_t n_end;
2457	caddr_t n_curr;
2458	uint_t  n_flag;
2459} nvs_native_t;
2460
2461static int
2462nvs_native_create(nvstream_t *nvs, nvs_native_t *native, char *buf,
2463    size_t buflen)
2464{
2465	switch (nvs->nvs_op) {
2466	case NVS_OP_ENCODE:
2467	case NVS_OP_DECODE:
2468		nvs->nvs_private = native;
2469		native->n_curr = native->n_base = buf;
2470		native->n_end = buf + buflen;
2471		native->n_flag = 0;
2472		return (0);
2473
2474	case NVS_OP_GETSIZE:
2475		nvs->nvs_private = native;
2476		native->n_curr = native->n_base = native->n_end = NULL;
2477		native->n_flag = 0;
2478		return (0);
2479	default:
2480		return (EINVAL);
2481	}
2482}
2483
2484/*ARGSUSED*/
2485static void
2486nvs_native_destroy(nvstream_t *nvs)
2487{
2488}
2489
2490static int
2491native_cp(nvstream_t *nvs, void *buf, size_t size)
2492{
2493	nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
2494
2495	if (native->n_curr + size > native->n_end)
2496		return (EFAULT);
2497
2498	/*
2499	 * The bcopy() below eliminates alignment requirement
2500	 * on the buffer (stream) and is preferred over direct access.
2501	 */
2502	switch (nvs->nvs_op) {
2503	case NVS_OP_ENCODE:
2504		bcopy(buf, native->n_curr, size);
2505		break;
2506	case NVS_OP_DECODE:
2507		bcopy(native->n_curr, buf, size);
2508		break;
2509	default:
2510		return (EINVAL);
2511	}
2512
2513	native->n_curr += size;
2514	return (0);
2515}
2516
2517/*
2518 * operate on nvlist_t header
2519 */
2520static int
2521nvs_native_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size)
2522{
2523	nvs_native_t *native = nvs->nvs_private;
2524
2525	switch (nvs->nvs_op) {
2526	case NVS_OP_ENCODE:
2527	case NVS_OP_DECODE:
2528		if (native->n_flag)
2529			return (0);	/* packed embedded list */
2530
2531		native->n_flag = 1;
2532
2533		/* copy version and nvflag of the nvlist_t */
2534		if (native_cp(nvs, &nvl->nvl_version, sizeof (int32_t)) != 0 ||
2535		    native_cp(nvs, &nvl->nvl_nvflag, sizeof (int32_t)) != 0)
2536			return (EFAULT);
2537
2538		return (0);
2539
2540	case NVS_OP_GETSIZE:
2541		/*
2542		 * if calculate for packed embedded list
2543		 * 	4 for end of the embedded list
2544		 * else
2545		 * 	2 * sizeof (int32_t) for nvl_version and nvl_nvflag
2546		 * 	and 4 for end of the entire list
2547		 */
2548		if (native->n_flag) {
2549			*size += 4;
2550		} else {
2551			native->n_flag = 1;
2552			*size += 2 * sizeof (int32_t) + 4;
2553		}
2554
2555		return (0);
2556
2557	default:
2558		return (EINVAL);
2559	}
2560}
2561
2562static int
2563nvs_native_nvl_fini(nvstream_t *nvs)
2564{
2565	if (nvs->nvs_op == NVS_OP_ENCODE) {
2566		nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
2567		/*
2568		 * Add 4 zero bytes at end of nvlist. They are used
2569		 * for end detection by the decode routine.
2570		 */
2571		if (native->n_curr + sizeof (int) > native->n_end)
2572			return (EFAULT);
2573
2574		bzero(native->n_curr, sizeof (int));
2575		native->n_curr += sizeof (int);
2576	}
2577
2578	return (0);
2579}
2580
2581static int
2582nvpair_native_embedded(nvstream_t *nvs, nvpair_t *nvp)
2583{
2584	if (nvs->nvs_op == NVS_OP_ENCODE) {
2585		nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
2586		char *packed = (void *)
2587		    (native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp));
2588		/*
2589		 * Null out the pointer that is meaningless in the packed
2590		 * structure. The address may not be aligned, so we have
2591		 * to use bzero.
2592		 */
2593		bzero(packed + offsetof(nvlist_t, nvl_priv),
2594		    sizeof(((nvlist_t *)NULL)->nvl_priv));
2595	}
2596
2597	return (nvs_embedded(nvs, EMBEDDED_NVL(nvp)));
2598}
2599
2600static int
2601nvpair_native_embedded_array(nvstream_t *nvs, nvpair_t *nvp)
2602{
2603	if (nvs->nvs_op == NVS_OP_ENCODE) {
2604		nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
2605		char *value = native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp);
2606		size_t len = NVP_NELEM(nvp) * sizeof (uint64_t);
2607		int i;
2608		/*
2609		 * Null out pointers that are meaningless in the packed
2610		 * structure. The addresses may not be aligned, so we have
2611		 * to use bzero.
2612		 */
2613		bzero(value, len);
2614
2615		value += len;
2616		for (i = 0; i < NVP_NELEM(nvp); i++) {
2617			/*
2618			 * Null out the pointer that is meaningless in the
2619			 * packed structure. The address may not be aligned,
2620			 * so we have to use bzero.
2621			 */
2622			bzero(value + offsetof(nvlist_t, nvl_priv),
2623			    sizeof(((nvlist_t *)NULL)->nvl_priv));
2624			value += sizeof(nvlist_t);
2625		}
2626	}
2627
2628	return (nvs_embedded_nvl_array(nvs, nvp, NULL));
2629}
2630
2631static void
2632nvpair_native_string_array(nvstream_t *nvs, nvpair_t *nvp)
2633{
2634	switch (nvs->nvs_op) {
2635	case NVS_OP_ENCODE: {
2636		nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
2637		uint64_t *strp = (void *)
2638		    (native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp));
2639		/*
2640		 * Null out pointers that are meaningless in the packed
2641		 * structure. The addresses may not be aligned, so we have
2642		 * to use bzero.
2643		 */
2644		bzero(strp, NVP_NELEM(nvp) * sizeof (uint64_t));
2645		break;
2646	}
2647	case NVS_OP_DECODE: {
2648		char **strp = (void *)NVP_VALUE(nvp);
2649		char *buf = ((char *)strp + NVP_NELEM(nvp) * sizeof (uint64_t));
2650		int i;
2651
2652		for (i = 0; i < NVP_NELEM(nvp); i++) {
2653			strp[i] = buf;
2654			buf += strlen(buf) + 1;
2655		}
2656		break;
2657	}
2658	}
2659}
2660
2661static int
2662nvs_native_nvp_op(nvstream_t *nvs, nvpair_t *nvp)
2663{
2664	data_type_t type;
2665	int value_sz;
2666	int ret = 0;
2667
2668	/*
2669	 * We do the initial bcopy of the data before we look at
2670	 * the nvpair type, because when we're decoding, we won't
2671	 * have the correct values for the pair until we do the bcopy.
2672	 */
2673	switch (nvs->nvs_op) {
2674	case NVS_OP_ENCODE:
2675	case NVS_OP_DECODE:
2676		if (native_cp(nvs, nvp, nvp->nvp_size) != 0)
2677			return (EFAULT);
2678		break;
2679	default:
2680		return (EINVAL);
2681	}
2682
2683	/* verify nvp_name_sz, check the name string length */
2684	if (i_validate_nvpair_name(nvp) != 0)
2685		return (EFAULT);
2686
2687	type = NVP_TYPE(nvp);
2688
2689	/*
2690	 * Verify type and nelem and get the value size.
2691	 * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY
2692	 * is the size of the string(s) excluded.
2693	 */
2694	if ((value_sz = i_get_value_size(type, NULL, NVP_NELEM(nvp))) < 0)
2695		return (EFAULT);
2696
2697	if (NVP_SIZE_CALC(nvp->nvp_name_sz, value_sz) > nvp->nvp_size)
2698		return (EFAULT);
2699
2700	switch (type) {
2701	case DATA_TYPE_NVLIST:
2702		ret = nvpair_native_embedded(nvs, nvp);
2703		break;
2704	case DATA_TYPE_NVLIST_ARRAY:
2705		ret = nvpair_native_embedded_array(nvs, nvp);
2706		break;
2707	case DATA_TYPE_STRING_ARRAY:
2708		nvpair_native_string_array(nvs, nvp);
2709		break;
2710	default:
2711		break;
2712	}
2713
2714	return (ret);
2715}
2716
2717static int
2718nvs_native_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
2719{
2720	uint64_t nvp_sz = nvp->nvp_size;
2721
2722	switch (NVP_TYPE(nvp)) {
2723	case DATA_TYPE_NVLIST: {
2724		size_t nvsize = 0;
2725
2726		if (nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize) != 0)
2727			return (EINVAL);
2728
2729		nvp_sz += nvsize;
2730		break;
2731	}
2732	case DATA_TYPE_NVLIST_ARRAY: {
2733		size_t nvsize;
2734
2735		if (nvs_embedded_nvl_array(nvs, nvp, &nvsize) != 0)
2736			return (EINVAL);
2737
2738		nvp_sz += nvsize;
2739		break;
2740	}
2741	default:
2742		break;
2743	}
2744
2745	if (nvp_sz > INT32_MAX)
2746		return (EINVAL);
2747
2748	*size = nvp_sz;
2749
2750	return (0);
2751}
2752
2753static int
2754nvs_native_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
2755{
2756	switch (nvs->nvs_op) {
2757	case NVS_OP_ENCODE:
2758		return (nvs_native_nvp_op(nvs, nvp));
2759
2760	case NVS_OP_DECODE: {
2761		nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
2762		int32_t decode_len;
2763
2764		/* try to read the size value from the stream */
2765		if (native->n_curr + sizeof (int32_t) > native->n_end)
2766			return (EFAULT);
2767		bcopy(native->n_curr, &decode_len, sizeof (int32_t));
2768
2769		/* sanity check the size value */
2770		if (decode_len < 0 ||
2771		    decode_len > native->n_end - native->n_curr)
2772			return (EFAULT);
2773
2774		*size = decode_len;
2775
2776		/*
2777		 * If at the end of the stream then move the cursor
2778		 * forward, otherwise nvpair_native_op() will read
2779		 * the entire nvpair at the same cursor position.
2780		 */
2781		if (*size == 0)
2782			native->n_curr += sizeof (int32_t);
2783		break;
2784	}
2785
2786	default:
2787		return (EINVAL);
2788	}
2789
2790	return (0);
2791}
2792
2793static const nvs_ops_t nvs_native_ops = {
2794	nvs_native_nvlist,
2795	nvs_native_nvpair,
2796	nvs_native_nvp_op,
2797	nvs_native_nvp_size,
2798	nvs_native_nvl_fini
2799};
2800
2801static int
2802nvs_native(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen)
2803{
2804	nvs_native_t native;
2805	int err;
2806
2807	nvs->nvs_ops = &nvs_native_ops;
2808
2809	if ((err = nvs_native_create(nvs, &native, buf + sizeof (nvs_header_t),
2810	    *buflen - sizeof (nvs_header_t))) != 0)
2811		return (err);
2812
2813	err = nvs_operation(nvs, nvl, buflen);
2814
2815	nvs_native_destroy(nvs);
2816
2817	return (err);
2818}
2819
2820/*
2821 * XDR encoding functions
2822 *
2823 * An xdr packed nvlist is encoded as:
2824 *
2825 *  - encoding methode and host endian (4 bytes)
2826 *  - nvl_version (4 bytes)
2827 *  - nvl_nvflag (4 bytes)
2828 *
2829 *  - encoded nvpairs, the format of one xdr encoded nvpair is:
2830 *	- encoded size of the nvpair (4 bytes)
2831 *	- decoded size of the nvpair (4 bytes)
2832 *	- name string, (4 + sizeof(NV_ALIGN4(string))
2833 *	  a string is coded as size (4 bytes) and data
2834 *	- data type (4 bytes)
2835 *	- number of elements in the nvpair (4 bytes)
2836 *	- data
2837 *
2838 *  - 2 zero's for end of the entire list (8 bytes)
2839 */
2840static int
2841nvs_xdr_create(nvstream_t *nvs, XDR *xdr, char *buf, size_t buflen)
2842{
2843	/* xdr data must be 4 byte aligned */
2844	if ((ulong_t)buf % 4 != 0)
2845		return (EFAULT);
2846
2847	switch (nvs->nvs_op) {
2848	case NVS_OP_ENCODE:
2849		xdrmem_create(xdr, buf, (uint_t)buflen, XDR_ENCODE);
2850		nvs->nvs_private = xdr;
2851		return (0);
2852	case NVS_OP_DECODE:
2853		xdrmem_create(xdr, buf, (uint_t)buflen, XDR_DECODE);
2854		nvs->nvs_private = xdr;
2855		return (0);
2856	case NVS_OP_GETSIZE:
2857		nvs->nvs_private = NULL;
2858		return (0);
2859	default:
2860		return (EINVAL);
2861	}
2862}
2863
2864static void
2865nvs_xdr_destroy(nvstream_t *nvs)
2866{
2867	switch (nvs->nvs_op) {
2868	case NVS_OP_ENCODE:
2869	case NVS_OP_DECODE:
2870		xdr_destroy((XDR *)nvs->nvs_private);
2871		break;
2872	default:
2873		break;
2874	}
2875}
2876
2877static int
2878nvs_xdr_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size)
2879{
2880	switch (nvs->nvs_op) {
2881	case NVS_OP_ENCODE:
2882	case NVS_OP_DECODE: {
2883		XDR 	*xdr = nvs->nvs_private;
2884
2885		if (!xdr_int(xdr, &nvl->nvl_version) ||
2886		    !xdr_u_int(xdr, &nvl->nvl_nvflag))
2887			return (EFAULT);
2888		break;
2889	}
2890	case NVS_OP_GETSIZE: {
2891		/*
2892		 * 2 * 4 for nvl_version + nvl_nvflag
2893		 * and 8 for end of the entire list
2894		 */
2895		*size += 2 * 4 + 8;
2896		break;
2897	}
2898	default:
2899		return (EINVAL);
2900	}
2901	return (0);
2902}
2903
2904static int
2905nvs_xdr_nvl_fini(nvstream_t *nvs)
2906{
2907	if (nvs->nvs_op == NVS_OP_ENCODE) {
2908		XDR *xdr = nvs->nvs_private;
2909		int zero = 0;
2910
2911		if (!xdr_int(xdr, &zero) || !xdr_int(xdr, &zero))
2912			return (EFAULT);
2913	}
2914
2915	return (0);
2916}
2917
2918/*
2919 * The format of xdr encoded nvpair is:
2920 * encode_size, decode_size, name string, data type, nelem, data
2921 */
2922static int
2923nvs_xdr_nvp_op(nvstream_t *nvs, nvpair_t *nvp)
2924{
2925	data_type_t type;
2926	char	*buf;
2927	char	*buf_end = (char *)nvp + nvp->nvp_size;
2928	int	value_sz;
2929	uint_t	nelem, buflen;
2930	bool_t	ret = FALSE;
2931	XDR	*xdr = nvs->nvs_private;
2932
2933	ASSERT(xdr != NULL && nvp != NULL);
2934
2935	/* name string */
2936	if ((buf = NVP_NAME(nvp)) >= buf_end)
2937		return (EFAULT);
2938	buflen = buf_end - buf;
2939
2940	if (!xdr_string(xdr, &buf, buflen - 1))
2941		return (EFAULT);
2942	nvp->nvp_name_sz = strlen(buf) + 1;
2943
2944	/* type and nelem */
2945	if (!xdr_int(xdr, (int *)&nvp->nvp_type) ||
2946	    !xdr_int(xdr, &nvp->nvp_value_elem))
2947		return (EFAULT);
2948
2949	type = NVP_TYPE(nvp);
2950	nelem = nvp->nvp_value_elem;
2951
2952	/*
2953	 * Verify type and nelem and get the value size.
2954	 * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY
2955	 * is the size of the string(s) excluded.
2956	 */
2957	if ((value_sz = i_get_value_size(type, NULL, nelem)) < 0)
2958		return (EFAULT);
2959
2960	/* if there is no data to extract then return */
2961	if (nelem == 0)
2962		return (0);
2963
2964	/* value */
2965	if ((buf = NVP_VALUE(nvp)) >= buf_end)
2966		return (EFAULT);
2967	buflen = buf_end - buf;
2968
2969	if (buflen < value_sz)
2970		return (EFAULT);
2971
2972	switch (type) {
2973	case DATA_TYPE_NVLIST:
2974		if (nvs_embedded(nvs, (void *)buf) == 0)
2975			return (0);
2976		break;
2977
2978	case DATA_TYPE_NVLIST_ARRAY:
2979		if (nvs_embedded_nvl_array(nvs, nvp, NULL) == 0)
2980			return (0);
2981		break;
2982
2983	case DATA_TYPE_BOOLEAN:
2984		ret = TRUE;
2985		break;
2986
2987	case DATA_TYPE_BYTE:
2988	case DATA_TYPE_INT8:
2989	case DATA_TYPE_UINT8:
2990		ret = xdr_char(xdr, buf);
2991		break;
2992
2993	case DATA_TYPE_INT16:
2994		ret = xdr_short(xdr, (void *)buf);
2995		break;
2996
2997	case DATA_TYPE_UINT16:
2998		ret = xdr_u_short(xdr, (void *)buf);
2999		break;
3000
3001	case DATA_TYPE_BOOLEAN_VALUE:
3002	case DATA_TYPE_INT32:
3003		ret = xdr_int(xdr, (void *)buf);
3004		break;
3005
3006	case DATA_TYPE_UINT32:
3007		ret = xdr_u_int(xdr, (void *)buf);
3008		break;
3009
3010	case DATA_TYPE_INT64:
3011		ret = xdr_longlong_t(xdr, (void *)buf);
3012		break;
3013
3014	case DATA_TYPE_UINT64:
3015		ret = xdr_u_longlong_t(xdr, (void *)buf);
3016		break;
3017
3018	case DATA_TYPE_HRTIME:
3019		/*
3020		 * NOTE: must expose the definition of hrtime_t here
3021		 */
3022		ret = xdr_longlong_t(xdr, (void *)buf);
3023		break;
3024#if !defined(_KERNEL)
3025	case DATA_TYPE_DOUBLE:
3026		ret = xdr_double(xdr, (void *)buf);
3027		break;
3028#endif
3029	case DATA_TYPE_STRING:
3030		ret = xdr_string(xdr, &buf, buflen - 1);
3031		break;
3032
3033	case DATA_TYPE_BYTE_ARRAY:
3034		ret = xdr_opaque(xdr, buf, nelem);
3035		break;
3036
3037	case DATA_TYPE_INT8_ARRAY:
3038	case DATA_TYPE_UINT8_ARRAY:
3039		ret = xdr_array(xdr, &buf, &nelem, buflen, sizeof (int8_t),
3040		    (xdrproc_t)xdr_char);
3041		break;
3042
3043	case DATA_TYPE_INT16_ARRAY:
3044		ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int16_t),
3045		    sizeof (int16_t), (xdrproc_t)xdr_short);
3046		break;
3047
3048	case DATA_TYPE_UINT16_ARRAY:
3049		ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint16_t),
3050		    sizeof (uint16_t), (xdrproc_t)xdr_u_short);
3051		break;
3052
3053	case DATA_TYPE_BOOLEAN_ARRAY:
3054	case DATA_TYPE_INT32_ARRAY:
3055		ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int32_t),
3056		    sizeof (int32_t), (xdrproc_t)xdr_int);
3057		break;
3058
3059	case DATA_TYPE_UINT32_ARRAY:
3060		ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint32_t),
3061		    sizeof (uint32_t), (xdrproc_t)xdr_u_int);
3062		break;
3063
3064	case DATA_TYPE_INT64_ARRAY:
3065		ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int64_t),
3066		    sizeof (int64_t), (xdrproc_t)xdr_longlong_t);
3067		break;
3068
3069	case DATA_TYPE_UINT64_ARRAY:
3070		ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint64_t),
3071		    sizeof (uint64_t), (xdrproc_t)xdr_u_longlong_t);
3072		break;
3073
3074	case DATA_TYPE_STRING_ARRAY: {
3075		size_t len = nelem * sizeof (uint64_t);
3076		char **strp = (void *)buf;
3077		int i;
3078
3079		if (nvs->nvs_op == NVS_OP_DECODE)
3080			bzero(buf, len);	/* don't trust packed data */
3081
3082		for (i = 0; i < nelem; i++) {
3083			if (buflen <= len)
3084				return (EFAULT);
3085
3086			buf += len;
3087			buflen -= len;
3088
3089			if (xdr_string(xdr, &buf, buflen - 1) != TRUE)
3090				return (EFAULT);
3091
3092			if (nvs->nvs_op == NVS_OP_DECODE)
3093				strp[i] = buf;
3094			len = strlen(buf) + 1;
3095		}
3096		ret = TRUE;
3097		break;
3098	}
3099	default:
3100		break;
3101	}
3102
3103	return (ret == TRUE ? 0 : EFAULT);
3104}
3105
3106static int
3107nvs_xdr_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
3108{
3109	data_type_t type = NVP_TYPE(nvp);
3110	/*
3111	 * encode_size + decode_size + name string size + data type + nelem
3112	 * where name string size = 4 + NV_ALIGN4(strlen(NVP_NAME(nvp)))
3113	 */
3114	uint64_t nvp_sz = 4 + 4 + 4 + NV_ALIGN4(strlen(NVP_NAME(nvp))) + 4 + 4;
3115
3116	switch (type) {
3117	case DATA_TYPE_BOOLEAN:
3118		break;
3119
3120	case DATA_TYPE_BOOLEAN_VALUE:
3121	case DATA_TYPE_BYTE:
3122	case DATA_TYPE_INT8:
3123	case DATA_TYPE_UINT8:
3124	case DATA_TYPE_INT16:
3125	case DATA_TYPE_UINT16:
3126	case DATA_TYPE_INT32:
3127	case DATA_TYPE_UINT32:
3128		nvp_sz += 4;	/* 4 is the minimum xdr unit */
3129		break;
3130
3131	case DATA_TYPE_INT64:
3132	case DATA_TYPE_UINT64:
3133	case DATA_TYPE_HRTIME:
3134#if !defined(_KERNEL)
3135	case DATA_TYPE_DOUBLE:
3136#endif
3137		nvp_sz += 8;
3138		break;
3139
3140	case DATA_TYPE_STRING:
3141		nvp_sz += 4 + NV_ALIGN4(strlen((char *)NVP_VALUE(nvp)));
3142		break;
3143
3144	case DATA_TYPE_BYTE_ARRAY:
3145		nvp_sz += NV_ALIGN4(NVP_NELEM(nvp));
3146		break;
3147
3148	case DATA_TYPE_BOOLEAN_ARRAY:
3149	case DATA_TYPE_INT8_ARRAY:
3150	case DATA_TYPE_UINT8_ARRAY:
3151	case DATA_TYPE_INT16_ARRAY:
3152	case DATA_TYPE_UINT16_ARRAY:
3153	case DATA_TYPE_INT32_ARRAY:
3154	case DATA_TYPE_UINT32_ARRAY:
3155		nvp_sz += 4 + 4 * (uint64_t)NVP_NELEM(nvp);
3156		break;
3157
3158	case DATA_TYPE_INT64_ARRAY:
3159	case DATA_TYPE_UINT64_ARRAY:
3160		nvp_sz += 4 + 8 * (uint64_t)NVP_NELEM(nvp);
3161		break;
3162
3163	case DATA_TYPE_STRING_ARRAY: {
3164		int i;
3165		char **strs = (void *)NVP_VALUE(nvp);
3166
3167		for (i = 0; i < NVP_NELEM(nvp); i++)
3168			nvp_sz += 4 + NV_ALIGN4(strlen(strs[i]));
3169
3170		break;
3171	}
3172
3173	case DATA_TYPE_NVLIST:
3174	case DATA_TYPE_NVLIST_ARRAY: {
3175		size_t nvsize = 0;
3176		int old_nvs_op = nvs->nvs_op;
3177		int err;
3178
3179		nvs->nvs_op = NVS_OP_GETSIZE;
3180		if (type == DATA_TYPE_NVLIST)
3181			err = nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize);
3182		else
3183			err = nvs_embedded_nvl_array(nvs, nvp, &nvsize);
3184		nvs->nvs_op = old_nvs_op;
3185
3186		if (err != 0)
3187			return (EINVAL);
3188
3189		nvp_sz += nvsize;
3190		break;
3191	}
3192
3193	default:
3194		return (EINVAL);
3195	}
3196
3197	if (nvp_sz > INT32_MAX)
3198		return (EINVAL);
3199
3200	*size = nvp_sz;
3201
3202	return (0);
3203}
3204
3205
3206/*
3207 * The NVS_XDR_MAX_LEN macro takes a packed xdr buffer of size x and estimates
3208 * the largest nvpair that could be encoded in the buffer.
3209 *
3210 * See comments above nvpair_xdr_op() for the format of xdr encoding.
3211 * The size of a xdr packed nvpair without any data is 5 words.
3212 *
3213 * Using the size of the data directly as an estimate would be ok
3214 * in all cases except one.  If the data type is of DATA_TYPE_STRING_ARRAY
3215 * then the actual nvpair has space for an array of pointers to index
3216 * the strings.  These pointers are not encoded into the packed xdr buffer.
3217 *
3218 * If the data is of type DATA_TYPE_STRING_ARRAY and all the strings are
3219 * of length 0, then each string is endcoded in xdr format as a single word.
3220 * Therefore when expanded to an nvpair there will be 2.25 word used for
3221 * each string.  (a int64_t allocated for pointer usage, and a single char
3222 * for the null termination.)
3223 *
3224 * This is the calculation performed by the NVS_XDR_MAX_LEN macro.
3225 */
3226#define	NVS_XDR_HDR_LEN		((size_t)(5 * 4))
3227#define	NVS_XDR_DATA_LEN(y)	(((size_t)(y) <= NVS_XDR_HDR_LEN) ? \
3228					0 : ((size_t)(y) - NVS_XDR_HDR_LEN))
3229#define	NVS_XDR_MAX_LEN(x)	(NVP_SIZE_CALC(1, 0) + \
3230					(NVS_XDR_DATA_LEN(x) * 2) + \
3231					NV_ALIGN4((NVS_XDR_DATA_LEN(x) / 4)))
3232
3233static int
3234nvs_xdr_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
3235{
3236	XDR 	*xdr = nvs->nvs_private;
3237	int32_t	encode_len, decode_len;
3238
3239	switch (nvs->nvs_op) {
3240	case NVS_OP_ENCODE: {
3241		size_t nvsize;
3242
3243		if (nvs_xdr_nvp_size(nvs, nvp, &nvsize) != 0)
3244			return (EFAULT);
3245
3246		decode_len = nvp->nvp_size;
3247		encode_len = nvsize;
3248		if (!xdr_int(xdr, &encode_len) || !xdr_int(xdr, &decode_len))
3249			return (EFAULT);
3250
3251		return (nvs_xdr_nvp_op(nvs, nvp));
3252	}
3253	case NVS_OP_DECODE: {
3254		struct xdr_bytesrec bytesrec;
3255
3256		/* get the encode and decode size */
3257		if (!xdr_int(xdr, &encode_len) || !xdr_int(xdr, &decode_len))
3258			return (EFAULT);
3259		*size = decode_len;
3260
3261		/* are we at the end of the stream? */
3262		if (*size == 0)
3263			return (0);
3264
3265		/* sanity check the size parameter */
3266		if (!xdr_control(xdr, XDR_GET_BYTES_AVAIL, &bytesrec))
3267			return (EFAULT);
3268
3269		if (*size > NVS_XDR_MAX_LEN(bytesrec.xc_num_avail))
3270			return (EFAULT);
3271		break;
3272	}
3273
3274	default:
3275		return (EINVAL);
3276	}
3277	return (0);
3278}
3279
3280static const struct nvs_ops nvs_xdr_ops = {
3281	nvs_xdr_nvlist,
3282	nvs_xdr_nvpair,
3283	nvs_xdr_nvp_op,
3284	nvs_xdr_nvp_size,
3285	nvs_xdr_nvl_fini
3286};
3287
3288static int
3289nvs_xdr(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen)
3290{
3291	XDR xdr;
3292	int err;
3293
3294	nvs->nvs_ops = &nvs_xdr_ops;
3295
3296	if ((err = nvs_xdr_create(nvs, &xdr, buf + sizeof (nvs_header_t),
3297	    *buflen - sizeof (nvs_header_t))) != 0)
3298		return (err);
3299
3300	err = nvs_operation(nvs, nvl, buflen);
3301
3302	nvs_xdr_destroy(nvs);
3303
3304	return (err);
3305}
3306