13830659eSToomas Soome /*-
23830659eSToomas Soome * Copyright 2020 Toomas Soome <tsoome@me.com>
33830659eSToomas Soome *
43830659eSToomas Soome * Redistribution and use in source and binary forms, with or without
53830659eSToomas Soome * modification, are permitted provided that the following conditions
63830659eSToomas Soome * are met:
73830659eSToomas Soome * 1. Redistributions of source code must retain the above copyright
83830659eSToomas Soome * notice, this list of conditions and the following disclaimer.
93830659eSToomas Soome * 2. Redistributions in binary form must reproduce the above copyright
103830659eSToomas Soome * notice, this list of conditions and the following disclaimer in the
113830659eSToomas Soome * documentation and/or other materials provided with the distribution.
123830659eSToomas Soome *
133830659eSToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
143830659eSToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
153830659eSToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
163830659eSToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
173830659eSToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
183830659eSToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
193830659eSToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
203830659eSToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
213830659eSToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
223830659eSToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
233830659eSToomas Soome * SUCH DAMAGE.
243830659eSToomas Soome */
253830659eSToomas Soome
26e097436cSMark Johnston #include <sys/param.h>
273830659eSToomas Soome #include <sys/endian.h>
28e307eb94SToomas Soome #include <sys/stdint.h>
29e097436cSMark Johnston #ifdef _STANDALONE
30e097436cSMark Johnston #include <stand.h>
31e097436cSMark Johnston #else
32e097436cSMark Johnston #include <errno.h>
33e097436cSMark Johnston #include <stdbool.h>
34e097436cSMark Johnston #include <stdio.h>
35e097436cSMark Johnston #include <stdlib.h>
36e097436cSMark Johnston #include <string.h>
37e097436cSMark Johnston #endif
38e097436cSMark Johnston
39e097436cSMark Johnston #include "nvlist.h"
403830659eSToomas Soome
41e307eb94SToomas Soome enum xdr_op {
42e307eb94SToomas Soome XDR_OP_ENCODE = 1,
43e307eb94SToomas Soome XDR_OP_DECODE = 2
44e307eb94SToomas Soome };
45e307eb94SToomas Soome
463830659eSToomas Soome typedef struct xdr {
47e307eb94SToomas Soome enum xdr_op xdr_op;
48e307eb94SToomas Soome int (*xdr_getint)(struct xdr *, int *);
49e307eb94SToomas Soome int (*xdr_putint)(struct xdr *, int);
50e307eb94SToomas Soome int (*xdr_getuint)(struct xdr *, unsigned *);
51e307eb94SToomas Soome int (*xdr_putuint)(struct xdr *, unsigned);
52e307eb94SToomas Soome const uint8_t *xdr_buf;
53e307eb94SToomas Soome uint8_t *xdr_idx;
54e307eb94SToomas Soome size_t xdr_buf_size;
553830659eSToomas Soome } xdr_t;
563830659eSToomas Soome
57e307eb94SToomas Soome static int nvlist_xdr_nvlist(xdr_t *, nvlist_t *);
58e307eb94SToomas Soome static bool nvlist_size_xdr(xdr_t *, size_t *);
59e307eb94SToomas Soome static bool nvlist_size_native(xdr_t *, size_t *);
60e307eb94SToomas Soome static bool xdr_int(xdr_t *, int *);
61e307eb94SToomas Soome static bool xdr_u_int(xdr_t *, unsigned *);
623830659eSToomas Soome
632ae58414SToomas Soome typedef bool (*xdrproc_t)(xdr_t *, void *);
643830659eSToomas Soome
65e307eb94SToomas Soome /* Basic primitives for XDR translation operations, getint and putint. */
663830659eSToomas Soome static int
_getint(struct xdr * xdr,int * ip)67e307eb94SToomas Soome _getint(struct xdr *xdr, int *ip)
683830659eSToomas Soome {
69e307eb94SToomas Soome *ip = be32dec(xdr->xdr_idx);
703830659eSToomas Soome return (sizeof(int));
713830659eSToomas Soome }
723830659eSToomas Soome
733830659eSToomas Soome static int
_putint(struct xdr * xdr,int i)74e307eb94SToomas Soome _putint(struct xdr *xdr, int i)
753830659eSToomas Soome {
76e307eb94SToomas Soome int *ip = (int *)xdr->xdr_idx;
77e307eb94SToomas Soome
78e307eb94SToomas Soome *ip = htobe32(i);
79e307eb94SToomas Soome return (sizeof(int));
80e307eb94SToomas Soome }
81e307eb94SToomas Soome
82e307eb94SToomas Soome static int
_getuint(struct xdr * xdr,unsigned * ip)83e307eb94SToomas Soome _getuint(struct xdr *xdr, unsigned *ip)
84e307eb94SToomas Soome {
85e307eb94SToomas Soome *ip = be32dec(xdr->xdr_idx);
863830659eSToomas Soome return (sizeof(unsigned));
873830659eSToomas Soome }
883830659eSToomas Soome
893830659eSToomas Soome static int
_putuint(struct xdr * xdr,unsigned i)90e307eb94SToomas Soome _putuint(struct xdr *xdr, unsigned i)
913830659eSToomas Soome {
92e307eb94SToomas Soome unsigned *up = (unsigned *)xdr->xdr_idx;
933830659eSToomas Soome
94e307eb94SToomas Soome *up = htobe32(i);
95e307eb94SToomas Soome return (sizeof(int));
963830659eSToomas Soome }
973830659eSToomas Soome
989de6a13eSToomas Soome static int
_getint_mem(struct xdr * xdr,int * ip)999de6a13eSToomas Soome _getint_mem(struct xdr *xdr, int *ip)
1009de6a13eSToomas Soome {
1019de6a13eSToomas Soome *ip = *(int *)xdr->xdr_idx;
1029de6a13eSToomas Soome return (sizeof(int));
1039de6a13eSToomas Soome }
1049de6a13eSToomas Soome
1059de6a13eSToomas Soome static int
_putint_mem(struct xdr * xdr,int i)1069de6a13eSToomas Soome _putint_mem(struct xdr *xdr, int i)
1079de6a13eSToomas Soome {
1089de6a13eSToomas Soome int *ip = (int *)xdr->xdr_idx;
1099de6a13eSToomas Soome
1109de6a13eSToomas Soome *ip = i;
1119de6a13eSToomas Soome return (sizeof(int));
1129de6a13eSToomas Soome }
1139de6a13eSToomas Soome
1149de6a13eSToomas Soome static int
_getuint_mem(struct xdr * xdr,unsigned * ip)1159de6a13eSToomas Soome _getuint_mem(struct xdr *xdr, unsigned *ip)
1169de6a13eSToomas Soome {
1179de6a13eSToomas Soome *ip = *(unsigned *)xdr->xdr_idx;
1189de6a13eSToomas Soome return (sizeof(unsigned));
1199de6a13eSToomas Soome }
1209de6a13eSToomas Soome
1219de6a13eSToomas Soome static int
_putuint_mem(struct xdr * xdr,unsigned i)1229de6a13eSToomas Soome _putuint_mem(struct xdr *xdr, unsigned i)
1239de6a13eSToomas Soome {
1249de6a13eSToomas Soome unsigned *up = (unsigned *)xdr->xdr_idx;
1259de6a13eSToomas Soome
1269de6a13eSToomas Soome *up = i;
1279de6a13eSToomas Soome return (sizeof(int));
1289de6a13eSToomas Soome }
1299de6a13eSToomas Soome
130e307eb94SToomas Soome /*
131e307eb94SToomas Soome * XDR data translations.
132e307eb94SToomas Soome */
133e307eb94SToomas Soome static bool
xdr_short(xdr_t * xdr,short * ip)134e307eb94SToomas Soome xdr_short(xdr_t *xdr, short *ip)
1353830659eSToomas Soome {
136e307eb94SToomas Soome int i;
137e307eb94SToomas Soome bool rv;
1383830659eSToomas Soome
139e307eb94SToomas Soome i = *ip;
140e307eb94SToomas Soome if ((rv = xdr_int(xdr, &i))) {
141e307eb94SToomas Soome if (xdr->xdr_op == XDR_OP_DECODE)
142e307eb94SToomas Soome *ip = i;
143e307eb94SToomas Soome }
1443830659eSToomas Soome return (rv);
1453830659eSToomas Soome }
1463830659eSToomas Soome
147e307eb94SToomas Soome static bool
xdr_u_short(xdr_t * xdr,unsigned short * ip)148e307eb94SToomas Soome xdr_u_short(xdr_t *xdr, unsigned short *ip)
1493830659eSToomas Soome {
150e307eb94SToomas Soome unsigned u;
151e307eb94SToomas Soome bool rv;
1523830659eSToomas Soome
153e307eb94SToomas Soome u = *ip;
154e307eb94SToomas Soome if ((rv = xdr_u_int(xdr, &u))) {
155e307eb94SToomas Soome if (xdr->xdr_op == XDR_OP_DECODE)
156e307eb94SToomas Soome *ip = u;
1573830659eSToomas Soome }
1583830659eSToomas Soome return (rv);
1593830659eSToomas Soome }
1603830659eSToomas Soome
1613830659eSToomas Soome /*
162e307eb94SToomas Soome * translate xdr->xdr_idx, increment it by size of int.
1633830659eSToomas Soome */
164e307eb94SToomas Soome static bool
xdr_int(xdr_t * xdr,int * ip)165e307eb94SToomas Soome xdr_int(xdr_t *xdr, int *ip)
1663830659eSToomas Soome {
167e307eb94SToomas Soome bool rv = false;
168e307eb94SToomas Soome int *i = (int *)xdr->xdr_idx;
169e307eb94SToomas Soome
170e307eb94SToomas Soome if (xdr->xdr_idx + sizeof(int) > xdr->xdr_buf + xdr->xdr_buf_size)
171e307eb94SToomas Soome return (rv);
172e307eb94SToomas Soome
173e307eb94SToomas Soome switch (xdr->xdr_op) {
174e307eb94SToomas Soome case XDR_OP_ENCODE:
175e307eb94SToomas Soome /* Encode value *ip, store to buf */
176e307eb94SToomas Soome xdr->xdr_idx += xdr->xdr_putint(xdr, *ip);
177e307eb94SToomas Soome rv = true;
178e307eb94SToomas Soome break;
179e307eb94SToomas Soome
180e307eb94SToomas Soome case XDR_OP_DECODE:
181e307eb94SToomas Soome /* Decode buf, return value to *ip */
182e307eb94SToomas Soome xdr->xdr_idx += xdr->xdr_getint(xdr, i);
183e307eb94SToomas Soome *ip = *i;
184e307eb94SToomas Soome rv = true;
185e307eb94SToomas Soome break;
186e307eb94SToomas Soome }
187e307eb94SToomas Soome return (rv);
1883830659eSToomas Soome }
1893830659eSToomas Soome
190e307eb94SToomas Soome /*
191e307eb94SToomas Soome * translate xdr->xdr_idx, increment it by size of unsigned int.
192e307eb94SToomas Soome */
193e307eb94SToomas Soome static bool
xdr_u_int(xdr_t * xdr,unsigned * ip)194e307eb94SToomas Soome xdr_u_int(xdr_t *xdr, unsigned *ip)
195e307eb94SToomas Soome {
196e307eb94SToomas Soome bool rv = false;
197e307eb94SToomas Soome unsigned *u = (unsigned *)xdr->xdr_idx;
198e307eb94SToomas Soome
199e307eb94SToomas Soome if (xdr->xdr_idx + sizeof(unsigned) > xdr->xdr_buf + xdr->xdr_buf_size)
200e307eb94SToomas Soome return (rv);
201e307eb94SToomas Soome
202e307eb94SToomas Soome switch (xdr->xdr_op) {
203e307eb94SToomas Soome case XDR_OP_ENCODE:
204e307eb94SToomas Soome /* Encode value *ip, store to buf */
205e307eb94SToomas Soome xdr->xdr_idx += xdr->xdr_putuint(xdr, *ip);
206e307eb94SToomas Soome rv = true;
207e307eb94SToomas Soome break;
208e307eb94SToomas Soome
209e307eb94SToomas Soome case XDR_OP_DECODE:
210e307eb94SToomas Soome /* Decode buf, return value to *ip */
211e307eb94SToomas Soome xdr->xdr_idx += xdr->xdr_getuint(xdr, u);
212e307eb94SToomas Soome *ip = *u;
213e307eb94SToomas Soome rv = true;
214e307eb94SToomas Soome break;
215e307eb94SToomas Soome }
216e307eb94SToomas Soome return (rv);
217e307eb94SToomas Soome }
218e307eb94SToomas Soome
219e307eb94SToomas Soome static bool
xdr_int64(xdr_t * xdr,int64_t * lp)220e307eb94SToomas Soome xdr_int64(xdr_t *xdr, int64_t *lp)
221e307eb94SToomas Soome {
222e307eb94SToomas Soome bool rv = false;
223e307eb94SToomas Soome
224e307eb94SToomas Soome if (xdr->xdr_idx + sizeof(int64_t) > xdr->xdr_buf + xdr->xdr_buf_size)
225e307eb94SToomas Soome return (rv);
226e307eb94SToomas Soome
227e307eb94SToomas Soome switch (xdr->xdr_op) {
228e307eb94SToomas Soome case XDR_OP_ENCODE:
229e307eb94SToomas Soome /* Encode value *lp, store to buf */
2309de6a13eSToomas Soome if (xdr->xdr_putint == _putint)
2319de6a13eSToomas Soome *(int64_t *)xdr->xdr_idx = htobe64(*lp);
2329de6a13eSToomas Soome else
2339de6a13eSToomas Soome *(int64_t *)xdr->xdr_idx = *lp;
2349de6a13eSToomas Soome xdr->xdr_idx += sizeof(int64_t);
235e307eb94SToomas Soome rv = true;
236e307eb94SToomas Soome break;
237e307eb94SToomas Soome
238e307eb94SToomas Soome case XDR_OP_DECODE:
239e307eb94SToomas Soome /* Decode buf, return value to *ip */
2409de6a13eSToomas Soome if (xdr->xdr_getint == _getint)
2419de6a13eSToomas Soome *lp = be64toh(*(int64_t *)xdr->xdr_idx);
2429de6a13eSToomas Soome else
2439de6a13eSToomas Soome *lp = *(int64_t *)xdr->xdr_idx;
2449de6a13eSToomas Soome xdr->xdr_idx += sizeof(int64_t);
245e307eb94SToomas Soome rv = true;
246e307eb94SToomas Soome }
247e307eb94SToomas Soome return (rv);
248e307eb94SToomas Soome }
249e307eb94SToomas Soome
250e307eb94SToomas Soome static bool
xdr_uint64(xdr_t * xdr,uint64_t * lp)251e307eb94SToomas Soome xdr_uint64(xdr_t *xdr, uint64_t *lp)
252e307eb94SToomas Soome {
253e307eb94SToomas Soome bool rv = false;
254e307eb94SToomas Soome
255e307eb94SToomas Soome if (xdr->xdr_idx + sizeof(uint64_t) > xdr->xdr_buf + xdr->xdr_buf_size)
256e307eb94SToomas Soome return (rv);
257e307eb94SToomas Soome
258e307eb94SToomas Soome switch (xdr->xdr_op) {
259e307eb94SToomas Soome case XDR_OP_ENCODE:
260e307eb94SToomas Soome /* Encode value *ip, store to buf */
2619de6a13eSToomas Soome if (xdr->xdr_putint == _putint)
2629de6a13eSToomas Soome *(uint64_t *)xdr->xdr_idx = htobe64(*lp);
2639de6a13eSToomas Soome else
2649de6a13eSToomas Soome *(uint64_t *)xdr->xdr_idx = *lp;
2659de6a13eSToomas Soome xdr->xdr_idx += sizeof(uint64_t);
266e307eb94SToomas Soome rv = true;
267e307eb94SToomas Soome break;
268e307eb94SToomas Soome
269e307eb94SToomas Soome case XDR_OP_DECODE:
270e307eb94SToomas Soome /* Decode buf, return value to *ip */
2719de6a13eSToomas Soome if (xdr->xdr_getuint == _getuint)
2729de6a13eSToomas Soome *lp = be64toh(*(uint64_t *)xdr->xdr_idx);
2739de6a13eSToomas Soome else
2749de6a13eSToomas Soome *lp = *(uint64_t *)xdr->xdr_idx;
2759de6a13eSToomas Soome xdr->xdr_idx += sizeof(uint64_t);
276e307eb94SToomas Soome rv = true;
277e307eb94SToomas Soome }
278e307eb94SToomas Soome return (rv);
279e307eb94SToomas Soome }
280e307eb94SToomas Soome
281e307eb94SToomas Soome static bool
xdr_char(xdr_t * xdr,char * cp)282e307eb94SToomas Soome xdr_char(xdr_t *xdr, char *cp)
283e307eb94SToomas Soome {
284e307eb94SToomas Soome int i;
285e307eb94SToomas Soome bool rv = false;
286e307eb94SToomas Soome
287e307eb94SToomas Soome i = *cp;
288e307eb94SToomas Soome if ((rv = xdr_int(xdr, &i))) {
289e307eb94SToomas Soome if (xdr->xdr_op == XDR_OP_DECODE)
290e307eb94SToomas Soome *cp = i;
291e307eb94SToomas Soome }
292e307eb94SToomas Soome return (rv);
293e307eb94SToomas Soome }
294e307eb94SToomas Soome
295e307eb94SToomas Soome static bool
xdr_string(xdr_t * xdr,nv_string_t * s)296e307eb94SToomas Soome xdr_string(xdr_t *xdr, nv_string_t *s)
297e307eb94SToomas Soome {
298e307eb94SToomas Soome int size = 0;
299e307eb94SToomas Soome bool rv = false;
300e307eb94SToomas Soome
301e307eb94SToomas Soome switch (xdr->xdr_op) {
302e307eb94SToomas Soome case XDR_OP_ENCODE:
303e307eb94SToomas Soome size = s->nv_size;
304e307eb94SToomas Soome if (xdr->xdr_idx + sizeof(unsigned) + NV_ALIGN4(size) >
305e307eb94SToomas Soome xdr->xdr_buf + xdr->xdr_buf_size)
306e307eb94SToomas Soome break;
307e307eb94SToomas Soome xdr->xdr_idx += xdr->xdr_putuint(xdr, s->nv_size);
308e307eb94SToomas Soome xdr->xdr_idx += NV_ALIGN4(size);
309e307eb94SToomas Soome rv = true;
310e307eb94SToomas Soome break;
311e307eb94SToomas Soome
312e307eb94SToomas Soome case XDR_OP_DECODE:
313e307eb94SToomas Soome if (xdr->xdr_idx + sizeof(unsigned) >
314e307eb94SToomas Soome xdr->xdr_buf + xdr->xdr_buf_size)
315e307eb94SToomas Soome break;
316e307eb94SToomas Soome size = xdr->xdr_getuint(xdr, &s->nv_size);
317e307eb94SToomas Soome size = NV_ALIGN4(size + s->nv_size);
318e307eb94SToomas Soome if (xdr->xdr_idx + size > xdr->xdr_buf + xdr->xdr_buf_size)
319e307eb94SToomas Soome break;
320e307eb94SToomas Soome xdr->xdr_idx += size;
321e307eb94SToomas Soome rv = true;
322e307eb94SToomas Soome break;
323e307eb94SToomas Soome }
324e307eb94SToomas Soome return (rv);
325e307eb94SToomas Soome }
326e307eb94SToomas Soome
327e307eb94SToomas Soome static bool
xdr_array(xdr_t * xdr,const unsigned nelem,const xdrproc_t elproc)328e307eb94SToomas Soome xdr_array(xdr_t *xdr, const unsigned nelem, const xdrproc_t elproc)
329e307eb94SToomas Soome {
330e307eb94SToomas Soome bool rv = true;
3319de6a13eSToomas Soome unsigned c = nelem;
3329de6a13eSToomas Soome
3339de6a13eSToomas Soome if (!xdr_u_int(xdr, &c))
3349de6a13eSToomas Soome return (false);
335e307eb94SToomas Soome
336e307eb94SToomas Soome for (unsigned i = 0; i < nelem; i++) {
337e307eb94SToomas Soome if (!elproc(xdr, xdr->xdr_idx))
338e307eb94SToomas Soome return (false);
339e307eb94SToomas Soome }
340e307eb94SToomas Soome return (rv);
341e307eb94SToomas Soome }
342e307eb94SToomas Soome
343e307eb94SToomas Soome /*
344e307eb94SToomas Soome * nvlist management functions.
345e307eb94SToomas Soome */
3463830659eSToomas Soome void
nvlist_destroy(nvlist_t * nvl)3473830659eSToomas Soome nvlist_destroy(nvlist_t *nvl)
3483830659eSToomas Soome {
3493830659eSToomas Soome if (nvl != NULL) {
3503830659eSToomas Soome /* Free data if it was allocated by us. */
3513830659eSToomas Soome if (nvl->nv_asize > 0)
3523830659eSToomas Soome free(nvl->nv_data);
3533830659eSToomas Soome }
3543830659eSToomas Soome free(nvl);
3553830659eSToomas Soome }
3563830659eSToomas Soome
3573830659eSToomas Soome char *
nvstring_get(nv_string_t * nvs)3583830659eSToomas Soome nvstring_get(nv_string_t *nvs)
3593830659eSToomas Soome {
3603830659eSToomas Soome char *s;
3613830659eSToomas Soome
3623830659eSToomas Soome s = malloc(nvs->nv_size + 1);
3633830659eSToomas Soome if (s != NULL) {
3643830659eSToomas Soome bcopy(nvs->nv_data, s, nvs->nv_size);
3653830659eSToomas Soome s[nvs->nv_size] = '\0';
3663830659eSToomas Soome }
3673830659eSToomas Soome return (s);
3683830659eSToomas Soome }
3693830659eSToomas Soome
3703830659eSToomas Soome /*
3713830659eSToomas Soome * Create empty nvlist.
3723830659eSToomas Soome * The nvlist is terminated by 2x zeros (8 bytes).
3733830659eSToomas Soome */
3743830659eSToomas Soome nvlist_t *
nvlist_create(int flag)3753830659eSToomas Soome nvlist_create(int flag)
3763830659eSToomas Soome {
3773830659eSToomas Soome nvlist_t *nvl;
3783830659eSToomas Soome nvs_data_t *nvs;
3793830659eSToomas Soome
3803830659eSToomas Soome nvl = calloc(1, sizeof(*nvl));
3813830659eSToomas Soome if (nvl == NULL)
3823830659eSToomas Soome return (nvl);
3833830659eSToomas Soome
3843830659eSToomas Soome nvl->nv_header.nvh_encoding = NV_ENCODE_XDR;
3853830659eSToomas Soome nvl->nv_header.nvh_endian = _BYTE_ORDER == _LITTLE_ENDIAN;
3863830659eSToomas Soome
3873830659eSToomas Soome nvl->nv_asize = nvl->nv_size = sizeof(*nvs);
3883830659eSToomas Soome nvs = calloc(1, nvl->nv_asize);
3893830659eSToomas Soome if (nvs == NULL) {
3903830659eSToomas Soome free(nvl);
3913830659eSToomas Soome return (NULL);
3923830659eSToomas Soome }
3933830659eSToomas Soome /* data in nvlist is byte stream */
3943830659eSToomas Soome nvl->nv_data = (uint8_t *)nvs;
3953830659eSToomas Soome
3963830659eSToomas Soome nvs->nvl_version = NV_VERSION;
3973830659eSToomas Soome nvs->nvl_nvflag = flag;
3983830659eSToomas Soome return (nvl);
3993830659eSToomas Soome }
4003830659eSToomas Soome
401e307eb94SToomas Soome static bool
nvlist_xdr_nvp(xdr_t * xdr,nvlist_t * nvl)402e307eb94SToomas Soome nvlist_xdr_nvp(xdr_t *xdr, nvlist_t *nvl)
4033830659eSToomas Soome {
4043830659eSToomas Soome nv_string_t *nv_string;
4053830659eSToomas Soome nv_pair_data_t *nvp_data;
4063830659eSToomas Soome nvlist_t nvlist;
407e307eb94SToomas Soome unsigned type, nelem;
408e307eb94SToomas Soome xdr_t nv_xdr;
4093830659eSToomas Soome
410e307eb94SToomas Soome nv_string = (nv_string_t *)xdr->xdr_idx;
411e307eb94SToomas Soome if (!xdr_string(xdr, nv_string)) {
412e307eb94SToomas Soome return (false);
413e307eb94SToomas Soome }
414e307eb94SToomas Soome nvp_data = (nv_pair_data_t *)xdr->xdr_idx;
4153830659eSToomas Soome
416e307eb94SToomas Soome type = nvp_data->nv_type;
417e307eb94SToomas Soome nelem = nvp_data->nv_nelem;
418e307eb94SToomas Soome if (!xdr_u_int(xdr, &type) || !xdr_u_int(xdr, &nelem))
419e307eb94SToomas Soome return (false);
4203830659eSToomas Soome
421e307eb94SToomas Soome switch (type) {
4223830659eSToomas Soome case DATA_TYPE_NVLIST:
4233830659eSToomas Soome case DATA_TYPE_NVLIST_ARRAY:
4243830659eSToomas Soome bzero(&nvlist, sizeof(nvlist));
425e307eb94SToomas Soome nvlist.nv_data = xdr->xdr_idx;
4263830659eSToomas Soome nvlist.nv_idx = nvlist.nv_data;
427e307eb94SToomas Soome
428e307eb94SToomas Soome /* Set up xdr for this nvlist. */
429e307eb94SToomas Soome nv_xdr = *xdr;
430e307eb94SToomas Soome nv_xdr.xdr_buf = nvlist.nv_data;
431e307eb94SToomas Soome nv_xdr.xdr_idx = nvlist.nv_data;
432e307eb94SToomas Soome nv_xdr.xdr_buf_size =
433e307eb94SToomas Soome nvl->nv_data + nvl->nv_size - nvlist.nv_data;
434e307eb94SToomas Soome
435e307eb94SToomas Soome for (unsigned i = 0; i < nelem; i++) {
436e307eb94SToomas Soome if (xdr->xdr_op == XDR_OP_ENCODE) {
437e307eb94SToomas Soome if (!nvlist_size_native(&nv_xdr,
438e307eb94SToomas Soome &nvlist.nv_size))
439e307eb94SToomas Soome return (false);
440e307eb94SToomas Soome } else {
441e307eb94SToomas Soome if (!nvlist_size_xdr(&nv_xdr,
442e307eb94SToomas Soome &nvlist.nv_size))
443e307eb94SToomas Soome return (false);
444e307eb94SToomas Soome }
445e307eb94SToomas Soome if (nvlist_xdr_nvlist(xdr, &nvlist) != 0)
446e307eb94SToomas Soome return (false);
447e307eb94SToomas Soome
448e307eb94SToomas Soome nvlist.nv_data = nv_xdr.xdr_idx;
449e307eb94SToomas Soome nvlist.nv_idx = nv_xdr.xdr_idx;
450e307eb94SToomas Soome
451e307eb94SToomas Soome nv_xdr.xdr_buf = nv_xdr.xdr_idx;
452e307eb94SToomas Soome nv_xdr.xdr_buf_size =
453e307eb94SToomas Soome nvl->nv_data + nvl->nv_size - nvlist.nv_data;
4543830659eSToomas Soome }
4553830659eSToomas Soome break;
4563830659eSToomas Soome
4573830659eSToomas Soome case DATA_TYPE_BOOLEAN:
4583830659eSToomas Soome /* BOOLEAN does not take value space */
4593830659eSToomas Soome break;
4603830659eSToomas Soome case DATA_TYPE_BYTE:
4613830659eSToomas Soome case DATA_TYPE_INT8:
4623830659eSToomas Soome case DATA_TYPE_UINT8:
463e307eb94SToomas Soome if (!xdr_char(xdr, (char *)&nvp_data->nv_data[0]))
464e307eb94SToomas Soome return (false);
4653830659eSToomas Soome break;
4663830659eSToomas Soome
4673830659eSToomas Soome case DATA_TYPE_INT16:
468e307eb94SToomas Soome if (!xdr_short(xdr, (short *)&nvp_data->nv_data[0]))
469e307eb94SToomas Soome return (false);
4703830659eSToomas Soome break;
4713830659eSToomas Soome
4723830659eSToomas Soome case DATA_TYPE_UINT16:
473e307eb94SToomas Soome if (!xdr_u_short(xdr, (unsigned short *)&nvp_data->nv_data[0]))
474e307eb94SToomas Soome return (false);
4753830659eSToomas Soome break;
4763830659eSToomas Soome
4773830659eSToomas Soome case DATA_TYPE_BOOLEAN_VALUE:
4783830659eSToomas Soome case DATA_TYPE_INT32:
479e307eb94SToomas Soome if (!xdr_int(xdr, (int *)&nvp_data->nv_data[0]))
480e307eb94SToomas Soome return (false);
4813830659eSToomas Soome break;
4823830659eSToomas Soome
4833830659eSToomas Soome case DATA_TYPE_UINT32:
484e307eb94SToomas Soome if (!xdr_u_int(xdr, (unsigned *)&nvp_data->nv_data[0]))
485e307eb94SToomas Soome return (false);
4863830659eSToomas Soome break;
4873830659eSToomas Soome
488e307eb94SToomas Soome case DATA_TYPE_HRTIME:
4893830659eSToomas Soome case DATA_TYPE_INT64:
490e307eb94SToomas Soome if (!xdr_int64(xdr, (int64_t *)&nvp_data->nv_data[0]))
491e307eb94SToomas Soome return (false);
4923830659eSToomas Soome break;
4933830659eSToomas Soome
4943830659eSToomas Soome case DATA_TYPE_UINT64:
495e307eb94SToomas Soome if (!xdr_uint64(xdr, (uint64_t *)&nvp_data->nv_data[0]))
496e307eb94SToomas Soome return (false);
4973830659eSToomas Soome break;
4983830659eSToomas Soome
499e307eb94SToomas Soome case DATA_TYPE_BYTE_ARRAY:
5003830659eSToomas Soome case DATA_TYPE_STRING:
5013830659eSToomas Soome nv_string = (nv_string_t *)&nvp_data->nv_data[0];
502e307eb94SToomas Soome if (!xdr_string(xdr, nv_string))
503e307eb94SToomas Soome return (false);
504e307eb94SToomas Soome break;
5053830659eSToomas Soome
506e307eb94SToomas Soome case DATA_TYPE_STRING_ARRAY:
507e307eb94SToomas Soome nv_string = (nv_string_t *)&nvp_data->nv_data[0];
508e307eb94SToomas Soome for (unsigned i = 0; i < nelem; i++) {
509e307eb94SToomas Soome if (!xdr_string(xdr, nv_string))
510e307eb94SToomas Soome return (false);
511e307eb94SToomas Soome nv_string = (nv_string_t *)xdr->xdr_idx;
512e307eb94SToomas Soome }
513e307eb94SToomas Soome break;
514e307eb94SToomas Soome
515e307eb94SToomas Soome case DATA_TYPE_INT8_ARRAY:
516e307eb94SToomas Soome case DATA_TYPE_UINT8_ARRAY:
517e307eb94SToomas Soome case DATA_TYPE_INT16_ARRAY:
518e307eb94SToomas Soome case DATA_TYPE_UINT16_ARRAY:
519e307eb94SToomas Soome case DATA_TYPE_BOOLEAN_ARRAY:
520e307eb94SToomas Soome case DATA_TYPE_INT32_ARRAY:
521e307eb94SToomas Soome case DATA_TYPE_UINT32_ARRAY:
522e307eb94SToomas Soome if (!xdr_array(xdr, nelem, (xdrproc_t)xdr_u_int))
523e307eb94SToomas Soome return (false);
524e307eb94SToomas Soome break;
525e307eb94SToomas Soome
526e307eb94SToomas Soome case DATA_TYPE_INT64_ARRAY:
527e307eb94SToomas Soome case DATA_TYPE_UINT64_ARRAY:
528e307eb94SToomas Soome if (!xdr_array(xdr, nelem, (xdrproc_t)xdr_uint64))
529e307eb94SToomas Soome return (false);
5303830659eSToomas Soome break;
5313830659eSToomas Soome }
532e307eb94SToomas Soome return (true);
5333830659eSToomas Soome }
5343830659eSToomas Soome
5353830659eSToomas Soome static int
nvlist_xdr_nvlist(xdr_t * xdr,nvlist_t * nvl)536e307eb94SToomas Soome nvlist_xdr_nvlist(xdr_t *xdr, nvlist_t *nvl)
5373830659eSToomas Soome {
538e307eb94SToomas Soome nvp_header_t *nvph;
539e307eb94SToomas Soome nvs_data_t *nvs;
540e307eb94SToomas Soome unsigned encoded_size, decoded_size;
541e307eb94SToomas Soome int rv;
542e307eb94SToomas Soome
543e307eb94SToomas Soome nvs = (nvs_data_t *)xdr->xdr_idx;
544e307eb94SToomas Soome nvph = &nvs->nvl_pair;
545e307eb94SToomas Soome
546e307eb94SToomas Soome if (!xdr_u_int(xdr, &nvs->nvl_version))
547e307eb94SToomas Soome return (EINVAL);
548e307eb94SToomas Soome if (!xdr_u_int(xdr, &nvs->nvl_nvflag))
549e307eb94SToomas Soome return (EINVAL);
550e307eb94SToomas Soome
551e307eb94SToomas Soome encoded_size = nvph->encoded_size;
552e307eb94SToomas Soome decoded_size = nvph->decoded_size;
553e307eb94SToomas Soome
554e307eb94SToomas Soome if (xdr->xdr_op == XDR_OP_ENCODE) {
555e307eb94SToomas Soome if (!xdr_u_int(xdr, &nvph->encoded_size))
556e307eb94SToomas Soome return (EINVAL);
557e307eb94SToomas Soome if (!xdr_u_int(xdr, &nvph->decoded_size))
558e307eb94SToomas Soome return (EINVAL);
559e307eb94SToomas Soome } else {
560e307eb94SToomas Soome xdr->xdr_idx += 2 * sizeof(unsigned);
561e307eb94SToomas Soome }
562e307eb94SToomas Soome
563e307eb94SToomas Soome rv = 0;
564e307eb94SToomas Soome while (encoded_size && decoded_size) {
565e307eb94SToomas Soome if (!nvlist_xdr_nvp(xdr, nvl))
566e307eb94SToomas Soome return (EINVAL);
567e307eb94SToomas Soome
568e307eb94SToomas Soome nvph = (nvp_header_t *)(xdr->xdr_idx);
569e307eb94SToomas Soome encoded_size = nvph->encoded_size;
570e307eb94SToomas Soome decoded_size = nvph->decoded_size;
571e307eb94SToomas Soome if (xdr->xdr_op == XDR_OP_ENCODE) {
572e307eb94SToomas Soome if (!xdr_u_int(xdr, &nvph->encoded_size))
573e307eb94SToomas Soome return (EINVAL);
574e307eb94SToomas Soome if (!xdr_u_int(xdr, &nvph->decoded_size))
575e307eb94SToomas Soome return (EINVAL);
576e307eb94SToomas Soome } else {
577e307eb94SToomas Soome xdr->xdr_idx += 2 * sizeof(unsigned);
578e307eb94SToomas Soome }
579e307eb94SToomas Soome }
580e307eb94SToomas Soome return (rv);
581e307eb94SToomas Soome }
582e307eb94SToomas Soome
583e307eb94SToomas Soome /*
584e307eb94SToomas Soome * Calculate nvlist size, translating encoded_size and decoded_size.
585e307eb94SToomas Soome */
586e307eb94SToomas Soome static bool
nvlist_size_xdr(xdr_t * xdr,size_t * size)587e307eb94SToomas Soome nvlist_size_xdr(xdr_t *xdr, size_t *size)
588e307eb94SToomas Soome {
589e307eb94SToomas Soome uint8_t *pair;
5903830659eSToomas Soome unsigned encoded_size, decoded_size;
5913830659eSToomas Soome
592e307eb94SToomas Soome xdr->xdr_idx += 2 * sizeof(unsigned);
5933830659eSToomas Soome
594e307eb94SToomas Soome pair = xdr->xdr_idx;
595e307eb94SToomas Soome if (!xdr_u_int(xdr, &encoded_size) || !xdr_u_int(xdr, &decoded_size))
596e307eb94SToomas Soome return (false);
597e307eb94SToomas Soome
5983830659eSToomas Soome while (encoded_size && decoded_size) {
599e307eb94SToomas Soome xdr->xdr_idx = pair + encoded_size;
600e307eb94SToomas Soome pair = xdr->xdr_idx;
601e307eb94SToomas Soome if (!xdr_u_int(xdr, &encoded_size) ||
602e307eb94SToomas Soome !xdr_u_int(xdr, &decoded_size))
603e307eb94SToomas Soome return (false);
6043830659eSToomas Soome }
605e307eb94SToomas Soome *size = xdr->xdr_idx - xdr->xdr_buf;
606e307eb94SToomas Soome
607e307eb94SToomas Soome return (true);
608e307eb94SToomas Soome }
609e307eb94SToomas Soome
610e307eb94SToomas Soome nvp_header_t *
nvlist_next_nvpair(nvlist_t * nvl,nvp_header_t * nvh)611e307eb94SToomas Soome nvlist_next_nvpair(nvlist_t *nvl, nvp_header_t *nvh)
612e307eb94SToomas Soome {
613e307eb94SToomas Soome uint8_t *pair;
614e307eb94SToomas Soome unsigned encoded_size, decoded_size;
615e307eb94SToomas Soome xdr_t xdr;
616e307eb94SToomas Soome
617e307eb94SToomas Soome if (nvl == NULL)
618e307eb94SToomas Soome return (NULL);
619e307eb94SToomas Soome
620e307eb94SToomas Soome xdr.xdr_buf = nvl->nv_data;
621e307eb94SToomas Soome xdr.xdr_idx = nvl->nv_data;
622e307eb94SToomas Soome xdr.xdr_buf_size = nvl->nv_size;
623e307eb94SToomas Soome
624e307eb94SToomas Soome xdr.xdr_idx += 2 * sizeof(unsigned);
625e307eb94SToomas Soome
626e307eb94SToomas Soome /* Skip tp current pair */
627e307eb94SToomas Soome if (nvh != NULL) {
628e307eb94SToomas Soome xdr.xdr_idx = (uint8_t *)nvh;
629e307eb94SToomas Soome }
630e307eb94SToomas Soome
631e307eb94SToomas Soome pair = xdr.xdr_idx;
632e307eb94SToomas Soome if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
633e307eb94SToomas Soome return (NULL);
634e307eb94SToomas Soome
635e307eb94SToomas Soome encoded_size = *(unsigned *)xdr.xdr_idx;
636e307eb94SToomas Soome xdr.xdr_idx += sizeof(unsigned);
637e307eb94SToomas Soome if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
638e307eb94SToomas Soome return (NULL);
639e307eb94SToomas Soome
640e307eb94SToomas Soome decoded_size = *(unsigned *)xdr.xdr_idx;
641e307eb94SToomas Soome xdr.xdr_idx += sizeof(unsigned);
642e307eb94SToomas Soome if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
643e307eb94SToomas Soome return (NULL);
644e307eb94SToomas Soome
645e307eb94SToomas Soome while (encoded_size && decoded_size) {
646e307eb94SToomas Soome if (nvh == NULL)
647e307eb94SToomas Soome return ((nvp_header_t *)pair);
648e307eb94SToomas Soome
649e307eb94SToomas Soome xdr.xdr_idx = pair + encoded_size;
650e307eb94SToomas Soome nvh = (nvp_header_t *)xdr.xdr_idx;
651e307eb94SToomas Soome
652e307eb94SToomas Soome if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
653e307eb94SToomas Soome return (NULL);
654e307eb94SToomas Soome
655e307eb94SToomas Soome encoded_size = *(unsigned *)xdr.xdr_idx;
656e307eb94SToomas Soome xdr.xdr_idx += sizeof(unsigned);
657e307eb94SToomas Soome if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
658e307eb94SToomas Soome return (NULL);
659e307eb94SToomas Soome decoded_size = *(unsigned *)xdr.xdr_idx;
660e307eb94SToomas Soome xdr.xdr_idx += sizeof(unsigned);
661e307eb94SToomas Soome if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
662e307eb94SToomas Soome return (NULL);
663e307eb94SToomas Soome
664e307eb94SToomas Soome if (encoded_size != 0 && decoded_size != 0) {
665e307eb94SToomas Soome return (nvh);
666e307eb94SToomas Soome }
667e307eb94SToomas Soome }
668e307eb94SToomas Soome return (NULL);
669e307eb94SToomas Soome }
670e307eb94SToomas Soome
671e307eb94SToomas Soome /*
672e307eb94SToomas Soome * Calculate nvlist size by walking in memory data.
673e307eb94SToomas Soome */
674e307eb94SToomas Soome static bool
nvlist_size_native(xdr_t * xdr,size_t * size)675e307eb94SToomas Soome nvlist_size_native(xdr_t *xdr, size_t *size)
676e307eb94SToomas Soome {
677e307eb94SToomas Soome uint8_t *pair;
678e307eb94SToomas Soome unsigned encoded_size, decoded_size;
679e307eb94SToomas Soome
680e307eb94SToomas Soome xdr->xdr_idx += 2 * sizeof(unsigned);
681e307eb94SToomas Soome
682e307eb94SToomas Soome pair = xdr->xdr_idx;
683e307eb94SToomas Soome if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
684e307eb94SToomas Soome return (false);
685e307eb94SToomas Soome
686e307eb94SToomas Soome encoded_size = *(unsigned *)xdr->xdr_idx;
687e307eb94SToomas Soome xdr->xdr_idx += sizeof(unsigned);
688e307eb94SToomas Soome if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
689e307eb94SToomas Soome return (false);
690e307eb94SToomas Soome decoded_size = *(unsigned *)xdr->xdr_idx;
691e307eb94SToomas Soome xdr->xdr_idx += sizeof(unsigned);
692e307eb94SToomas Soome while (encoded_size && decoded_size) {
693e307eb94SToomas Soome xdr->xdr_idx = pair + encoded_size;
694e307eb94SToomas Soome pair = xdr->xdr_idx;
695e307eb94SToomas Soome if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
696e307eb94SToomas Soome return (false);
697e307eb94SToomas Soome encoded_size = *(unsigned *)xdr->xdr_idx;
698e307eb94SToomas Soome xdr->xdr_idx += sizeof(unsigned);
699e307eb94SToomas Soome if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
700e307eb94SToomas Soome return (false);
701e307eb94SToomas Soome decoded_size = *(unsigned *)xdr->xdr_idx;
702e307eb94SToomas Soome xdr->xdr_idx += sizeof(unsigned);
703e307eb94SToomas Soome }
704e307eb94SToomas Soome *size = xdr->xdr_idx - xdr->xdr_buf;
705e307eb94SToomas Soome
706e307eb94SToomas Soome return (true);
707e307eb94SToomas Soome }
708e307eb94SToomas Soome
709e307eb94SToomas Soome /*
710e307eb94SToomas Soome * Export nvlist to byte stream format.
711e307eb94SToomas Soome */
712e307eb94SToomas Soome int
nvlist_export(nvlist_t * nvl)713e307eb94SToomas Soome nvlist_export(nvlist_t *nvl)
714e307eb94SToomas Soome {
715e307eb94SToomas Soome int rv;
716e307eb94SToomas Soome xdr_t xdr = {
717e307eb94SToomas Soome .xdr_op = XDR_OP_ENCODE,
718e307eb94SToomas Soome .xdr_putint = _putint,
719e307eb94SToomas Soome .xdr_putuint = _putuint,
720e307eb94SToomas Soome .xdr_buf = nvl->nv_data,
721e307eb94SToomas Soome .xdr_idx = nvl->nv_data,
722e307eb94SToomas Soome .xdr_buf_size = nvl->nv_size
723e307eb94SToomas Soome };
724e307eb94SToomas Soome
725e307eb94SToomas Soome if (nvl->nv_header.nvh_encoding != NV_ENCODE_XDR)
726e307eb94SToomas Soome return (ENOTSUP);
727e307eb94SToomas Soome
728e307eb94SToomas Soome nvl->nv_idx = nvl->nv_data;
729e307eb94SToomas Soome rv = nvlist_xdr_nvlist(&xdr, nvl);
730e307eb94SToomas Soome
731e307eb94SToomas Soome return (rv);
7323830659eSToomas Soome }
7333830659eSToomas Soome
7343830659eSToomas Soome /*
7353830659eSToomas Soome * Import nvlist from byte stream.
7363830659eSToomas Soome * Determine the stream size and allocate private copy.
7373830659eSToomas Soome * Then translate the data.
7383830659eSToomas Soome */
7393830659eSToomas Soome nvlist_t *
nvlist_import(const char * stream,size_t size)740e307eb94SToomas Soome nvlist_import(const char *stream, size_t size)
7413830659eSToomas Soome {
7423830659eSToomas Soome nvlist_t *nvl;
743e307eb94SToomas Soome xdr_t xdr = {
744e307eb94SToomas Soome .xdr_op = XDR_OP_DECODE,
745e307eb94SToomas Soome .xdr_getint = _getint,
746e307eb94SToomas Soome .xdr_getuint = _getuint
747e307eb94SToomas Soome };
7483830659eSToomas Soome
749e307eb94SToomas Soome /* Check the nvlist head. */
750e307eb94SToomas Soome if (stream[0] != NV_ENCODE_XDR ||
751e307eb94SToomas Soome (stream[1] != '\0' && stream[1] != '\1') ||
752e307eb94SToomas Soome stream[2] != '\0' || stream[3] != '\0' ||
753e307eb94SToomas Soome be32toh(*(uint32_t *)(stream + 4)) != NV_VERSION ||
754e307eb94SToomas Soome be32toh(*(uint32_t *)(stream + 8)) != NV_UNIQUE_NAME)
7553830659eSToomas Soome return (NULL);
7563830659eSToomas Soome
7573830659eSToomas Soome nvl = malloc(sizeof(*nvl));
7583830659eSToomas Soome if (nvl == NULL)
7593830659eSToomas Soome return (nvl);
7603830659eSToomas Soome
761e307eb94SToomas Soome nvl->nv_header.nvh_encoding = stream[0];
762e307eb94SToomas Soome nvl->nv_header.nvh_endian = stream[1];
763e307eb94SToomas Soome nvl->nv_header.nvh_reserved1 = stream[2];
764e307eb94SToomas Soome nvl->nv_header.nvh_reserved2 = stream[3];
765e307eb94SToomas Soome
766e307eb94SToomas Soome xdr.xdr_buf = xdr.xdr_idx = (uint8_t *)stream + 4;
767e307eb94SToomas Soome xdr.xdr_buf_size = size - 4;
768e307eb94SToomas Soome
769e307eb94SToomas Soome if (!nvlist_size_xdr(&xdr, &nvl->nv_asize)) {
770e307eb94SToomas Soome free(nvl);
771e307eb94SToomas Soome return (NULL);
772e307eb94SToomas Soome }
773e307eb94SToomas Soome nvl->nv_size = nvl->nv_asize;
7743830659eSToomas Soome nvl->nv_data = malloc(nvl->nv_asize);
7753830659eSToomas Soome if (nvl->nv_data == NULL) {
7763830659eSToomas Soome free(nvl);
7773830659eSToomas Soome return (NULL);
7783830659eSToomas Soome }
7793830659eSToomas Soome nvl->nv_idx = nvl->nv_data;
780e307eb94SToomas Soome bcopy(stream + 4, nvl->nv_data, nvl->nv_asize);
7813830659eSToomas Soome
782e307eb94SToomas Soome xdr.xdr_buf = xdr.xdr_idx = nvl->nv_data;
783e307eb94SToomas Soome xdr.xdr_buf_size = nvl->nv_asize;
784e307eb94SToomas Soome
785e307eb94SToomas Soome if (nvlist_xdr_nvlist(&xdr, nvl) != 0) {
786e307eb94SToomas Soome free(nvl->nv_data);
787e307eb94SToomas Soome free(nvl);
788e307eb94SToomas Soome nvl = NULL;
789e307eb94SToomas Soome }
790e307eb94SToomas Soome
7913830659eSToomas Soome return (nvl);
7923830659eSToomas Soome }
7933830659eSToomas Soome
7943830659eSToomas Soome /*
7953830659eSToomas Soome * remove pair from this nvlist.
7963830659eSToomas Soome */
7973830659eSToomas Soome int
nvlist_remove(nvlist_t * nvl,const char * name,data_type_t type)7983830659eSToomas Soome nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type)
7993830659eSToomas Soome {
8003830659eSToomas Soome uint8_t *head, *tail;
8013830659eSToomas Soome nvs_data_t *data;
8023830659eSToomas Soome nvp_header_t *nvp;
8033830659eSToomas Soome nv_string_t *nvp_name;
8043830659eSToomas Soome nv_pair_data_t *nvp_data;
8053830659eSToomas Soome size_t size;
806e307eb94SToomas Soome xdr_t xdr;
8073830659eSToomas Soome
8083830659eSToomas Soome if (nvl == NULL || nvl->nv_data == NULL || name == NULL)
8093830659eSToomas Soome return (EINVAL);
8103830659eSToomas Soome
811e307eb94SToomas Soome /* Make sure the nvlist size is set correct */
812e307eb94SToomas Soome xdr.xdr_idx = nvl->nv_data;
813e307eb94SToomas Soome xdr.xdr_buf = xdr.xdr_idx;
814e307eb94SToomas Soome xdr.xdr_buf_size = nvl->nv_size;
815e307eb94SToomas Soome if (!nvlist_size_native(&xdr, &nvl->nv_size))
816e307eb94SToomas Soome return (EINVAL);
817e307eb94SToomas Soome
818e307eb94SToomas Soome data = (nvs_data_t *)nvl->nv_data;
8193830659eSToomas Soome nvp = &data->nvl_pair; /* first pair in nvlist */
8203830659eSToomas Soome head = (uint8_t *)nvp;
8213830659eSToomas Soome
8223830659eSToomas Soome while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
823e307eb94SToomas Soome nvp_name = (nv_string_t *)(nvp + 1);
8243830659eSToomas Soome
825e307eb94SToomas Soome nvp_data = (nv_pair_data_t *)(&nvp_name->nv_data[0] +
826e307eb94SToomas Soome NV_ALIGN4(nvp_name->nv_size));
8273830659eSToomas Soome
828e307eb94SToomas Soome if (strlen(name) == nvp_name->nv_size &&
829e307eb94SToomas Soome memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 &&
830e307eb94SToomas Soome (nvp_data->nv_type == type || type == DATA_TYPE_UNKNOWN)) {
8313830659eSToomas Soome /*
8323830659eSToomas Soome * set tail to point to next nvpair and size
8333830659eSToomas Soome * is the length of the tail.
8343830659eSToomas Soome */
8353830659eSToomas Soome tail = head + nvp->encoded_size;
836e307eb94SToomas Soome size = nvl->nv_size - (tail - nvl->nv_data);
8373830659eSToomas Soome
8383830659eSToomas Soome /* adjust the size of the nvlist. */
8393830659eSToomas Soome nvl->nv_size -= nvp->encoded_size;
8403830659eSToomas Soome bcopy(tail, head, size);
8413830659eSToomas Soome return (0);
8423830659eSToomas Soome }
8433830659eSToomas Soome /* Not our pair, skip to next. */
8443830659eSToomas Soome head = head + nvp->encoded_size;
8453830659eSToomas Soome nvp = (nvp_header_t *)head;
8463830659eSToomas Soome }
8473830659eSToomas Soome return (ENOENT);
8483830659eSToomas Soome }
8493830659eSToomas Soome
850e307eb94SToomas Soome static int
clone_nvlist(const nvlist_t * nvl,const uint8_t * ptr,unsigned size,nvlist_t ** nvlist)851e307eb94SToomas Soome clone_nvlist(const nvlist_t *nvl, const uint8_t *ptr, unsigned size,
852e307eb94SToomas Soome nvlist_t **nvlist)
853e307eb94SToomas Soome {
854e307eb94SToomas Soome nvlist_t *nv;
855e307eb94SToomas Soome
856e307eb94SToomas Soome nv = calloc(1, sizeof(*nv));
857e307eb94SToomas Soome if (nv == NULL)
858e307eb94SToomas Soome return (ENOMEM);
859e307eb94SToomas Soome
860e307eb94SToomas Soome nv->nv_header = nvl->nv_header;
861e307eb94SToomas Soome nv->nv_asize = size;
862e307eb94SToomas Soome nv->nv_size = size;
863e307eb94SToomas Soome nv->nv_data = malloc(nv->nv_asize);
864e307eb94SToomas Soome if (nv->nv_data == NULL) {
865e307eb94SToomas Soome free(nv);
866e307eb94SToomas Soome return (ENOMEM);
867e307eb94SToomas Soome }
868e307eb94SToomas Soome
869e307eb94SToomas Soome bcopy(ptr, nv->nv_data, nv->nv_asize);
870e307eb94SToomas Soome *nvlist = nv;
871e307eb94SToomas Soome return (0);
872e307eb94SToomas Soome }
873e307eb94SToomas Soome
874e307eb94SToomas Soome /*
875e307eb94SToomas Soome * Return the next nvlist in an nvlist array.
876e307eb94SToomas Soome */
877e307eb94SToomas Soome static uint8_t *
nvlist_next(const uint8_t * ptr)878e307eb94SToomas Soome nvlist_next(const uint8_t *ptr)
879e307eb94SToomas Soome {
880e307eb94SToomas Soome nvs_data_t *data;
881e307eb94SToomas Soome nvp_header_t *nvp;
882e307eb94SToomas Soome
883e307eb94SToomas Soome data = (nvs_data_t *)ptr;
884e307eb94SToomas Soome nvp = &data->nvl_pair; /* first pair in nvlist */
885e307eb94SToomas Soome
886e307eb94SToomas Soome while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
887e307eb94SToomas Soome nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size);
888e307eb94SToomas Soome }
889e307eb94SToomas Soome return ((uint8_t *)nvp + sizeof(*nvp));
890e307eb94SToomas Soome }
891e307eb94SToomas Soome
892e307eb94SToomas Soome /*
893e307eb94SToomas Soome * Note: nvlist and nvlist array must be freed by caller.
894e307eb94SToomas Soome */
8953830659eSToomas Soome int
nvlist_find(const nvlist_t * nvl,const char * name,data_type_t type,int * elementsp,void * valuep,int * sizep)8963830659eSToomas Soome nvlist_find(const nvlist_t *nvl, const char *name, data_type_t type,
8973830659eSToomas Soome int *elementsp, void *valuep, int *sizep)
8983830659eSToomas Soome {
8993830659eSToomas Soome nvs_data_t *data;
9003830659eSToomas Soome nvp_header_t *nvp;
9013830659eSToomas Soome nv_string_t *nvp_name;
9023830659eSToomas Soome nv_pair_data_t *nvp_data;
903e307eb94SToomas Soome nvlist_t **nvlist, *nv;
904e307eb94SToomas Soome uint8_t *ptr;
905e307eb94SToomas Soome int rv;
9063830659eSToomas Soome
9073830659eSToomas Soome if (nvl == NULL || nvl->nv_data == NULL || name == NULL)
9083830659eSToomas Soome return (EINVAL);
9093830659eSToomas Soome
9103830659eSToomas Soome data = (nvs_data_t *)nvl->nv_data;
9113830659eSToomas Soome nvp = &data->nvl_pair; /* first pair in nvlist */
9123830659eSToomas Soome
9133830659eSToomas Soome while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
9143830659eSToomas Soome nvp_name = (nv_string_t *)((uint8_t *)nvp + sizeof(*nvp));
915e307eb94SToomas Soome if (nvl->nv_data + nvl->nv_size <
916e307eb94SToomas Soome nvp_name->nv_data + nvp_name->nv_size)
917e307eb94SToomas Soome return (EIO);
9183830659eSToomas Soome
9193830659eSToomas Soome nvp_data = (nv_pair_data_t *)
9203830659eSToomas Soome NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] +
9213830659eSToomas Soome nvp_name->nv_size);
9223830659eSToomas Soome
923e307eb94SToomas Soome if (strlen(name) == nvp_name->nv_size &&
924e307eb94SToomas Soome memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 &&
925e307eb94SToomas Soome (nvp_data->nv_type == type || type == DATA_TYPE_UNKNOWN)) {
9263830659eSToomas Soome if (elementsp != NULL)
9273830659eSToomas Soome *elementsp = nvp_data->nv_nelem;
9283830659eSToomas Soome switch (nvp_data->nv_type) {
9293830659eSToomas Soome case DATA_TYPE_UINT64:
930e307eb94SToomas Soome bcopy(nvp_data->nv_data, valuep,
931e307eb94SToomas Soome sizeof(uint64_t));
9323830659eSToomas Soome return (0);
9333830659eSToomas Soome case DATA_TYPE_STRING:
9343830659eSToomas Soome nvp_name = (nv_string_t *)nvp_data->nv_data;
9353830659eSToomas Soome if (sizep != NULL) {
9363830659eSToomas Soome *sizep = nvp_name->nv_size;
9373830659eSToomas Soome }
9383830659eSToomas Soome *(const uint8_t **)valuep =
9393830659eSToomas Soome &nvp_name->nv_data[0];
9403830659eSToomas Soome return (0);
9413830659eSToomas Soome case DATA_TYPE_NVLIST:
942e307eb94SToomas Soome ptr = &nvp_data->nv_data[0];
943e307eb94SToomas Soome rv = clone_nvlist(nvl, ptr,
944e307eb94SToomas Soome nvlist_next(ptr) - ptr, &nv);
945e307eb94SToomas Soome if (rv == 0) {
946e307eb94SToomas Soome *(nvlist_t **)valuep = nv;
9473830659eSToomas Soome }
948e307eb94SToomas Soome return (rv);
949e307eb94SToomas Soome
950e307eb94SToomas Soome case DATA_TYPE_NVLIST_ARRAY:
951e307eb94SToomas Soome nvlist = calloc(nvp_data->nv_nelem,
952e307eb94SToomas Soome sizeof(nvlist_t *));
953e307eb94SToomas Soome if (nvlist == NULL)
9543830659eSToomas Soome return (ENOMEM);
955e307eb94SToomas Soome ptr = &nvp_data->nv_data[0];
956e307eb94SToomas Soome rv = 0;
957e307eb94SToomas Soome for (unsigned i = 0; i < nvp_data->nv_nelem;
958e307eb94SToomas Soome i++) {
959e307eb94SToomas Soome rv = clone_nvlist(nvl, ptr,
960e307eb94SToomas Soome nvlist_next(ptr) - ptr, &nvlist[i]);
961e307eb94SToomas Soome if (rv != 0)
962e307eb94SToomas Soome goto error;
963e307eb94SToomas Soome ptr = nvlist_next(ptr);
964e307eb94SToomas Soome }
965e307eb94SToomas Soome *(nvlist_t ***)valuep = nvlist;
966e307eb94SToomas Soome return (rv);
9673830659eSToomas Soome }
9683830659eSToomas Soome return (EIO);
9693830659eSToomas Soome }
9703830659eSToomas Soome /* Not our pair, skip to next. */
9713830659eSToomas Soome nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size);
972e307eb94SToomas Soome if (nvl->nv_data + nvl->nv_size < (uint8_t *)nvp)
973e307eb94SToomas Soome return (EIO);
9743830659eSToomas Soome }
9753830659eSToomas Soome return (ENOENT);
976e307eb94SToomas Soome error:
977e307eb94SToomas Soome for (unsigned i = 0; i < nvp_data->nv_nelem; i++) {
978e307eb94SToomas Soome free(nvlist[i]->nv_data);
979e307eb94SToomas Soome free(nvlist[i]);
980e307eb94SToomas Soome }
981e307eb94SToomas Soome free(nvlist);
982e307eb94SToomas Soome return (rv);
9833830659eSToomas Soome }
9843830659eSToomas Soome
985e307eb94SToomas Soome static int
get_value_size(data_type_t type,const void * data,uint32_t nelem)986e307eb94SToomas Soome get_value_size(data_type_t type, const void *data, uint32_t nelem)
9873830659eSToomas Soome {
988e307eb94SToomas Soome uint64_t value_sz = 0;
9893830659eSToomas Soome
990e307eb94SToomas Soome switch (type) {
991e307eb94SToomas Soome case DATA_TYPE_BOOLEAN:
992e307eb94SToomas Soome value_sz = 0;
993e307eb94SToomas Soome break;
994e307eb94SToomas Soome case DATA_TYPE_BOOLEAN_VALUE:
995e307eb94SToomas Soome case DATA_TYPE_BYTE:
996e307eb94SToomas Soome case DATA_TYPE_INT8:
997e307eb94SToomas Soome case DATA_TYPE_UINT8:
998e307eb94SToomas Soome case DATA_TYPE_INT16:
999e307eb94SToomas Soome case DATA_TYPE_UINT16:
1000e307eb94SToomas Soome case DATA_TYPE_INT32:
1001e307eb94SToomas Soome case DATA_TYPE_UINT32:
1002e307eb94SToomas Soome /* Our smallest data unit is 32-bit */
1003e307eb94SToomas Soome value_sz = sizeof(uint32_t);
1004e307eb94SToomas Soome break;
1005e307eb94SToomas Soome case DATA_TYPE_HRTIME:
1006e307eb94SToomas Soome case DATA_TYPE_INT64:
1007e307eb94SToomas Soome value_sz = sizeof(int64_t);
1008e307eb94SToomas Soome break;
1009e307eb94SToomas Soome case DATA_TYPE_UINT64:
1010e307eb94SToomas Soome value_sz = sizeof(uint64_t);
1011e307eb94SToomas Soome break;
1012e307eb94SToomas Soome case DATA_TYPE_STRING:
1013e307eb94SToomas Soome if (data == NULL)
1014e307eb94SToomas Soome value_sz = 0;
1015e307eb94SToomas Soome else
1016e307eb94SToomas Soome value_sz = strlen(data) + 1;
1017e307eb94SToomas Soome break;
1018e307eb94SToomas Soome case DATA_TYPE_BYTE_ARRAY:
1019e307eb94SToomas Soome value_sz = nelem * sizeof(uint8_t);
1020e307eb94SToomas Soome break;
1021e307eb94SToomas Soome case DATA_TYPE_BOOLEAN_ARRAY:
1022e307eb94SToomas Soome case DATA_TYPE_INT8_ARRAY:
1023e307eb94SToomas Soome case DATA_TYPE_UINT8_ARRAY:
1024e307eb94SToomas Soome case DATA_TYPE_INT16_ARRAY:
1025e307eb94SToomas Soome case DATA_TYPE_UINT16_ARRAY:
1026e307eb94SToomas Soome case DATA_TYPE_INT32_ARRAY:
1027e307eb94SToomas Soome case DATA_TYPE_UINT32_ARRAY:
1028e307eb94SToomas Soome value_sz = (uint64_t)nelem * sizeof(uint32_t);
1029e307eb94SToomas Soome break;
1030e307eb94SToomas Soome case DATA_TYPE_INT64_ARRAY:
1031e307eb94SToomas Soome value_sz = (uint64_t)nelem * sizeof(int64_t);
1032e307eb94SToomas Soome break;
1033e307eb94SToomas Soome case DATA_TYPE_UINT64_ARRAY:
1034e307eb94SToomas Soome value_sz = (uint64_t)nelem * sizeof(uint64_t);
1035e307eb94SToomas Soome break;
1036e307eb94SToomas Soome case DATA_TYPE_STRING_ARRAY:
1037e307eb94SToomas Soome value_sz = (uint64_t)nelem * sizeof(uint64_t);
1038e307eb94SToomas Soome
1039e307eb94SToomas Soome if (data != NULL) {
1040e307eb94SToomas Soome char *const *strs = data;
1041e307eb94SToomas Soome uint32_t i;
1042e307eb94SToomas Soome
1043e307eb94SToomas Soome for (i = 0; i < nelem; i++) {
1044e307eb94SToomas Soome if (strs[i] == NULL)
1045e307eb94SToomas Soome return (-1);
1046e307eb94SToomas Soome value_sz += strlen(strs[i]) + 1;
1047e307eb94SToomas Soome }
1048e307eb94SToomas Soome }
1049e307eb94SToomas Soome break;
1050e307eb94SToomas Soome case DATA_TYPE_NVLIST:
1051e307eb94SToomas Soome /*
1052e307eb94SToomas Soome * The decoded size of nvlist is constant.
1053e307eb94SToomas Soome */
1054e307eb94SToomas Soome value_sz = NV_ALIGN(6 * 4); /* sizeof nvlist_t */
1055e307eb94SToomas Soome break;
1056e307eb94SToomas Soome case DATA_TYPE_NVLIST_ARRAY:
1057e307eb94SToomas Soome value_sz = (uint64_t)nelem * sizeof(uint64_t) +
1058e307eb94SToomas Soome (uint64_t)nelem * NV_ALIGN(6 * 4); /* sizeof nvlist_t */
1059e307eb94SToomas Soome break;
1060e307eb94SToomas Soome default:
1061e307eb94SToomas Soome return (-1);
1062e307eb94SToomas Soome }
1063e307eb94SToomas Soome
1064e307eb94SToomas Soome return (value_sz > INT32_MAX ? -1 : (int)value_sz);
1065e307eb94SToomas Soome }
1066e307eb94SToomas Soome
1067e307eb94SToomas Soome static int
get_nvp_data_size(data_type_t type,const void * data,uint32_t nelem)1068e307eb94SToomas Soome get_nvp_data_size(data_type_t type, const void *data, uint32_t nelem)
1069e307eb94SToomas Soome {
1070e307eb94SToomas Soome uint64_t value_sz = 0;
1071e307eb94SToomas Soome xdr_t xdr;
1072e307eb94SToomas Soome size_t size;
1073e307eb94SToomas Soome
1074e307eb94SToomas Soome switch (type) {
1075e307eb94SToomas Soome case DATA_TYPE_BOOLEAN:
1076e307eb94SToomas Soome value_sz = 0;
1077e307eb94SToomas Soome break;
1078e307eb94SToomas Soome case DATA_TYPE_BOOLEAN_VALUE:
1079e307eb94SToomas Soome case DATA_TYPE_BYTE:
1080e307eb94SToomas Soome case DATA_TYPE_INT8:
1081e307eb94SToomas Soome case DATA_TYPE_UINT8:
1082e307eb94SToomas Soome case DATA_TYPE_INT16:
1083e307eb94SToomas Soome case DATA_TYPE_UINT16:
1084e307eb94SToomas Soome case DATA_TYPE_INT32:
1085e307eb94SToomas Soome case DATA_TYPE_UINT32:
1086e307eb94SToomas Soome /* Our smallest data unit is 32-bit */
1087e307eb94SToomas Soome value_sz = sizeof(uint32_t);
1088e307eb94SToomas Soome break;
1089e307eb94SToomas Soome case DATA_TYPE_HRTIME:
1090e307eb94SToomas Soome case DATA_TYPE_INT64:
1091e307eb94SToomas Soome case DATA_TYPE_UINT64:
1092e307eb94SToomas Soome value_sz = sizeof(uint64_t);
1093e307eb94SToomas Soome break;
1094e307eb94SToomas Soome case DATA_TYPE_STRING:
1095e307eb94SToomas Soome value_sz = 4 + NV_ALIGN4(strlen(data));
1096e307eb94SToomas Soome break;
1097e307eb94SToomas Soome case DATA_TYPE_BYTE_ARRAY:
1098e307eb94SToomas Soome value_sz = NV_ALIGN4(nelem);
1099e307eb94SToomas Soome break;
1100e307eb94SToomas Soome case DATA_TYPE_BOOLEAN_ARRAY:
1101e307eb94SToomas Soome case DATA_TYPE_INT8_ARRAY:
1102e307eb94SToomas Soome case DATA_TYPE_UINT8_ARRAY:
1103e307eb94SToomas Soome case DATA_TYPE_INT16_ARRAY:
1104e307eb94SToomas Soome case DATA_TYPE_UINT16_ARRAY:
1105e307eb94SToomas Soome case DATA_TYPE_INT32_ARRAY:
1106e307eb94SToomas Soome case DATA_TYPE_UINT32_ARRAY:
1107e307eb94SToomas Soome value_sz = 4 + (uint64_t)nelem * sizeof(uint32_t);
1108e307eb94SToomas Soome break;
1109e307eb94SToomas Soome case DATA_TYPE_INT64_ARRAY:
1110e307eb94SToomas Soome case DATA_TYPE_UINT64_ARRAY:
1111e307eb94SToomas Soome value_sz = 4 + (uint64_t)nelem * sizeof(uint64_t);
1112e307eb94SToomas Soome break;
1113e307eb94SToomas Soome case DATA_TYPE_STRING_ARRAY:
1114e307eb94SToomas Soome if (data != NULL) {
1115e307eb94SToomas Soome char *const *strs = data;
1116e307eb94SToomas Soome uint32_t i;
1117e307eb94SToomas Soome
1118e307eb94SToomas Soome for (i = 0; i < nelem; i++) {
1119e307eb94SToomas Soome value_sz += 4 + NV_ALIGN4(strlen(strs[i]));
1120e307eb94SToomas Soome }
1121e307eb94SToomas Soome }
1122e307eb94SToomas Soome break;
1123e307eb94SToomas Soome case DATA_TYPE_NVLIST:
1124e307eb94SToomas Soome xdr.xdr_idx = ((nvlist_t *)data)->nv_data;
1125e307eb94SToomas Soome xdr.xdr_buf = xdr.xdr_idx;
1126e307eb94SToomas Soome xdr.xdr_buf_size = ((nvlist_t *)data)->nv_size;
1127e307eb94SToomas Soome
1128e307eb94SToomas Soome if (!nvlist_size_native(&xdr, &size))
1129e307eb94SToomas Soome return (-1);
1130e307eb94SToomas Soome
1131e307eb94SToomas Soome value_sz = size;
1132e307eb94SToomas Soome break;
1133e307eb94SToomas Soome case DATA_TYPE_NVLIST_ARRAY:
1134e307eb94SToomas Soome value_sz = 0;
1135e307eb94SToomas Soome for (uint32_t i = 0; i < nelem; i++) {
1136e307eb94SToomas Soome xdr.xdr_idx = ((nvlist_t **)data)[i]->nv_data;
1137e307eb94SToomas Soome xdr.xdr_buf = xdr.xdr_idx;
1138e307eb94SToomas Soome xdr.xdr_buf_size = ((nvlist_t **)data)[i]->nv_size;
1139e307eb94SToomas Soome
1140e307eb94SToomas Soome if (!nvlist_size_native(&xdr, &size))
1141e307eb94SToomas Soome return (-1);
1142e307eb94SToomas Soome value_sz += size;
1143e307eb94SToomas Soome }
1144e307eb94SToomas Soome break;
1145e307eb94SToomas Soome default:
1146e307eb94SToomas Soome return (-1);
1147e307eb94SToomas Soome }
1148e307eb94SToomas Soome
1149e307eb94SToomas Soome return (value_sz > INT32_MAX ? -1 : (int)value_sz);
1150e307eb94SToomas Soome }
1151e307eb94SToomas Soome
1152e307eb94SToomas Soome #define NVPE_SIZE(name_len, data_len) \
1153e307eb94SToomas Soome (4 + 4 + 4 + NV_ALIGN4(name_len) + 4 + 4 + data_len)
1154e307eb94SToomas Soome #define NVP_SIZE(name_len, data_len) \
1155e307eb94SToomas Soome (NV_ALIGN((4 * 4) + (name_len)) + NV_ALIGN(data_len))
1156e307eb94SToomas Soome
1157e307eb94SToomas Soome static int
nvlist_add_common(nvlist_t * nvl,const char * name,data_type_t type,uint32_t nelem,const void * data)1158e307eb94SToomas Soome nvlist_add_common(nvlist_t *nvl, const char *name, data_type_t type,
1159e307eb94SToomas Soome uint32_t nelem, const void *data)
1160e307eb94SToomas Soome {
1161e307eb94SToomas Soome nvs_data_t *nvs;
1162e307eb94SToomas Soome nvp_header_t head, *hp;
1163e307eb94SToomas Soome uint8_t *ptr;
1164e307eb94SToomas Soome size_t namelen;
1165e307eb94SToomas Soome int decoded_size, encoded_size;
11669de6a13eSToomas Soome xdr_t xdr = {
11679de6a13eSToomas Soome .xdr_op = XDR_OP_ENCODE,
11689de6a13eSToomas Soome .xdr_putint = _putint_mem,
11699de6a13eSToomas Soome .xdr_putuint = _putuint_mem,
11709de6a13eSToomas Soome .xdr_buf = nvl->nv_data,
11719de6a13eSToomas Soome .xdr_idx = nvl->nv_data,
11729de6a13eSToomas Soome .xdr_buf_size = nvl->nv_size
11739de6a13eSToomas Soome };
1174e307eb94SToomas Soome
1175e307eb94SToomas Soome nvs = (nvs_data_t *)nvl->nv_data;
1176e307eb94SToomas Soome if (nvs->nvl_nvflag & NV_UNIQUE_NAME)
1177e307eb94SToomas Soome (void) nvlist_remove(nvl, name, type);
1178e307eb94SToomas Soome
1179e307eb94SToomas Soome xdr.xdr_buf = nvl->nv_data;
1180e307eb94SToomas Soome xdr.xdr_idx = nvl->nv_data;
1181e307eb94SToomas Soome xdr.xdr_buf_size = nvl->nv_size;
1182e307eb94SToomas Soome if (!nvlist_size_native(&xdr, &nvl->nv_size))
11833830659eSToomas Soome return (EINVAL);
11843830659eSToomas Soome
1185e307eb94SToomas Soome namelen = strlen(name);
1186e307eb94SToomas Soome if ((decoded_size = get_value_size(type, data, nelem)) < 0)
1187e307eb94SToomas Soome return (EINVAL);
1188e307eb94SToomas Soome if ((encoded_size = get_nvp_data_size(type, data, nelem)) < 0)
1189e307eb94SToomas Soome return (EINVAL);
11903830659eSToomas Soome
1191e307eb94SToomas Soome /*
1192e307eb94SToomas Soome * The encoded size is calculated as:
1193e307eb94SToomas Soome * encode_size (4) + decode_size (4) +
1194e307eb94SToomas Soome * name string size (4 + NV_ALIGN4(namelen) +
1195e307eb94SToomas Soome * data type (4) + nelem size (4) + datalen
1196e307eb94SToomas Soome *
1197e307eb94SToomas Soome * The decoded size is calculated as:
1198e307eb94SToomas Soome * Note: namelen is with terminating 0.
1199e307eb94SToomas Soome * NV_ALIGN(sizeof(nvpair_t) (4 * 4) + namelen + 1) +
1200e307eb94SToomas Soome * NV_ALIGN(data_len)
1201e307eb94SToomas Soome */
1202e307eb94SToomas Soome
1203e307eb94SToomas Soome head.encoded_size = NVPE_SIZE(namelen, encoded_size);
1204e307eb94SToomas Soome head.decoded_size = NVP_SIZE(namelen + 1, decoded_size);
1205e307eb94SToomas Soome
1206e307eb94SToomas Soome if (nvl->nv_asize - nvl->nv_size < head.encoded_size + 8) {
1207e307eb94SToomas Soome ptr = realloc(nvl->nv_data, nvl->nv_asize + head.encoded_size);
1208e307eb94SToomas Soome if (ptr == NULL)
1209e307eb94SToomas Soome return (ENOMEM);
1210e307eb94SToomas Soome nvl->nv_data = ptr;
1211e307eb94SToomas Soome nvl->nv_asize += head.encoded_size;
12123830659eSToomas Soome }
1213e307eb94SToomas Soome nvl->nv_idx = nvl->nv_data + nvl->nv_size - sizeof(*hp);
1214e307eb94SToomas Soome bzero(nvl->nv_idx, head.encoded_size + 8);
1215e307eb94SToomas Soome hp = (nvp_header_t *)nvl->nv_idx;
1216e307eb94SToomas Soome *hp = head;
1217e307eb94SToomas Soome nvl->nv_idx += sizeof(*hp);
12189de6a13eSToomas Soome
12199de6a13eSToomas Soome xdr.xdr_buf = nvl->nv_data;
1220bcc3148cSMark Johnston xdr.xdr_buf_size = nvl->nv_asize;
12219de6a13eSToomas Soome xdr.xdr_idx = nvl->nv_idx;
12229de6a13eSToomas Soome
12239de6a13eSToomas Soome xdr.xdr_idx += xdr.xdr_putuint(&xdr, namelen);
12249de6a13eSToomas Soome strlcpy((char *)xdr.xdr_idx, name, namelen + 1);
12259de6a13eSToomas Soome xdr.xdr_idx += NV_ALIGN4(namelen);
12269de6a13eSToomas Soome xdr.xdr_idx += xdr.xdr_putuint(&xdr, type);
12279de6a13eSToomas Soome xdr.xdr_idx += xdr.xdr_putuint(&xdr, nelem);
1228e307eb94SToomas Soome
1229e307eb94SToomas Soome switch (type) {
1230e307eb94SToomas Soome case DATA_TYPE_BOOLEAN:
1231e307eb94SToomas Soome break;
12329de6a13eSToomas Soome
1233e307eb94SToomas Soome case DATA_TYPE_BYTE_ARRAY:
12349de6a13eSToomas Soome xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size);
12359de6a13eSToomas Soome bcopy(data, xdr.xdr_idx, nelem);
12369de6a13eSToomas Soome xdr.xdr_idx += NV_ALIGN4(encoded_size);
1237e307eb94SToomas Soome break;
12389de6a13eSToomas Soome
1239e307eb94SToomas Soome case DATA_TYPE_STRING:
1240e307eb94SToomas Soome encoded_size = strlen(data);
12419de6a13eSToomas Soome xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size);
12429de6a13eSToomas Soome strlcpy((char *)xdr.xdr_idx, data, encoded_size + 1);
12439de6a13eSToomas Soome xdr.xdr_idx += NV_ALIGN4(encoded_size);
1244e307eb94SToomas Soome break;
12459de6a13eSToomas Soome
1246e307eb94SToomas Soome case DATA_TYPE_STRING_ARRAY:
1247e307eb94SToomas Soome for (uint32_t i = 0; i < nelem; i++) {
1248e307eb94SToomas Soome encoded_size = strlen(((char **)data)[i]);
12499de6a13eSToomas Soome xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size);
12509de6a13eSToomas Soome strlcpy((char *)xdr.xdr_idx, ((char **)data)[i],
1251e307eb94SToomas Soome encoded_size + 1);
12529de6a13eSToomas Soome xdr.xdr_idx += NV_ALIGN4(encoded_size);
1253e307eb94SToomas Soome }
1254e307eb94SToomas Soome break;
12559de6a13eSToomas Soome
1256e307eb94SToomas Soome case DATA_TYPE_BYTE:
1257e307eb94SToomas Soome case DATA_TYPE_INT8:
1258e307eb94SToomas Soome case DATA_TYPE_UINT8:
12599de6a13eSToomas Soome xdr_char(&xdr, (char *)data);
12609de6a13eSToomas Soome break;
12619de6a13eSToomas Soome
1262e307eb94SToomas Soome case DATA_TYPE_INT8_ARRAY:
1263e307eb94SToomas Soome case DATA_TYPE_UINT8_ARRAY:
12649de6a13eSToomas Soome xdr_array(&xdr, nelem, (xdrproc_t)xdr_char);
1265e307eb94SToomas Soome break;
12669de6a13eSToomas Soome
1267e307eb94SToomas Soome case DATA_TYPE_INT16:
12689de6a13eSToomas Soome xdr_short(&xdr, (short *)data);
12699de6a13eSToomas Soome break;
12709de6a13eSToomas Soome
1271e307eb94SToomas Soome case DATA_TYPE_UINT16:
12729de6a13eSToomas Soome xdr_u_short(&xdr, (unsigned short *)data);
12739de6a13eSToomas Soome break;
12749de6a13eSToomas Soome
1275e307eb94SToomas Soome case DATA_TYPE_INT16_ARRAY:
12769de6a13eSToomas Soome xdr_array(&xdr, nelem, (xdrproc_t)xdr_short);
12779de6a13eSToomas Soome break;
12789de6a13eSToomas Soome
1279e307eb94SToomas Soome case DATA_TYPE_UINT16_ARRAY:
12809de6a13eSToomas Soome xdr_array(&xdr, nelem, (xdrproc_t)xdr_u_short);
1281e307eb94SToomas Soome break;
12829de6a13eSToomas Soome
12839de6a13eSToomas Soome case DATA_TYPE_BOOLEAN_VALUE:
12849de6a13eSToomas Soome case DATA_TYPE_INT32:
12859de6a13eSToomas Soome xdr_int(&xdr, (int *)data);
12869de6a13eSToomas Soome break;
12879de6a13eSToomas Soome
12889de6a13eSToomas Soome case DATA_TYPE_UINT32:
12899de6a13eSToomas Soome xdr_u_int(&xdr, (unsigned int *)data);
12909de6a13eSToomas Soome break;
12919de6a13eSToomas Soome
12929de6a13eSToomas Soome case DATA_TYPE_BOOLEAN_ARRAY:
12939de6a13eSToomas Soome case DATA_TYPE_INT32_ARRAY:
12949de6a13eSToomas Soome xdr_array(&xdr, nelem, (xdrproc_t)xdr_int);
12959de6a13eSToomas Soome break;
12969de6a13eSToomas Soome
12979de6a13eSToomas Soome case DATA_TYPE_UINT32_ARRAY:
12989de6a13eSToomas Soome xdr_array(&xdr, nelem, (xdrproc_t)xdr_u_int);
12999de6a13eSToomas Soome break;
13009de6a13eSToomas Soome
13019de6a13eSToomas Soome case DATA_TYPE_INT64:
13029de6a13eSToomas Soome xdr_int64(&xdr, (int64_t *)data);
13039de6a13eSToomas Soome break;
13049de6a13eSToomas Soome
13059de6a13eSToomas Soome case DATA_TYPE_UINT64:
13069de6a13eSToomas Soome xdr_uint64(&xdr, (uint64_t *)data);
13079de6a13eSToomas Soome break;
13089de6a13eSToomas Soome
13099de6a13eSToomas Soome case DATA_TYPE_INT64_ARRAY:
13109de6a13eSToomas Soome xdr_array(&xdr, nelem, (xdrproc_t)xdr_int64);
13119de6a13eSToomas Soome break;
13129de6a13eSToomas Soome
13139de6a13eSToomas Soome case DATA_TYPE_UINT64_ARRAY:
13149de6a13eSToomas Soome xdr_array(&xdr, nelem, (xdrproc_t)xdr_uint64);
13159de6a13eSToomas Soome break;
13169de6a13eSToomas Soome
1317e307eb94SToomas Soome case DATA_TYPE_NVLIST:
13189de6a13eSToomas Soome bcopy(((nvlist_t *)data)->nv_data, xdr.xdr_idx, encoded_size);
1319e307eb94SToomas Soome break;
13209de6a13eSToomas Soome
1321e307eb94SToomas Soome case DATA_TYPE_NVLIST_ARRAY: {
1322e307eb94SToomas Soome size_t size;
13239de6a13eSToomas Soome xdr_t xdr_nv;
1324e307eb94SToomas Soome
1325e307eb94SToomas Soome for (uint32_t i = 0; i < nelem; i++) {
13269de6a13eSToomas Soome xdr_nv.xdr_idx = ((nvlist_t **)data)[i]->nv_data;
13279de6a13eSToomas Soome xdr_nv.xdr_buf = xdr_nv.xdr_idx;
13289de6a13eSToomas Soome xdr_nv.xdr_buf_size = ((nvlist_t **)data)[i]->nv_size;
1329e307eb94SToomas Soome
13309de6a13eSToomas Soome if (!nvlist_size_native(&xdr_nv, &size))
1331e307eb94SToomas Soome return (EINVAL);
1332e307eb94SToomas Soome
13339de6a13eSToomas Soome bcopy(((nvlist_t **)data)[i]->nv_data, xdr.xdr_idx,
13349de6a13eSToomas Soome size);
13359de6a13eSToomas Soome xdr.xdr_idx += size;
1336e307eb94SToomas Soome }
1337e307eb94SToomas Soome break;
1338e307eb94SToomas Soome }
1339e307eb94SToomas Soome default:
13409de6a13eSToomas Soome bcopy(data, xdr.xdr_idx, encoded_size);
1341e307eb94SToomas Soome }
1342e307eb94SToomas Soome
1343e307eb94SToomas Soome nvl->nv_size += head.encoded_size;
1344e307eb94SToomas Soome
13453830659eSToomas Soome return (0);
13463830659eSToomas Soome }
13473830659eSToomas Soome
1348e307eb94SToomas Soome int
nvlist_add_boolean_value(nvlist_t * nvl,const char * name,int value)1349e097436cSMark Johnston nvlist_add_boolean_value(nvlist_t *nvl, const char *name, int value)
13503830659eSToomas Soome {
1351e307eb94SToomas Soome return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_VALUE, 1,
1352e307eb94SToomas Soome &value));
1353e307eb94SToomas Soome }
1354e307eb94SToomas Soome
1355e307eb94SToomas Soome int
nvlist_add_byte(nvlist_t * nvl,const char * name,uint8_t value)1356e307eb94SToomas Soome nvlist_add_byte(nvlist_t *nvl, const char *name, uint8_t value)
1357e307eb94SToomas Soome {
1358e307eb94SToomas Soome return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE, 1, &value));
1359e307eb94SToomas Soome }
1360e307eb94SToomas Soome
1361e307eb94SToomas Soome int
nvlist_add_int8(nvlist_t * nvl,const char * name,int8_t value)1362e307eb94SToomas Soome nvlist_add_int8(nvlist_t *nvl, const char *name, int8_t value)
1363e307eb94SToomas Soome {
1364e307eb94SToomas Soome return (nvlist_add_common(nvl, name, DATA_TYPE_INT8, 1, &value));
1365e307eb94SToomas Soome }
1366e307eb94SToomas Soome
1367e307eb94SToomas Soome int
nvlist_add_uint8(nvlist_t * nvl,const char * name,uint8_t value)1368e307eb94SToomas Soome nvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t value)
1369e307eb94SToomas Soome {
1370e307eb94SToomas Soome return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8, 1, &value));
1371e307eb94SToomas Soome }
1372e307eb94SToomas Soome
1373e307eb94SToomas Soome int
nvlist_add_int16(nvlist_t * nvl,const char * name,int16_t value)1374e307eb94SToomas Soome nvlist_add_int16(nvlist_t *nvl, const char *name, int16_t value)
1375e307eb94SToomas Soome {
1376e307eb94SToomas Soome return (nvlist_add_common(nvl, name, DATA_TYPE_INT16, 1, &value));
1377e307eb94SToomas Soome }
1378e307eb94SToomas Soome
1379e307eb94SToomas Soome int
nvlist_add_uint16(nvlist_t * nvl,const char * name,uint16_t value)1380e307eb94SToomas Soome nvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t value)
1381e307eb94SToomas Soome {
1382e307eb94SToomas Soome return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16, 1, &value));
1383e307eb94SToomas Soome }
1384e307eb94SToomas Soome
1385e307eb94SToomas Soome int
nvlist_add_int32(nvlist_t * nvl,const char * name,int32_t value)1386e307eb94SToomas Soome nvlist_add_int32(nvlist_t *nvl, const char *name, int32_t value)
1387e307eb94SToomas Soome {
1388e307eb94SToomas Soome return (nvlist_add_common(nvl, name, DATA_TYPE_INT32, 1, &value));
1389e307eb94SToomas Soome }
1390e307eb94SToomas Soome
1391e307eb94SToomas Soome int
nvlist_add_uint32(nvlist_t * nvl,const char * name,uint32_t value)1392e307eb94SToomas Soome nvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t value)
1393e307eb94SToomas Soome {
1394e307eb94SToomas Soome return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32, 1, &value));
1395e307eb94SToomas Soome }
1396e307eb94SToomas Soome
1397e307eb94SToomas Soome int
nvlist_add_int64(nvlist_t * nvl,const char * name,int64_t value)1398e307eb94SToomas Soome nvlist_add_int64(nvlist_t *nvl, const char *name, int64_t value)
1399e307eb94SToomas Soome {
1400e307eb94SToomas Soome return (nvlist_add_common(nvl, name, DATA_TYPE_INT64, 1, &value));
1401e307eb94SToomas Soome }
1402e307eb94SToomas Soome
1403e307eb94SToomas Soome int
nvlist_add_uint64(nvlist_t * nvl,const char * name,uint64_t value)1404e307eb94SToomas Soome nvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t value)
1405e307eb94SToomas Soome {
1406e307eb94SToomas Soome return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64, 1, &value));
1407e307eb94SToomas Soome }
1408e307eb94SToomas Soome
1409e307eb94SToomas Soome int
nvlist_add_string(nvlist_t * nvl,const char * name,const char * value)1410e307eb94SToomas Soome nvlist_add_string(nvlist_t *nvl, const char *name, const char *value)
1411e307eb94SToomas Soome {
1412e307eb94SToomas Soome return (nvlist_add_common(nvl, name, DATA_TYPE_STRING, 1, value));
1413e307eb94SToomas Soome }
1414e307eb94SToomas Soome
1415e307eb94SToomas Soome int
nvlist_add_boolean_array(nvlist_t * nvl,const char * name,int * a,uint32_t n)1416e097436cSMark Johnston nvlist_add_boolean_array(nvlist_t *nvl, const char *name, int *a, uint32_t n)
1417e307eb94SToomas Soome {
1418e307eb94SToomas Soome return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_ARRAY, n, a));
1419e307eb94SToomas Soome }
1420e307eb94SToomas Soome
1421e307eb94SToomas Soome int
nvlist_add_byte_array(nvlist_t * nvl,const char * name,uint8_t * a,uint32_t n)1422e307eb94SToomas Soome nvlist_add_byte_array(nvlist_t *nvl, const char *name, uint8_t *a, uint32_t n)
1423e307eb94SToomas Soome {
1424e307eb94SToomas Soome return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a));
1425e307eb94SToomas Soome }
1426e307eb94SToomas Soome
1427e307eb94SToomas Soome int
nvlist_add_int8_array(nvlist_t * nvl,const char * name,int8_t * a,uint32_t n)1428e307eb94SToomas Soome nvlist_add_int8_array(nvlist_t *nvl, const char *name, int8_t *a, uint32_t n)
1429e307eb94SToomas Soome {
1430e307eb94SToomas Soome return (nvlist_add_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a));
1431e307eb94SToomas Soome }
1432e307eb94SToomas Soome
1433e307eb94SToomas Soome int
nvlist_add_uint8_array(nvlist_t * nvl,const char * name,uint8_t * a,uint32_t n)1434e307eb94SToomas Soome nvlist_add_uint8_array(nvlist_t *nvl, const char *name, uint8_t *a, uint32_t n)
1435e307eb94SToomas Soome {
1436e307eb94SToomas Soome return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a));
1437e307eb94SToomas Soome }
1438e307eb94SToomas Soome
1439e307eb94SToomas Soome int
nvlist_add_int16_array(nvlist_t * nvl,const char * name,int16_t * a,uint32_t n)1440e307eb94SToomas Soome nvlist_add_int16_array(nvlist_t *nvl, const char *name, int16_t *a, uint32_t n)
1441e307eb94SToomas Soome {
1442e307eb94SToomas Soome return (nvlist_add_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a));
1443e307eb94SToomas Soome }
1444e307eb94SToomas Soome
1445e307eb94SToomas Soome int
nvlist_add_uint16_array(nvlist_t * nvl,const char * name,uint16_t * a,uint32_t n)1446e307eb94SToomas Soome nvlist_add_uint16_array(nvlist_t *nvl, const char *name, uint16_t *a,
1447e307eb94SToomas Soome uint32_t n)
1448e307eb94SToomas Soome {
1449e307eb94SToomas Soome return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a));
1450e307eb94SToomas Soome }
1451e307eb94SToomas Soome
1452e307eb94SToomas Soome int
nvlist_add_int32_array(nvlist_t * nvl,const char * name,int32_t * a,uint32_t n)1453e307eb94SToomas Soome nvlist_add_int32_array(nvlist_t *nvl, const char *name, int32_t *a, uint32_t n)
1454e307eb94SToomas Soome {
1455e307eb94SToomas Soome return (nvlist_add_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a));
1456e307eb94SToomas Soome }
1457e307eb94SToomas Soome
1458e307eb94SToomas Soome int
nvlist_add_uint32_array(nvlist_t * nvl,const char * name,uint32_t * a,uint32_t n)1459e307eb94SToomas Soome nvlist_add_uint32_array(nvlist_t *nvl, const char *name, uint32_t *a,
1460e307eb94SToomas Soome uint32_t n)
1461e307eb94SToomas Soome {
1462e307eb94SToomas Soome return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a));
1463e307eb94SToomas Soome }
1464e307eb94SToomas Soome
1465e307eb94SToomas Soome int
nvlist_add_int64_array(nvlist_t * nvl,const char * name,int64_t * a,uint32_t n)1466e307eb94SToomas Soome nvlist_add_int64_array(nvlist_t *nvl, const char *name, int64_t *a, uint32_t n)
1467e307eb94SToomas Soome {
1468e307eb94SToomas Soome return (nvlist_add_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a));
1469e307eb94SToomas Soome }
1470e307eb94SToomas Soome
1471e307eb94SToomas Soome int
nvlist_add_uint64_array(nvlist_t * nvl,const char * name,uint64_t * a,uint32_t n)1472e307eb94SToomas Soome nvlist_add_uint64_array(nvlist_t *nvl, const char *name, uint64_t *a,
1473e307eb94SToomas Soome uint32_t n)
1474e307eb94SToomas Soome {
1475e307eb94SToomas Soome return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a));
1476e307eb94SToomas Soome }
1477e307eb94SToomas Soome
1478e307eb94SToomas Soome int
nvlist_add_string_array(nvlist_t * nvl,const char * name,char * const * a,uint32_t n)1479e307eb94SToomas Soome nvlist_add_string_array(nvlist_t *nvl, const char *name,
1480e307eb94SToomas Soome char * const *a, uint32_t n)
1481e307eb94SToomas Soome {
1482e307eb94SToomas Soome return (nvlist_add_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a));
1483e307eb94SToomas Soome }
1484e307eb94SToomas Soome
1485e307eb94SToomas Soome int
nvlist_add_nvlist(nvlist_t * nvl,const char * name,nvlist_t * val)1486e307eb94SToomas Soome nvlist_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val)
1487e307eb94SToomas Soome {
1488e307eb94SToomas Soome return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST, 1, val));
1489e307eb94SToomas Soome }
1490e307eb94SToomas Soome
1491e307eb94SToomas Soome int
nvlist_add_nvlist_array(nvlist_t * nvl,const char * name,nvlist_t ** a,uint32_t n)1492e307eb94SToomas Soome nvlist_add_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **a,
1493e307eb94SToomas Soome uint32_t n)
1494e307eb94SToomas Soome {
1495e307eb94SToomas Soome return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a));
1496e307eb94SToomas Soome }
1497e307eb94SToomas Soome
14983830659eSToomas Soome static const char *typenames[] = {
14993830659eSToomas Soome "DATA_TYPE_UNKNOWN",
15003830659eSToomas Soome "DATA_TYPE_BOOLEAN",
15013830659eSToomas Soome "DATA_TYPE_BYTE",
15023830659eSToomas Soome "DATA_TYPE_INT16",
15033830659eSToomas Soome "DATA_TYPE_UINT16",
15043830659eSToomas Soome "DATA_TYPE_INT32",
15053830659eSToomas Soome "DATA_TYPE_UINT32",
15063830659eSToomas Soome "DATA_TYPE_INT64",
15073830659eSToomas Soome "DATA_TYPE_UINT64",
15083830659eSToomas Soome "DATA_TYPE_STRING",
15093830659eSToomas Soome "DATA_TYPE_BYTE_ARRAY",
15103830659eSToomas Soome "DATA_TYPE_INT16_ARRAY",
15113830659eSToomas Soome "DATA_TYPE_UINT16_ARRAY",
15123830659eSToomas Soome "DATA_TYPE_INT32_ARRAY",
15133830659eSToomas Soome "DATA_TYPE_UINT32_ARRAY",
15143830659eSToomas Soome "DATA_TYPE_INT64_ARRAY",
15153830659eSToomas Soome "DATA_TYPE_UINT64_ARRAY",
15163830659eSToomas Soome "DATA_TYPE_STRING_ARRAY",
15173830659eSToomas Soome "DATA_TYPE_HRTIME",
15183830659eSToomas Soome "DATA_TYPE_NVLIST",
15193830659eSToomas Soome "DATA_TYPE_NVLIST_ARRAY",
15203830659eSToomas Soome "DATA_TYPE_BOOLEAN_VALUE",
15213830659eSToomas Soome "DATA_TYPE_INT8",
15223830659eSToomas Soome "DATA_TYPE_UINT8",
15233830659eSToomas Soome "DATA_TYPE_BOOLEAN_ARRAY",
15243830659eSToomas Soome "DATA_TYPE_INT8_ARRAY",
15253830659eSToomas Soome "DATA_TYPE_UINT8_ARRAY"
15263830659eSToomas Soome };
1527e307eb94SToomas Soome
1528e307eb94SToomas Soome int
nvpair_type_from_name(const char * name)1529e307eb94SToomas Soome nvpair_type_from_name(const char *name)
1530e307eb94SToomas Soome {
1531e307eb94SToomas Soome unsigned i;
1532e307eb94SToomas Soome
1533e307eb94SToomas Soome for (i = 0; i < nitems(typenames); i++) {
1534e307eb94SToomas Soome if (strcmp(name, typenames[i]) == 0)
1535e307eb94SToomas Soome return (i);
1536e307eb94SToomas Soome }
1537e307eb94SToomas Soome return (0);
1538e307eb94SToomas Soome }
1539e307eb94SToomas Soome
1540e307eb94SToomas Soome nvp_header_t *
nvpair_find(nvlist_t * nv,const char * name)1541e307eb94SToomas Soome nvpair_find(nvlist_t *nv, const char *name)
1542e307eb94SToomas Soome {
1543e307eb94SToomas Soome nvp_header_t *nvh;
1544e307eb94SToomas Soome
1545e307eb94SToomas Soome nvh = NULL;
1546e307eb94SToomas Soome while ((nvh = nvlist_next_nvpair(nv, nvh)) != NULL) {
1547e307eb94SToomas Soome nv_string_t *nvp_name;
1548e307eb94SToomas Soome
1549e307eb94SToomas Soome nvp_name = (nv_string_t *)(nvh + 1);
1550e307eb94SToomas Soome if (nvp_name->nv_size == strlen(name) &&
1551e307eb94SToomas Soome memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0)
1552e307eb94SToomas Soome break;
1553e307eb94SToomas Soome }
1554e307eb94SToomas Soome return (nvh);
1555e307eb94SToomas Soome }
1556e307eb94SToomas Soome
1557e307eb94SToomas Soome void
nvpair_print(nvp_header_t * nvp,unsigned int indent)1558e307eb94SToomas Soome nvpair_print(nvp_header_t *nvp, unsigned int indent)
1559e307eb94SToomas Soome {
15603830659eSToomas Soome nv_string_t *nvp_name;
15613830659eSToomas Soome nv_pair_data_t *nvp_data;
15623830659eSToomas Soome nvlist_t nvlist;
15639de6a13eSToomas Soome unsigned i, j;
15649de6a13eSToomas Soome xdr_t xdr = {
15659de6a13eSToomas Soome .xdr_op = XDR_OP_DECODE,
15669de6a13eSToomas Soome .xdr_getint = _getint_mem,
15679de6a13eSToomas Soome .xdr_getuint = _getuint_mem,
15689de6a13eSToomas Soome .xdr_buf = (const uint8_t *)nvp,
15699de6a13eSToomas Soome .xdr_idx = NULL,
15709de6a13eSToomas Soome .xdr_buf_size = nvp->encoded_size
15719de6a13eSToomas Soome };
15723830659eSToomas Soome
15733830659eSToomas Soome nvp_name = (nv_string_t *)((uintptr_t)nvp + sizeof(*nvp));
15743830659eSToomas Soome nvp_data = (nv_pair_data_t *)
1575e307eb94SToomas Soome NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] + nvp_name->nv_size);
15763830659eSToomas Soome
1577e307eb94SToomas Soome for (i = 0; i < indent; i++)
15783830659eSToomas Soome printf(" ");
15793830659eSToomas Soome
15803830659eSToomas Soome printf("%s [%d] %.*s", typenames[nvp_data->nv_type],
15813830659eSToomas Soome nvp_data->nv_nelem, nvp_name->nv_size, nvp_name->nv_data);
15823830659eSToomas Soome
15839de6a13eSToomas Soome xdr.xdr_idx = nvp_data->nv_data;
15843830659eSToomas Soome switch (nvp_data->nv_type) {
1585e307eb94SToomas Soome case DATA_TYPE_BYTE:
1586e307eb94SToomas Soome case DATA_TYPE_INT8:
15879de6a13eSToomas Soome case DATA_TYPE_UINT8: {
15889de6a13eSToomas Soome char c;
15899de6a13eSToomas Soome
15909de6a13eSToomas Soome if (xdr_char(&xdr, &c))
15919de6a13eSToomas Soome printf(" = 0x%x\n", c);
15923830659eSToomas Soome break;
15939de6a13eSToomas Soome }
15943830659eSToomas Soome
1595e307eb94SToomas Soome case DATA_TYPE_INT16:
15969de6a13eSToomas Soome case DATA_TYPE_UINT16: {
15979de6a13eSToomas Soome unsigned short u;
15989de6a13eSToomas Soome
15999de6a13eSToomas Soome if (xdr_u_short(&xdr, &u))
16009de6a13eSToomas Soome printf(" = 0x%hx\n", u);
1601e307eb94SToomas Soome break;
16029de6a13eSToomas Soome }
1603e307eb94SToomas Soome
1604e307eb94SToomas Soome case DATA_TYPE_BOOLEAN_VALUE:
1605e307eb94SToomas Soome case DATA_TYPE_INT32:
16069de6a13eSToomas Soome case DATA_TYPE_UINT32: {
16079de6a13eSToomas Soome unsigned u;
16089de6a13eSToomas Soome
16099de6a13eSToomas Soome if (xdr_u_int(&xdr, &u))
1610e307eb94SToomas Soome printf(" = 0x%x\n", u);
1611e307eb94SToomas Soome break;
16129de6a13eSToomas Soome }
1613e307eb94SToomas Soome
1614e307eb94SToomas Soome case DATA_TYPE_INT64:
16159de6a13eSToomas Soome case DATA_TYPE_UINT64: {
16169de6a13eSToomas Soome uint64_t u;
16179de6a13eSToomas Soome
16189de6a13eSToomas Soome if (xdr_uint64(&xdr, &u))
16199de6a13eSToomas Soome printf(" = 0x%jx\n", (uintmax_t)u);
1620e307eb94SToomas Soome break;
16219de6a13eSToomas Soome }
16229de6a13eSToomas Soome
16239de6a13eSToomas Soome case DATA_TYPE_INT64_ARRAY:
16249de6a13eSToomas Soome case DATA_TYPE_UINT64_ARRAY: {
16259de6a13eSToomas Soome uint64_t *u;
16269de6a13eSToomas Soome
16279de6a13eSToomas Soome if (xdr_array(&xdr, nvp_data->nv_nelem,
16289de6a13eSToomas Soome (xdrproc_t)xdr_uint64)) {
16299de6a13eSToomas Soome u = (uint64_t *)(nvp_data->nv_data + sizeof(unsigned));
16309de6a13eSToomas Soome for (i = 0; i < nvp_data->nv_nelem; i++)
16319de6a13eSToomas Soome printf(" [%u] = 0x%jx", i, (uintmax_t)u[i]);
16329de6a13eSToomas Soome printf("\n");
16339de6a13eSToomas Soome }
16349de6a13eSToomas Soome
16359de6a13eSToomas Soome break;
16369de6a13eSToomas Soome }
1637e307eb94SToomas Soome
1638e307eb94SToomas Soome case DATA_TYPE_STRING:
1639e307eb94SToomas Soome case DATA_TYPE_STRING_ARRAY:
16403830659eSToomas Soome nvp_name = (nv_string_t *)&nvp_data->nv_data[0];
1641e307eb94SToomas Soome for (i = 0; i < nvp_data->nv_nelem; i++) {
16423830659eSToomas Soome printf(" = \"%.*s\"\n", nvp_name->nv_size,
16433830659eSToomas Soome nvp_name->nv_data);
16443830659eSToomas Soome }
1645e307eb94SToomas Soome break;
16463830659eSToomas Soome
16473830659eSToomas Soome case DATA_TYPE_NVLIST:
16483830659eSToomas Soome printf("\n");
16493830659eSToomas Soome nvlist.nv_data = &nvp_data->nv_data[0];
16503830659eSToomas Soome nvlist_print(&nvlist, indent + 2);
16513830659eSToomas Soome break;
16523830659eSToomas Soome
16533830659eSToomas Soome case DATA_TYPE_NVLIST_ARRAY:
16543830659eSToomas Soome nvlist.nv_data = &nvp_data->nv_data[0];
16553830659eSToomas Soome for (j = 0; j < nvp_data->nv_nelem; j++) {
1656e307eb94SToomas Soome size_t size;
1657e307eb94SToomas Soome
16583830659eSToomas Soome printf("[%d]\n", j);
16593830659eSToomas Soome nvlist_print(&nvlist, indent + 2);
16603830659eSToomas Soome if (j != nvp_data->nv_nelem - 1) {
16613830659eSToomas Soome for (i = 0; i < indent; i++)
16623830659eSToomas Soome printf(" ");
16633830659eSToomas Soome printf("%s %.*s",
16643830659eSToomas Soome typenames[nvp_data->nv_type],
16653830659eSToomas Soome nvp_name->nv_size,
16663830659eSToomas Soome nvp_name->nv_data);
16673830659eSToomas Soome }
1668e307eb94SToomas Soome xdr.xdr_idx = nvlist.nv_data;
1669e307eb94SToomas Soome xdr.xdr_buf = xdr.xdr_idx;
1670e307eb94SToomas Soome xdr.xdr_buf_size = nvp->encoded_size -
1671e307eb94SToomas Soome (xdr.xdr_idx - (uint8_t *)nvp);
1672e307eb94SToomas Soome
1673e307eb94SToomas Soome if (!nvlist_size_native(&xdr, &size))
1674e307eb94SToomas Soome return;
1675e307eb94SToomas Soome
1676e307eb94SToomas Soome nvlist.nv_data += size;
16773830659eSToomas Soome }
16783830659eSToomas Soome break;
16793830659eSToomas Soome
16803830659eSToomas Soome default:
16813830659eSToomas Soome printf("\n");
16823830659eSToomas Soome }
1683e307eb94SToomas Soome }
1684e307eb94SToomas Soome
1685e307eb94SToomas Soome void
nvlist_print(const nvlist_t * nvl,unsigned int indent)1686e307eb94SToomas Soome nvlist_print(const nvlist_t *nvl, unsigned int indent)
1687e307eb94SToomas Soome {
1688e307eb94SToomas Soome nvs_data_t *data;
1689e307eb94SToomas Soome nvp_header_t *nvp;
1690e307eb94SToomas Soome
1691e307eb94SToomas Soome data = (nvs_data_t *)nvl->nv_data;
1692e307eb94SToomas Soome nvp = &data->nvl_pair; /* first pair in nvlist */
1693e307eb94SToomas Soome while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
1694e307eb94SToomas Soome nvpair_print(nvp, indent);
16953830659eSToomas Soome nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size);
16963830659eSToomas Soome }
16973830659eSToomas Soome printf("%*s\n", indent + 13, "End of nvlist");
16983830659eSToomas Soome }
1699