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