2 * Copyright 2020 Toomas Soome <tsoome@me.com>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
30 #include <sys/endian.h>
35 int (*xdr_getint)(const struct xdr *, const void *, int *);
38 static int xdr_int(const xdr_t *, const void *, int *);
39 static int mem_int(const xdr_t *, const void *, int *);
40 static void nvlist_decode_nvlist(const xdr_t *, nvlist_t *);
41 static int nvlist_size(const xdr_t *, const uint8_t *);
44 * transform data from network to host.
51 * transform data from host to host.
58 * transform data from host to network.
65 xdr_short(const xdr_t *xdr, const uint8_t *buf, short *ip)
69 rv = xdr->xdr_getint(xdr, buf, &i);
75 xdr_u_short(const xdr_t *xdr, const uint8_t *buf, unsigned short *ip)
80 rv = xdr->xdr_getint(xdr, buf, &u);
86 xdr_int(const xdr_t *xdr __unused, const void *buf, int *ip)
93 xdr_u_int(const xdr_t *xdr __unused, const void *buf, unsigned *ip)
96 return (sizeof(unsigned));
100 xdr_string(const xdr_t *xdr, const void *buf, nv_string_t *s)
104 size = xdr->xdr_getint(xdr, buf, &s->nv_size);
105 size = NV_ALIGN4(size + s->nv_size);
110 xdr_int64(const xdr_t *xdr, const uint8_t *buf, int64_t *lp)
115 rv = xdr->xdr_getint(xdr, buf, &hi);
116 rv += xdr->xdr_getint(xdr, buf + rv, &lo);
117 *lp = (((int64_t)hi) << 32) | lo;
122 xdr_uint64(const xdr_t *xdr, const uint8_t *buf, uint64_t *lp)
127 rv = xdr->xdr_getint(xdr, buf, &hi);
128 rv += xdr->xdr_getint(xdr, buf + rv, &lo);
129 *lp = (((int64_t)hi) << 32) | lo;
134 xdr_char(const xdr_t *xdr, const uint8_t *buf, char *cp)
138 rv = xdr->xdr_getint(xdr, buf, &i);
147 mem_int(const xdr_t *xdr, const void *buf, int *i)
150 return (sizeof(int));
154 nvlist_destroy(nvlist_t *nvl)
157 /* Free data if it was allocated by us. */
158 if (nvl->nv_asize > 0)
165 nvstring_get(nv_string_t *nvs)
169 s = malloc(nvs->nv_size + 1);
171 bcopy(nvs->nv_data, s, nvs->nv_size);
172 s[nvs->nv_size] = '\0';
178 * Create empty nvlist.
179 * The nvlist is terminated by 2x zeros (8 bytes).
182 nvlist_create(int flag)
187 nvl = calloc(1, sizeof(*nvl));
191 nvl->nv_header.nvh_encoding = NV_ENCODE_XDR;
192 nvl->nv_header.nvh_endian = _BYTE_ORDER == _LITTLE_ENDIAN;
194 nvl->nv_asize = nvl->nv_size = sizeof(*nvs);
195 nvs = calloc(1, nvl->nv_asize);
200 /* data in nvlist is byte stream */
201 nvl->nv_data = (uint8_t *)nvs;
203 nvs->nvl_version = NV_VERSION;
204 nvs->nvl_nvflag = flag;
209 nvlist_nvp_decode(const xdr_t *xdr, nvlist_t *nvl, nvp_header_t *nvph)
211 nv_string_t *nv_string;
212 nv_pair_data_t *nvp_data;
215 nv_string = (nv_string_t *)nvl->nv_idx;
216 nvl->nv_idx += xdr_string(xdr, &nv_string->nv_size, nv_string);
217 nvp_data = (nv_pair_data_t *)nvl->nv_idx;
219 nvl->nv_idx += xdr_u_int(xdr, &nvp_data->nv_type, &nvp_data->nv_type);
220 nvl->nv_idx += xdr_u_int(xdr, &nvp_data->nv_nelem, &nvp_data->nv_nelem);
222 switch (nvp_data->nv_type) {
223 case DATA_TYPE_NVLIST:
224 case DATA_TYPE_NVLIST_ARRAY:
225 bzero(&nvlist, sizeof (nvlist));
226 nvlist.nv_data = &nvp_data->nv_data[0];
227 nvlist.nv_idx = nvlist.nv_data;
228 for (int i = 0; i < nvp_data->nv_nelem; i++) {
230 nvlist_size(xdr, nvlist.nv_data);
231 nvlist_decode_nvlist(xdr, &nvlist);
232 nvl->nv_idx = nvlist.nv_idx;
233 nvlist.nv_data = nvlist.nv_idx;
237 case DATA_TYPE_BOOLEAN:
238 /* BOOLEAN does not take value space */
242 case DATA_TYPE_UINT8:
243 nvl->nv_idx += xdr_char(xdr, &nvp_data->nv_data[0],
244 (char *)&nvp_data->nv_data[0]);
247 case DATA_TYPE_INT16:
248 nvl->nv_idx += xdr_short(xdr, &nvp_data->nv_data[0],
249 (short *)&nvp_data->nv_data[0]);
252 case DATA_TYPE_UINT16:
253 nvl->nv_idx += xdr_u_short(xdr, &nvp_data->nv_data[0],
254 (unsigned short *)&nvp_data->nv_data[0]);
257 case DATA_TYPE_BOOLEAN_VALUE:
258 case DATA_TYPE_INT32:
259 nvl->nv_idx += xdr_int(xdr, &nvp_data->nv_data[0],
260 (int *)&nvp_data->nv_data[0]);
263 case DATA_TYPE_UINT32:
264 nvl->nv_idx += xdr_u_int(xdr, &nvp_data->nv_data[0],
265 (unsigned *)&nvp_data->nv_data[0]);
268 case DATA_TYPE_INT64:
269 nvl->nv_idx += xdr_int64(xdr, &nvp_data->nv_data[0],
270 (int64_t *)&nvp_data->nv_data[0]);
273 case DATA_TYPE_UINT64:
274 nvl->nv_idx += xdr_uint64(xdr, &nvp_data->nv_data[0],
275 (uint64_t *)&nvp_data->nv_data[0]);
278 case DATA_TYPE_STRING:
279 nv_string = (nv_string_t *)&nvp_data->nv_data[0];
280 nvl->nv_idx += xdr_string(xdr, &nvp_data->nv_data[0],
288 nvlist_decode_nvlist(const xdr_t *xdr, nvlist_t *nvl)
291 nvs_data_t *nvs = (nvs_data_t *)nvl->nv_data;
293 nvl->nv_idx = nvl->nv_data;
294 nvl->nv_idx += xdr->xdr_getint(xdr, (const uint8_t *)&nvs->nvl_version,
296 nvl->nv_idx += xdr->xdr_getint(xdr, (const uint8_t *)&nvs->nvl_nvflag,
299 nvph = &nvs->nvl_pair;
300 nvl->nv_idx += xdr->xdr_getint(xdr,
301 (const uint8_t *)&nvph->encoded_size, &nvph->encoded_size);
302 nvl->nv_idx += xdr->xdr_getint(xdr,
303 (const uint8_t *)&nvph->decoded_size, &nvph->decoded_size);
305 while (nvph->encoded_size && nvph->decoded_size) {
306 nvlist_nvp_decode(xdr, nvl, nvph);
308 nvph = (nvp_header_t *)(nvl->nv_idx);
309 nvl->nv_idx += xdr->xdr_getint(xdr, &nvph->encoded_size,
310 &nvph->encoded_size);
311 nvl->nv_idx += xdr->xdr_getint(xdr, &nvph->decoded_size,
312 &nvph->decoded_size);
317 nvlist_size(const xdr_t *xdr, const uint8_t *stream)
319 const uint8_t *p, *pair;
320 unsigned encoded_size, decoded_size;
323 p += 2 * sizeof(unsigned);
326 p += xdr->xdr_getint(xdr, p, &encoded_size);
327 p += xdr->xdr_getint(xdr, p, &decoded_size);
328 while (encoded_size && decoded_size) {
329 p = pair + encoded_size;
331 p += xdr->xdr_getint(xdr, p, &encoded_size);
332 p += xdr->xdr_getint(xdr, p, &decoded_size);
338 * Import nvlist from byte stream.
339 * Determine the stream size and allocate private copy.
340 * Then translate the data.
343 nvlist_import(const uint8_t *stream, char encoding, char endian)
347 if (encoding != NV_ENCODE_XDR)
350 nvl = malloc(sizeof(*nvl));
354 nvl->nv_asize = nvl->nv_size = nvlist_size(&ntoh, stream);
355 nvl->nv_data = malloc(nvl->nv_asize);
356 if (nvl->nv_data == NULL) {
360 nvl->nv_idx = nvl->nv_data;
361 bcopy(stream, nvl->nv_data, nvl->nv_asize);
363 nvlist_decode_nvlist(&ntoh, nvl);
364 nvl->nv_idx = nvl->nv_data;
369 * remove pair from this nvlist.
372 nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type)
374 uint8_t *head, *tail;
377 nv_string_t *nvp_name;
378 nv_pair_data_t *nvp_data;
381 if (nvl == NULL || nvl->nv_data == NULL || name == NULL)
385 data = (nvs_data_t *)head;
386 nvp = &data->nvl_pair; /* first pair in nvlist */
387 head = (uint8_t *)nvp;
389 while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
390 nvp_name = (nv_string_t *)(head + sizeof(*nvp));
392 nvp_data = (nv_pair_data_t *)
393 NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] +
396 if (memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 &&
397 nvp_data->nv_type == type) {
399 * set tail to point to next nvpair and size
400 * is the length of the tail.
402 tail = head + nvp->encoded_size;
403 size = nvl->nv_data + nvl->nv_size - tail;
405 /* adjust the size of the nvlist. */
406 nvl->nv_size -= nvp->encoded_size;
407 bcopy(tail, head, size);
410 /* Not our pair, skip to next. */
411 head = head + nvp->encoded_size;
412 nvp = (nvp_header_t *)head;
418 nvlist_find(const nvlist_t *nvl, const char *name, data_type_t type,
419 int *elementsp, void *valuep, int *sizep)
423 nv_string_t *nvp_name;
424 nv_pair_data_t *nvp_data;
427 if (nvl == NULL || nvl->nv_data == NULL || name == NULL)
430 data = (nvs_data_t *)nvl->nv_data;
431 nvp = &data->nvl_pair; /* first pair in nvlist */
433 while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
434 nvp_name = (nv_string_t *)((uint8_t *)nvp + sizeof(*nvp));
436 nvp_data = (nv_pair_data_t *)
437 NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] +
440 if (memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 &&
441 nvp_data->nv_type == type) {
442 if (elementsp != NULL)
443 *elementsp = nvp_data->nv_nelem;
444 switch (nvp_data->nv_type) {
445 case DATA_TYPE_UINT64:
446 *(uint64_t *)valuep =
447 *(uint64_t *)nvp_data->nv_data;
449 case DATA_TYPE_STRING:
450 nvp_name = (nv_string_t *)nvp_data->nv_data;
452 *sizep = nvp_name->nv_size;
454 *(const uint8_t **)valuep =
455 &nvp_name->nv_data[0];
457 case DATA_TYPE_NVLIST:
458 case DATA_TYPE_NVLIST_ARRAY:
459 nvlist = malloc(sizeof(*nvlist));
460 if (nvlist != NULL) {
461 nvlist->nv_header = nvl->nv_header;
462 nvlist->nv_asize = 0;
464 nvlist->nv_idx = NULL;
465 nvlist->nv_data = &nvp_data->nv_data[0];
466 *(nvlist_t **)valuep = nvlist;
473 /* Not our pair, skip to next. */
474 nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size);
480 * Return the next nvlist in an nvlist array.
483 nvlist_next(nvlist_t *nvl)
488 if (nvl == NULL || nvl->nv_data == NULL || nvl->nv_asize != 0)
491 data = (nvs_data_t *)nvl->nv_data;
492 nvp = &data->nvl_pair; /* first pair in nvlist */
494 while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
495 nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size);
497 nvl->nv_data = (uint8_t *)nvp + sizeof(*nvp);
502 nvlist_print(nvlist_t *nvl, unsigned int indent)
504 static const char *typenames[] = {
515 "DATA_TYPE_BYTE_ARRAY",
516 "DATA_TYPE_INT16_ARRAY",
517 "DATA_TYPE_UINT16_ARRAY",
518 "DATA_TYPE_INT32_ARRAY",
519 "DATA_TYPE_UINT32_ARRAY",
520 "DATA_TYPE_INT64_ARRAY",
521 "DATA_TYPE_UINT64_ARRAY",
522 "DATA_TYPE_STRING_ARRAY",
525 "DATA_TYPE_NVLIST_ARRAY",
526 "DATA_TYPE_BOOLEAN_VALUE",
529 "DATA_TYPE_BOOLEAN_ARRAY",
530 "DATA_TYPE_INT8_ARRAY",
531 "DATA_TYPE_UINT8_ARRAY"
535 nv_string_t *nvp_name;
536 nv_pair_data_t *nvp_data;
540 data = (nvs_data_t *)nvl->nv_data;
541 nvp = &data->nvl_pair; /* first pair in nvlist */
542 while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
543 nvp_name = (nv_string_t *)((uintptr_t)nvp + sizeof(*nvp));
544 nvp_data = (nv_pair_data_t *)
545 NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] +
548 for (int i = 0; i < indent; i++)
551 printf("%s [%d] %.*s", typenames[nvp_data->nv_type],
552 nvp_data->nv_nelem, nvp_name->nv_size, nvp_name->nv_data);
554 switch (nvp_data->nv_type) {
555 case DATA_TYPE_UINT64: {
558 val = *(uint64_t *)nvp_data->nv_data;
559 printf(" = 0x%jx\n", (uintmax_t)val);
563 case DATA_TYPE_STRING: {
564 nvp_name = (nv_string_t *)&nvp_data->nv_data[0];
565 printf(" = \"%.*s\"\n", nvp_name->nv_size,
570 case DATA_TYPE_NVLIST:
572 nvlist.nv_data = &nvp_data->nv_data[0];
573 nvlist_print(&nvlist, indent + 2);
576 case DATA_TYPE_NVLIST_ARRAY:
577 nvlist.nv_data = &nvp_data->nv_data[0];
578 for (j = 0; j < nvp_data->nv_nelem; j++) {
579 data = (nvs_data_t *)nvlist.nv_data;
581 nvlist_print(&nvlist, indent + 2);
582 if (j != nvp_data->nv_nelem - 1) {
583 for (i = 0; i < indent; i++)
586 typenames[nvp_data->nv_type],
590 nvlist.nv_data = (uint8_t *)data +
591 nvlist_size(&native, nvlist.nv_data);
598 nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size);
600 printf("%*s\n", indent + 13, "End of nvlist");