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