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