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