132115b10SPawel Jakub Dawidek /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni *
432115b10SPawel Jakub Dawidek * Copyright (c) 2009-2010 The FreeBSD Foundation
532115b10SPawel Jakub Dawidek * All rights reserved.
632115b10SPawel Jakub Dawidek *
732115b10SPawel Jakub Dawidek * This software was developed by Pawel Jakub Dawidek under sponsorship from
832115b10SPawel Jakub Dawidek * the FreeBSD Foundation.
932115b10SPawel Jakub Dawidek *
1032115b10SPawel Jakub Dawidek * Redistribution and use in source and binary forms, with or without
1132115b10SPawel Jakub Dawidek * modification, are permitted provided that the following conditions
1232115b10SPawel Jakub Dawidek * are met:
1332115b10SPawel Jakub Dawidek * 1. Redistributions of source code must retain the above copyright
1432115b10SPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer.
1532115b10SPawel Jakub Dawidek * 2. Redistributions in binary form must reproduce the above copyright
1632115b10SPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer in the
1732115b10SPawel Jakub Dawidek * documentation and/or other materials provided with the distribution.
1832115b10SPawel Jakub Dawidek *
1932115b10SPawel Jakub Dawidek * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
2032115b10SPawel Jakub Dawidek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2132115b10SPawel Jakub Dawidek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2232115b10SPawel Jakub Dawidek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
2332115b10SPawel Jakub Dawidek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2432115b10SPawel Jakub Dawidek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2532115b10SPawel Jakub Dawidek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2632115b10SPawel Jakub Dawidek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2732115b10SPawel Jakub Dawidek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2832115b10SPawel Jakub Dawidek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2932115b10SPawel Jakub Dawidek * SUCH DAMAGE.
3032115b10SPawel Jakub Dawidek */
3132115b10SPawel Jakub Dawidek
3232115b10SPawel Jakub Dawidek #include <sys/param.h>
3332115b10SPawel Jakub Dawidek #include <sys/endian.h>
3432115b10SPawel Jakub Dawidek
3532115b10SPawel Jakub Dawidek #include <bitstring.h>
3632115b10SPawel Jakub Dawidek #include <errno.h>
3732115b10SPawel Jakub Dawidek #include <stdarg.h>
3832115b10SPawel Jakub Dawidek #include <stdbool.h>
3932115b10SPawel Jakub Dawidek #include <stdint.h>
4032115b10SPawel Jakub Dawidek #include <stdlib.h>
4132115b10SPawel Jakub Dawidek #include <string.h>
4232115b10SPawel Jakub Dawidek #include <unistd.h>
4332115b10SPawel Jakub Dawidek
4432115b10SPawel Jakub Dawidek #include <ebuf.h>
45adf8002bSPawel Jakub Dawidek #include <pjdlog.h>
46adf8002bSPawel Jakub Dawidek
47adf8002bSPawel Jakub Dawidek #include "nv.h"
48adf8002bSPawel Jakub Dawidek
49adf8002bSPawel Jakub Dawidek #ifndef PJDLOG_ASSERT
50adf8002bSPawel Jakub Dawidek #include <assert.h>
51adf8002bSPawel Jakub Dawidek #define PJDLOG_ASSERT(...) assert(__VA_ARGS__)
52adf8002bSPawel Jakub Dawidek #endif
53adf8002bSPawel Jakub Dawidek #ifndef PJDLOG_ABORT
54adf8002bSPawel Jakub Dawidek #define PJDLOG_ABORT(...) abort()
55adf8002bSPawel Jakub Dawidek #endif
5632115b10SPawel Jakub Dawidek
57b9ffbb0aSPawel Jakub Dawidek #define NV_TYPE_NONE 0
58b9ffbb0aSPawel Jakub Dawidek
593dea75d2SPawel Jakub Dawidek #define NV_TYPE_INT8 1
603dea75d2SPawel Jakub Dawidek #define NV_TYPE_UINT8 2
613dea75d2SPawel Jakub Dawidek #define NV_TYPE_INT16 3
623dea75d2SPawel Jakub Dawidek #define NV_TYPE_UINT16 4
633dea75d2SPawel Jakub Dawidek #define NV_TYPE_INT32 5
643dea75d2SPawel Jakub Dawidek #define NV_TYPE_UINT32 6
653dea75d2SPawel Jakub Dawidek #define NV_TYPE_INT64 7
663dea75d2SPawel Jakub Dawidek #define NV_TYPE_UINT64 8
673dea75d2SPawel Jakub Dawidek #define NV_TYPE_INT8_ARRAY 9
683dea75d2SPawel Jakub Dawidek #define NV_TYPE_UINT8_ARRAY 10
693dea75d2SPawel Jakub Dawidek #define NV_TYPE_INT16_ARRAY 11
703dea75d2SPawel Jakub Dawidek #define NV_TYPE_UINT16_ARRAY 12
713dea75d2SPawel Jakub Dawidek #define NV_TYPE_INT32_ARRAY 13
723dea75d2SPawel Jakub Dawidek #define NV_TYPE_UINT32_ARRAY 14
733dea75d2SPawel Jakub Dawidek #define NV_TYPE_INT64_ARRAY 15
743dea75d2SPawel Jakub Dawidek #define NV_TYPE_UINT64_ARRAY 16
753dea75d2SPawel Jakub Dawidek #define NV_TYPE_STRING 17
763dea75d2SPawel Jakub Dawidek
773dea75d2SPawel Jakub Dawidek #define NV_TYPE_MASK 0x7f
783dea75d2SPawel Jakub Dawidek #define NV_TYPE_FIRST NV_TYPE_INT8
793dea75d2SPawel Jakub Dawidek #define NV_TYPE_LAST NV_TYPE_STRING
803dea75d2SPawel Jakub Dawidek
813dea75d2SPawel Jakub Dawidek #define NV_ORDER_NETWORK 0x00
823dea75d2SPawel Jakub Dawidek #define NV_ORDER_HOST 0x80
833dea75d2SPawel Jakub Dawidek
843dea75d2SPawel Jakub Dawidek #define NV_ORDER_MASK 0x80
853dea75d2SPawel Jakub Dawidek
8632115b10SPawel Jakub Dawidek #define NV_MAGIC 0xaea1e
8732115b10SPawel Jakub Dawidek struct nv {
8832115b10SPawel Jakub Dawidek int nv_magic;
8932115b10SPawel Jakub Dawidek int nv_error;
9032115b10SPawel Jakub Dawidek struct ebuf *nv_ebuf;
9132115b10SPawel Jakub Dawidek };
9232115b10SPawel Jakub Dawidek
9332115b10SPawel Jakub Dawidek struct nvhdr {
9432115b10SPawel Jakub Dawidek uint8_t nvh_type;
9532115b10SPawel Jakub Dawidek uint8_t nvh_namesize;
9632115b10SPawel Jakub Dawidek uint32_t nvh_dsize;
9732115b10SPawel Jakub Dawidek char nvh_name[0];
9832115b10SPawel Jakub Dawidek } __packed;
9932115b10SPawel Jakub Dawidek #define NVH_DATA(nvh) ((unsigned char *)nvh + NVH_HSIZE(nvh))
10032115b10SPawel Jakub Dawidek #define NVH_HSIZE(nvh) \
10132115b10SPawel Jakub Dawidek (sizeof(struct nvhdr) + roundup2((nvh)->nvh_namesize, 8))
10232115b10SPawel Jakub Dawidek #define NVH_DSIZE(nvh) \
10332115b10SPawel Jakub Dawidek (((nvh)->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST ? \
10432115b10SPawel Jakub Dawidek (nvh)->nvh_dsize : \
10532115b10SPawel Jakub Dawidek le32toh((nvh)->nvh_dsize))
10632115b10SPawel Jakub Dawidek #define NVH_SIZE(nvh) (NVH_HSIZE(nvh) + roundup2(NVH_DSIZE(nvh), 8))
10732115b10SPawel Jakub Dawidek
10832115b10SPawel Jakub Dawidek #define NV_CHECK(nv) do { \
109adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT((nv) != NULL); \
110adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT((nv)->nv_magic == NV_MAGIC); \
11132115b10SPawel Jakub Dawidek } while (0)
11232115b10SPawel Jakub Dawidek
11332115b10SPawel Jakub Dawidek static void nv_add(struct nv *nv, const unsigned char *value, size_t vsize,
11432115b10SPawel Jakub Dawidek int type, const char *name);
11532115b10SPawel Jakub Dawidek static void nv_addv(struct nv *nv, const unsigned char *value, size_t vsize,
11632115b10SPawel Jakub Dawidek int type, const char *namefmt, va_list nameap);
11732115b10SPawel Jakub Dawidek static struct nvhdr *nv_find(struct nv *nv, int type, const char *namefmt,
11832115b10SPawel Jakub Dawidek va_list nameap);
11932115b10SPawel Jakub Dawidek static void nv_swap(struct nvhdr *nvh, bool tohost);
12032115b10SPawel Jakub Dawidek
12132115b10SPawel Jakub Dawidek /*
12232115b10SPawel Jakub Dawidek * Allocate and initialize new nv structure.
12332115b10SPawel Jakub Dawidek * Return NULL in case of malloc(3) failure.
12432115b10SPawel Jakub Dawidek */
12532115b10SPawel Jakub Dawidek struct nv *
nv_alloc(void)12632115b10SPawel Jakub Dawidek nv_alloc(void)
12732115b10SPawel Jakub Dawidek {
12832115b10SPawel Jakub Dawidek struct nv *nv;
12932115b10SPawel Jakub Dawidek
13032115b10SPawel Jakub Dawidek nv = malloc(sizeof(*nv));
13132115b10SPawel Jakub Dawidek if (nv == NULL)
13232115b10SPawel Jakub Dawidek return (NULL);
13332115b10SPawel Jakub Dawidek nv->nv_ebuf = ebuf_alloc(0);
13432115b10SPawel Jakub Dawidek if (nv->nv_ebuf == NULL) {
13532115b10SPawel Jakub Dawidek free(nv);
13632115b10SPawel Jakub Dawidek return (NULL);
13732115b10SPawel Jakub Dawidek }
13832115b10SPawel Jakub Dawidek nv->nv_error = 0;
13932115b10SPawel Jakub Dawidek nv->nv_magic = NV_MAGIC;
14032115b10SPawel Jakub Dawidek return (nv);
14132115b10SPawel Jakub Dawidek }
14232115b10SPawel Jakub Dawidek
14332115b10SPawel Jakub Dawidek /*
14432115b10SPawel Jakub Dawidek * Free the given nv structure.
14532115b10SPawel Jakub Dawidek */
14632115b10SPawel Jakub Dawidek void
nv_free(struct nv * nv)14732115b10SPawel Jakub Dawidek nv_free(struct nv *nv)
14832115b10SPawel Jakub Dawidek {
14932115b10SPawel Jakub Dawidek
15032115b10SPawel Jakub Dawidek if (nv == NULL)
15132115b10SPawel Jakub Dawidek return;
15232115b10SPawel Jakub Dawidek
15332115b10SPawel Jakub Dawidek NV_CHECK(nv);
15432115b10SPawel Jakub Dawidek
15532115b10SPawel Jakub Dawidek nv->nv_magic = 0;
15632115b10SPawel Jakub Dawidek ebuf_free(nv->nv_ebuf);
15732115b10SPawel Jakub Dawidek free(nv);
15832115b10SPawel Jakub Dawidek }
15932115b10SPawel Jakub Dawidek
16032115b10SPawel Jakub Dawidek /*
16132115b10SPawel Jakub Dawidek * Return error for the given nv structure.
16232115b10SPawel Jakub Dawidek */
16332115b10SPawel Jakub Dawidek int
nv_error(const struct nv * nv)16432115b10SPawel Jakub Dawidek nv_error(const struct nv *nv)
16532115b10SPawel Jakub Dawidek {
16632115b10SPawel Jakub Dawidek
16732115b10SPawel Jakub Dawidek if (nv == NULL)
16832115b10SPawel Jakub Dawidek return (ENOMEM);
16932115b10SPawel Jakub Dawidek
17032115b10SPawel Jakub Dawidek NV_CHECK(nv);
17132115b10SPawel Jakub Dawidek
17232115b10SPawel Jakub Dawidek return (nv->nv_error);
17332115b10SPawel Jakub Dawidek }
17432115b10SPawel Jakub Dawidek
17532115b10SPawel Jakub Dawidek /*
17632115b10SPawel Jakub Dawidek * Set error for the given nv structure and return previous error.
17732115b10SPawel Jakub Dawidek */
17832115b10SPawel Jakub Dawidek int
nv_set_error(struct nv * nv,int error)17932115b10SPawel Jakub Dawidek nv_set_error(struct nv *nv, int error)
18032115b10SPawel Jakub Dawidek {
18132115b10SPawel Jakub Dawidek int preverr;
18232115b10SPawel Jakub Dawidek
18332115b10SPawel Jakub Dawidek if (nv == NULL)
18432115b10SPawel Jakub Dawidek return (ENOMEM);
18532115b10SPawel Jakub Dawidek
18632115b10SPawel Jakub Dawidek NV_CHECK(nv);
18732115b10SPawel Jakub Dawidek
18832115b10SPawel Jakub Dawidek preverr = nv->nv_error;
18932115b10SPawel Jakub Dawidek nv->nv_error = error;
19032115b10SPawel Jakub Dawidek return (preverr);
19132115b10SPawel Jakub Dawidek }
19232115b10SPawel Jakub Dawidek
19332115b10SPawel Jakub Dawidek /*
19432115b10SPawel Jakub Dawidek * Validate correctness of the entire nv structure and all its elements.
19532115b10SPawel Jakub Dawidek * If extrap is not NULL, store number of extra bytes at the end of the buffer.
19632115b10SPawel Jakub Dawidek */
19732115b10SPawel Jakub Dawidek int
nv_validate(struct nv * nv,size_t * extrap)19832115b10SPawel Jakub Dawidek nv_validate(struct nv *nv, size_t *extrap)
19932115b10SPawel Jakub Dawidek {
20032115b10SPawel Jakub Dawidek struct nvhdr *nvh;
20132115b10SPawel Jakub Dawidek unsigned char *data, *ptr;
20232115b10SPawel Jakub Dawidek size_t dsize, size, vsize;
20332115b10SPawel Jakub Dawidek int error;
20432115b10SPawel Jakub Dawidek
20532115b10SPawel Jakub Dawidek if (nv == NULL) {
20632115b10SPawel Jakub Dawidek errno = ENOMEM;
20732115b10SPawel Jakub Dawidek return (-1);
20832115b10SPawel Jakub Dawidek }
20932115b10SPawel Jakub Dawidek
21032115b10SPawel Jakub Dawidek NV_CHECK(nv);
211adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(nv->nv_error == 0);
21232115b10SPawel Jakub Dawidek
21332115b10SPawel Jakub Dawidek /* TODO: Check that names are unique? */
21432115b10SPawel Jakub Dawidek
21532115b10SPawel Jakub Dawidek error = 0;
21632115b10SPawel Jakub Dawidek ptr = ebuf_data(nv->nv_ebuf, &size);
21732115b10SPawel Jakub Dawidek while (size > 0) {
21832115b10SPawel Jakub Dawidek /*
21932115b10SPawel Jakub Dawidek * Zeros at the end of the buffer are acceptable.
22032115b10SPawel Jakub Dawidek */
22132115b10SPawel Jakub Dawidek if (ptr[0] == '\0')
22232115b10SPawel Jakub Dawidek break;
22332115b10SPawel Jakub Dawidek /*
22432115b10SPawel Jakub Dawidek * Minimum size at this point is size of nvhdr structure, one
22532115b10SPawel Jakub Dawidek * character long name plus terminating '\0'.
22632115b10SPawel Jakub Dawidek */
22732115b10SPawel Jakub Dawidek if (size < sizeof(*nvh) + 2) {
22832115b10SPawel Jakub Dawidek error = EINVAL;
22932115b10SPawel Jakub Dawidek break;
23032115b10SPawel Jakub Dawidek }
23132115b10SPawel Jakub Dawidek nvh = (struct nvhdr *)ptr;
23232115b10SPawel Jakub Dawidek if (size < NVH_HSIZE(nvh)) {
23332115b10SPawel Jakub Dawidek error = EINVAL;
23432115b10SPawel Jakub Dawidek break;
23532115b10SPawel Jakub Dawidek }
23632115b10SPawel Jakub Dawidek if (nvh->nvh_name[nvh->nvh_namesize - 1] != '\0') {
23732115b10SPawel Jakub Dawidek error = EINVAL;
23832115b10SPawel Jakub Dawidek break;
23932115b10SPawel Jakub Dawidek }
24032115b10SPawel Jakub Dawidek if (strlen(nvh->nvh_name) !=
24132115b10SPawel Jakub Dawidek (size_t)(nvh->nvh_namesize - 1)) {
24232115b10SPawel Jakub Dawidek error = EINVAL;
24332115b10SPawel Jakub Dawidek break;
24432115b10SPawel Jakub Dawidek }
24532115b10SPawel Jakub Dawidek if ((nvh->nvh_type & NV_TYPE_MASK) < NV_TYPE_FIRST ||
24632115b10SPawel Jakub Dawidek (nvh->nvh_type & NV_TYPE_MASK) > NV_TYPE_LAST) {
24732115b10SPawel Jakub Dawidek error = EINVAL;
24832115b10SPawel Jakub Dawidek break;
24932115b10SPawel Jakub Dawidek }
25032115b10SPawel Jakub Dawidek dsize = NVH_DSIZE(nvh);
25132115b10SPawel Jakub Dawidek if (dsize == 0) {
25232115b10SPawel Jakub Dawidek error = EINVAL;
25332115b10SPawel Jakub Dawidek break;
25432115b10SPawel Jakub Dawidek }
25532115b10SPawel Jakub Dawidek if (size < NVH_SIZE(nvh)) {
25632115b10SPawel Jakub Dawidek error = EINVAL;
25732115b10SPawel Jakub Dawidek break;
25832115b10SPawel Jakub Dawidek }
25932115b10SPawel Jakub Dawidek vsize = 0;
26032115b10SPawel Jakub Dawidek switch (nvh->nvh_type & NV_TYPE_MASK) {
26132115b10SPawel Jakub Dawidek case NV_TYPE_INT8:
26232115b10SPawel Jakub Dawidek case NV_TYPE_UINT8:
26332115b10SPawel Jakub Dawidek if (vsize == 0)
26432115b10SPawel Jakub Dawidek vsize = 1;
265f9c5a09cSMikolaj Golub /* FALLTHROUGH */
26632115b10SPawel Jakub Dawidek case NV_TYPE_INT16:
26732115b10SPawel Jakub Dawidek case NV_TYPE_UINT16:
26832115b10SPawel Jakub Dawidek if (vsize == 0)
26932115b10SPawel Jakub Dawidek vsize = 2;
270f9c5a09cSMikolaj Golub /* FALLTHROUGH */
27132115b10SPawel Jakub Dawidek case NV_TYPE_INT32:
27232115b10SPawel Jakub Dawidek case NV_TYPE_UINT32:
27332115b10SPawel Jakub Dawidek if (vsize == 0)
27432115b10SPawel Jakub Dawidek vsize = 4;
275f9c5a09cSMikolaj Golub /* FALLTHROUGH */
27632115b10SPawel Jakub Dawidek case NV_TYPE_INT64:
27732115b10SPawel Jakub Dawidek case NV_TYPE_UINT64:
27832115b10SPawel Jakub Dawidek if (vsize == 0)
27932115b10SPawel Jakub Dawidek vsize = 8;
28032115b10SPawel Jakub Dawidek if (dsize != vsize) {
28132115b10SPawel Jakub Dawidek error = EINVAL;
28232115b10SPawel Jakub Dawidek break;
28332115b10SPawel Jakub Dawidek }
28432115b10SPawel Jakub Dawidek break;
28532115b10SPawel Jakub Dawidek case NV_TYPE_INT8_ARRAY:
28632115b10SPawel Jakub Dawidek case NV_TYPE_UINT8_ARRAY:
28732115b10SPawel Jakub Dawidek break;
28832115b10SPawel Jakub Dawidek case NV_TYPE_INT16_ARRAY:
28932115b10SPawel Jakub Dawidek case NV_TYPE_UINT16_ARRAY:
29032115b10SPawel Jakub Dawidek if (vsize == 0)
29132115b10SPawel Jakub Dawidek vsize = 2;
292f9c5a09cSMikolaj Golub /* FALLTHROUGH */
29332115b10SPawel Jakub Dawidek case NV_TYPE_INT32_ARRAY:
29432115b10SPawel Jakub Dawidek case NV_TYPE_UINT32_ARRAY:
29532115b10SPawel Jakub Dawidek if (vsize == 0)
29632115b10SPawel Jakub Dawidek vsize = 4;
297f9c5a09cSMikolaj Golub /* FALLTHROUGH */
29832115b10SPawel Jakub Dawidek case NV_TYPE_INT64_ARRAY:
29932115b10SPawel Jakub Dawidek case NV_TYPE_UINT64_ARRAY:
30032115b10SPawel Jakub Dawidek if (vsize == 0)
30132115b10SPawel Jakub Dawidek vsize = 8;
30232115b10SPawel Jakub Dawidek if ((dsize % vsize) != 0) {
30332115b10SPawel Jakub Dawidek error = EINVAL;
30432115b10SPawel Jakub Dawidek break;
30532115b10SPawel Jakub Dawidek }
30632115b10SPawel Jakub Dawidek break;
30732115b10SPawel Jakub Dawidek case NV_TYPE_STRING:
30832115b10SPawel Jakub Dawidek data = NVH_DATA(nvh);
30932115b10SPawel Jakub Dawidek if (data[dsize - 1] != '\0') {
31032115b10SPawel Jakub Dawidek error = EINVAL;
31132115b10SPawel Jakub Dawidek break;
31232115b10SPawel Jakub Dawidek }
31332115b10SPawel Jakub Dawidek if (strlen((char *)data) != dsize - 1) {
31432115b10SPawel Jakub Dawidek error = EINVAL;
31532115b10SPawel Jakub Dawidek break;
31632115b10SPawel Jakub Dawidek }
31732115b10SPawel Jakub Dawidek break;
31832115b10SPawel Jakub Dawidek default:
319adf8002bSPawel Jakub Dawidek PJDLOG_ABORT("invalid condition");
32032115b10SPawel Jakub Dawidek }
32132115b10SPawel Jakub Dawidek if (error != 0)
32232115b10SPawel Jakub Dawidek break;
32332115b10SPawel Jakub Dawidek ptr += NVH_SIZE(nvh);
32432115b10SPawel Jakub Dawidek size -= NVH_SIZE(nvh);
32532115b10SPawel Jakub Dawidek }
32632115b10SPawel Jakub Dawidek if (error != 0) {
32732115b10SPawel Jakub Dawidek errno = error;
32832115b10SPawel Jakub Dawidek if (nv->nv_error == 0)
32932115b10SPawel Jakub Dawidek nv->nv_error = error;
33032115b10SPawel Jakub Dawidek return (-1);
33132115b10SPawel Jakub Dawidek }
33232115b10SPawel Jakub Dawidek if (extrap != NULL)
33332115b10SPawel Jakub Dawidek *extrap = size;
33432115b10SPawel Jakub Dawidek return (0);
33532115b10SPawel Jakub Dawidek }
33632115b10SPawel Jakub Dawidek
33732115b10SPawel Jakub Dawidek /*
33832115b10SPawel Jakub Dawidek * Convert the given nv structure to network byte order and return ebuf
33932115b10SPawel Jakub Dawidek * structure.
34032115b10SPawel Jakub Dawidek */
34132115b10SPawel Jakub Dawidek struct ebuf *
nv_hton(struct nv * nv)34232115b10SPawel Jakub Dawidek nv_hton(struct nv *nv)
34332115b10SPawel Jakub Dawidek {
34432115b10SPawel Jakub Dawidek struct nvhdr *nvh;
34532115b10SPawel Jakub Dawidek unsigned char *ptr;
34632115b10SPawel Jakub Dawidek size_t size;
34732115b10SPawel Jakub Dawidek
34832115b10SPawel Jakub Dawidek NV_CHECK(nv);
349adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(nv->nv_error == 0);
35032115b10SPawel Jakub Dawidek
35132115b10SPawel Jakub Dawidek ptr = ebuf_data(nv->nv_ebuf, &size);
35232115b10SPawel Jakub Dawidek while (size > 0) {
35332115b10SPawel Jakub Dawidek /*
35432115b10SPawel Jakub Dawidek * Minimum size at this point is size of nvhdr structure,
35532115b10SPawel Jakub Dawidek * one character long name plus terminating '\0'.
35632115b10SPawel Jakub Dawidek */
357adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(size >= sizeof(*nvh) + 2);
35832115b10SPawel Jakub Dawidek nvh = (struct nvhdr *)ptr;
359adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(NVH_SIZE(nvh) <= size);
36032115b10SPawel Jakub Dawidek nv_swap(nvh, false);
36132115b10SPawel Jakub Dawidek ptr += NVH_SIZE(nvh);
36232115b10SPawel Jakub Dawidek size -= NVH_SIZE(nvh);
36332115b10SPawel Jakub Dawidek }
36432115b10SPawel Jakub Dawidek
36532115b10SPawel Jakub Dawidek return (nv->nv_ebuf);
36632115b10SPawel Jakub Dawidek }
36732115b10SPawel Jakub Dawidek
36832115b10SPawel Jakub Dawidek /*
36932115b10SPawel Jakub Dawidek * Create nv structure based on ebuf received from the network.
37032115b10SPawel Jakub Dawidek */
37132115b10SPawel Jakub Dawidek struct nv *
nv_ntoh(struct ebuf * eb)37232115b10SPawel Jakub Dawidek nv_ntoh(struct ebuf *eb)
37332115b10SPawel Jakub Dawidek {
37432115b10SPawel Jakub Dawidek struct nv *nv;
37532115b10SPawel Jakub Dawidek size_t extra;
37632115b10SPawel Jakub Dawidek int rerrno;
37732115b10SPawel Jakub Dawidek
378adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(eb != NULL);
37932115b10SPawel Jakub Dawidek
38032115b10SPawel Jakub Dawidek nv = malloc(sizeof(*nv));
38132115b10SPawel Jakub Dawidek if (nv == NULL)
38232115b10SPawel Jakub Dawidek return (NULL);
38332115b10SPawel Jakub Dawidek nv->nv_error = 0;
38432115b10SPawel Jakub Dawidek nv->nv_ebuf = eb;
38532115b10SPawel Jakub Dawidek nv->nv_magic = NV_MAGIC;
38632115b10SPawel Jakub Dawidek
3872b1b224dSPawel Jakub Dawidek if (nv_validate(nv, &extra) == -1) {
38832115b10SPawel Jakub Dawidek rerrno = errno;
38932115b10SPawel Jakub Dawidek nv->nv_magic = 0;
39032115b10SPawel Jakub Dawidek free(nv);
39132115b10SPawel Jakub Dawidek errno = rerrno;
39232115b10SPawel Jakub Dawidek return (NULL);
39332115b10SPawel Jakub Dawidek }
39432115b10SPawel Jakub Dawidek /*
39532115b10SPawel Jakub Dawidek * Remove extra zeros at the end of the buffer.
39632115b10SPawel Jakub Dawidek */
39732115b10SPawel Jakub Dawidek ebuf_del_tail(eb, extra);
39832115b10SPawel Jakub Dawidek
39932115b10SPawel Jakub Dawidek return (nv);
40032115b10SPawel Jakub Dawidek }
40132115b10SPawel Jakub Dawidek
40232115b10SPawel Jakub Dawidek #define NV_DEFINE_ADD(type, TYPE) \
40332115b10SPawel Jakub Dawidek void \
40432115b10SPawel Jakub Dawidek nv_add_##type(struct nv *nv, type##_t value, const char *namefmt, ...) \
40532115b10SPawel Jakub Dawidek { \
40632115b10SPawel Jakub Dawidek va_list nameap; \
40732115b10SPawel Jakub Dawidek \
40832115b10SPawel Jakub Dawidek va_start(nameap, namefmt); \
40932115b10SPawel Jakub Dawidek nv_addv(nv, (unsigned char *)&value, sizeof(value), \
41032115b10SPawel Jakub Dawidek NV_TYPE_##TYPE, namefmt, nameap); \
41132115b10SPawel Jakub Dawidek va_end(nameap); \
41232115b10SPawel Jakub Dawidek }
41332115b10SPawel Jakub Dawidek
NV_DEFINE_ADD(int8,INT8)41432115b10SPawel Jakub Dawidek NV_DEFINE_ADD(int8, INT8)
41532115b10SPawel Jakub Dawidek NV_DEFINE_ADD(uint8, UINT8)
41632115b10SPawel Jakub Dawidek NV_DEFINE_ADD(int16, INT16)
41732115b10SPawel Jakub Dawidek NV_DEFINE_ADD(uint16, UINT16)
41832115b10SPawel Jakub Dawidek NV_DEFINE_ADD(int32, INT32)
41932115b10SPawel Jakub Dawidek NV_DEFINE_ADD(uint32, UINT32)
42032115b10SPawel Jakub Dawidek NV_DEFINE_ADD(int64, INT64)
42132115b10SPawel Jakub Dawidek NV_DEFINE_ADD(uint64, UINT64)
42232115b10SPawel Jakub Dawidek
42332115b10SPawel Jakub Dawidek #undef NV_DEFINE_ADD
42432115b10SPawel Jakub Dawidek
42532115b10SPawel Jakub Dawidek #define NV_DEFINE_ADD_ARRAY(type, TYPE) \
42632115b10SPawel Jakub Dawidek void \
42732115b10SPawel Jakub Dawidek nv_add_##type##_array(struct nv *nv, const type##_t *value, \
42832115b10SPawel Jakub Dawidek size_t nsize, const char *namefmt, ...) \
42932115b10SPawel Jakub Dawidek { \
43032115b10SPawel Jakub Dawidek va_list nameap; \
43132115b10SPawel Jakub Dawidek \
43232115b10SPawel Jakub Dawidek va_start(nameap, namefmt); \
43332115b10SPawel Jakub Dawidek nv_addv(nv, (const unsigned char *)value, \
43432115b10SPawel Jakub Dawidek sizeof(value[0]) * nsize, NV_TYPE_##TYPE##_ARRAY, namefmt, \
43532115b10SPawel Jakub Dawidek nameap); \
43632115b10SPawel Jakub Dawidek va_end(nameap); \
43732115b10SPawel Jakub Dawidek }
43832115b10SPawel Jakub Dawidek
43932115b10SPawel Jakub Dawidek NV_DEFINE_ADD_ARRAY(int8, INT8)
44032115b10SPawel Jakub Dawidek NV_DEFINE_ADD_ARRAY(uint8, UINT8)
44132115b10SPawel Jakub Dawidek NV_DEFINE_ADD_ARRAY(int16, INT16)
44232115b10SPawel Jakub Dawidek NV_DEFINE_ADD_ARRAY(uint16, UINT16)
44332115b10SPawel Jakub Dawidek NV_DEFINE_ADD_ARRAY(int32, INT32)
44432115b10SPawel Jakub Dawidek NV_DEFINE_ADD_ARRAY(uint32, UINT32)
44532115b10SPawel Jakub Dawidek NV_DEFINE_ADD_ARRAY(int64, INT64)
44632115b10SPawel Jakub Dawidek NV_DEFINE_ADD_ARRAY(uint64, UINT64)
44732115b10SPawel Jakub Dawidek
44832115b10SPawel Jakub Dawidek #undef NV_DEFINE_ADD_ARRAY
44932115b10SPawel Jakub Dawidek
45032115b10SPawel Jakub Dawidek void
45132115b10SPawel Jakub Dawidek nv_add_string(struct nv *nv, const char *value, const char *namefmt, ...)
45232115b10SPawel Jakub Dawidek {
45332115b10SPawel Jakub Dawidek va_list nameap;
45432115b10SPawel Jakub Dawidek size_t size;
45532115b10SPawel Jakub Dawidek
45632115b10SPawel Jakub Dawidek size = strlen(value) + 1;
45732115b10SPawel Jakub Dawidek
45832115b10SPawel Jakub Dawidek va_start(nameap, namefmt);
45932115b10SPawel Jakub Dawidek nv_addv(nv, (const unsigned char *)value, size, NV_TYPE_STRING,
46032115b10SPawel Jakub Dawidek namefmt, nameap);
46132115b10SPawel Jakub Dawidek va_end(nameap);
46232115b10SPawel Jakub Dawidek }
46332115b10SPawel Jakub Dawidek
46432115b10SPawel Jakub Dawidek void
nv_add_stringf(struct nv * nv,const char * name,const char * valuefmt,...)46532115b10SPawel Jakub Dawidek nv_add_stringf(struct nv *nv, const char *name, const char *valuefmt, ...)
46632115b10SPawel Jakub Dawidek {
46732115b10SPawel Jakub Dawidek va_list valueap;
46832115b10SPawel Jakub Dawidek
46932115b10SPawel Jakub Dawidek va_start(valueap, valuefmt);
47032115b10SPawel Jakub Dawidek nv_add_stringv(nv, name, valuefmt, valueap);
47132115b10SPawel Jakub Dawidek va_end(valueap);
47232115b10SPawel Jakub Dawidek }
47332115b10SPawel Jakub Dawidek
47432115b10SPawel Jakub Dawidek void
nv_add_stringv(struct nv * nv,const char * name,const char * valuefmt,va_list valueap)47532115b10SPawel Jakub Dawidek nv_add_stringv(struct nv *nv, const char *name, const char *valuefmt,
47632115b10SPawel Jakub Dawidek va_list valueap)
47732115b10SPawel Jakub Dawidek {
47832115b10SPawel Jakub Dawidek char *value;
47932115b10SPawel Jakub Dawidek ssize_t size;
48032115b10SPawel Jakub Dawidek
48132115b10SPawel Jakub Dawidek size = vasprintf(&value, valuefmt, valueap);
4822b1b224dSPawel Jakub Dawidek if (size == -1) {
48332115b10SPawel Jakub Dawidek if (nv->nv_error == 0)
48432115b10SPawel Jakub Dawidek nv->nv_error = ENOMEM;
48532115b10SPawel Jakub Dawidek return;
48632115b10SPawel Jakub Dawidek }
48732115b10SPawel Jakub Dawidek size++;
48832115b10SPawel Jakub Dawidek nv_add(nv, (const unsigned char *)value, size, NV_TYPE_STRING, name);
48932115b10SPawel Jakub Dawidek free(value);
49032115b10SPawel Jakub Dawidek }
49132115b10SPawel Jakub Dawidek
49232115b10SPawel Jakub Dawidek #define NV_DEFINE_GET(type, TYPE) \
49332115b10SPawel Jakub Dawidek type##_t \
49432115b10SPawel Jakub Dawidek nv_get_##type(struct nv *nv, const char *namefmt, ...) \
49532115b10SPawel Jakub Dawidek { \
49632115b10SPawel Jakub Dawidek struct nvhdr *nvh; \
49732115b10SPawel Jakub Dawidek va_list nameap; \
49832115b10SPawel Jakub Dawidek type##_t value; \
49932115b10SPawel Jakub Dawidek \
50032115b10SPawel Jakub Dawidek va_start(nameap, namefmt); \
50132115b10SPawel Jakub Dawidek nvh = nv_find(nv, NV_TYPE_##TYPE, namefmt, nameap); \
50232115b10SPawel Jakub Dawidek va_end(nameap); \
50332115b10SPawel Jakub Dawidek if (nvh == NULL) \
50432115b10SPawel Jakub Dawidek return (0); \
505adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST);\
506adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(sizeof(value) == nvh->nvh_dsize); \
50732115b10SPawel Jakub Dawidek bcopy(NVH_DATA(nvh), &value, sizeof(value)); \
50832115b10SPawel Jakub Dawidek \
50932115b10SPawel Jakub Dawidek return (value); \
51032115b10SPawel Jakub Dawidek }
51132115b10SPawel Jakub Dawidek
NV_DEFINE_GET(int8,INT8)51232115b10SPawel Jakub Dawidek NV_DEFINE_GET(int8, INT8)
51332115b10SPawel Jakub Dawidek NV_DEFINE_GET(uint8, UINT8)
51432115b10SPawel Jakub Dawidek NV_DEFINE_GET(int16, INT16)
51532115b10SPawel Jakub Dawidek NV_DEFINE_GET(uint16, UINT16)
51632115b10SPawel Jakub Dawidek NV_DEFINE_GET(int32, INT32)
51732115b10SPawel Jakub Dawidek NV_DEFINE_GET(uint32, UINT32)
51832115b10SPawel Jakub Dawidek NV_DEFINE_GET(int64, INT64)
51932115b10SPawel Jakub Dawidek NV_DEFINE_GET(uint64, UINT64)
52032115b10SPawel Jakub Dawidek
52132115b10SPawel Jakub Dawidek #undef NV_DEFINE_GET
52232115b10SPawel Jakub Dawidek
52332115b10SPawel Jakub Dawidek #define NV_DEFINE_GET_ARRAY(type, TYPE) \
52432115b10SPawel Jakub Dawidek const type##_t * \
52532115b10SPawel Jakub Dawidek nv_get_##type##_array(struct nv *nv, size_t *sizep, \
52632115b10SPawel Jakub Dawidek const char *namefmt, ...) \
52732115b10SPawel Jakub Dawidek { \
52832115b10SPawel Jakub Dawidek struct nvhdr *nvh; \
52932115b10SPawel Jakub Dawidek va_list nameap; \
53032115b10SPawel Jakub Dawidek \
53132115b10SPawel Jakub Dawidek va_start(nameap, namefmt); \
53232115b10SPawel Jakub Dawidek nvh = nv_find(nv, NV_TYPE_##TYPE##_ARRAY, namefmt, nameap); \
53332115b10SPawel Jakub Dawidek va_end(nameap); \
53432115b10SPawel Jakub Dawidek if (nvh == NULL) \
53532115b10SPawel Jakub Dawidek return (NULL); \
536adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST);\
537adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT((nvh->nvh_dsize % sizeof(type##_t)) == 0); \
53832115b10SPawel Jakub Dawidek if (sizep != NULL) \
53932115b10SPawel Jakub Dawidek *sizep = nvh->nvh_dsize / sizeof(type##_t); \
54032115b10SPawel Jakub Dawidek return ((type##_t *)(void *)NVH_DATA(nvh)); \
54132115b10SPawel Jakub Dawidek }
54232115b10SPawel Jakub Dawidek
54332115b10SPawel Jakub Dawidek NV_DEFINE_GET_ARRAY(int8, INT8)
54432115b10SPawel Jakub Dawidek NV_DEFINE_GET_ARRAY(uint8, UINT8)
54532115b10SPawel Jakub Dawidek NV_DEFINE_GET_ARRAY(int16, INT16)
54632115b10SPawel Jakub Dawidek NV_DEFINE_GET_ARRAY(uint16, UINT16)
54732115b10SPawel Jakub Dawidek NV_DEFINE_GET_ARRAY(int32, INT32)
54832115b10SPawel Jakub Dawidek NV_DEFINE_GET_ARRAY(uint32, UINT32)
54932115b10SPawel Jakub Dawidek NV_DEFINE_GET_ARRAY(int64, INT64)
55032115b10SPawel Jakub Dawidek NV_DEFINE_GET_ARRAY(uint64, UINT64)
55132115b10SPawel Jakub Dawidek
55232115b10SPawel Jakub Dawidek #undef NV_DEFINE_GET_ARRAY
55332115b10SPawel Jakub Dawidek
55432115b10SPawel Jakub Dawidek const char *
55532115b10SPawel Jakub Dawidek nv_get_string(struct nv *nv, const char *namefmt, ...)
55632115b10SPawel Jakub Dawidek {
55732115b10SPawel Jakub Dawidek struct nvhdr *nvh;
55832115b10SPawel Jakub Dawidek va_list nameap;
55932115b10SPawel Jakub Dawidek char *str;
56032115b10SPawel Jakub Dawidek
56132115b10SPawel Jakub Dawidek va_start(nameap, namefmt);
56232115b10SPawel Jakub Dawidek nvh = nv_find(nv, NV_TYPE_STRING, namefmt, nameap);
56332115b10SPawel Jakub Dawidek va_end(nameap);
56432115b10SPawel Jakub Dawidek if (nvh == NULL)
56532115b10SPawel Jakub Dawidek return (NULL);
566adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST);
567adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(nvh->nvh_dsize >= 1);
5684d70e06fSMikolaj Golub str = (char *)NVH_DATA(nvh);
569adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(str[nvh->nvh_dsize - 1] == '\0');
570adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(strlen(str) == nvh->nvh_dsize - 1);
57132115b10SPawel Jakub Dawidek return (str);
57232115b10SPawel Jakub Dawidek }
57332115b10SPawel Jakub Dawidek
574eed4e65fSPawel Jakub Dawidek static bool
nv_vexists(struct nv * nv,const char * namefmt,va_list nameap)575eed4e65fSPawel Jakub Dawidek nv_vexists(struct nv *nv, const char *namefmt, va_list nameap)
576b9ffbb0aSPawel Jakub Dawidek {
577b9ffbb0aSPawel Jakub Dawidek struct nvhdr *nvh;
578b9ffbb0aSPawel Jakub Dawidek int snverror, serrno;
579b9ffbb0aSPawel Jakub Dawidek
580b9ffbb0aSPawel Jakub Dawidek if (nv == NULL)
581b9ffbb0aSPawel Jakub Dawidek return (false);
582b9ffbb0aSPawel Jakub Dawidek
583b9ffbb0aSPawel Jakub Dawidek serrno = errno;
584b9ffbb0aSPawel Jakub Dawidek snverror = nv->nv_error;
585b9ffbb0aSPawel Jakub Dawidek
586b9ffbb0aSPawel Jakub Dawidek nvh = nv_find(nv, NV_TYPE_NONE, namefmt, nameap);
587b9ffbb0aSPawel Jakub Dawidek
588b9ffbb0aSPawel Jakub Dawidek errno = serrno;
589b9ffbb0aSPawel Jakub Dawidek nv->nv_error = snverror;
590b9ffbb0aSPawel Jakub Dawidek
591b9ffbb0aSPawel Jakub Dawidek return (nvh != NULL);
592b9ffbb0aSPawel Jakub Dawidek }
593b9ffbb0aSPawel Jakub Dawidek
594eed4e65fSPawel Jakub Dawidek bool
nv_exists(struct nv * nv,const char * namefmt,...)595eed4e65fSPawel Jakub Dawidek nv_exists(struct nv *nv, const char *namefmt, ...)
596eed4e65fSPawel Jakub Dawidek {
597eed4e65fSPawel Jakub Dawidek va_list nameap;
598eed4e65fSPawel Jakub Dawidek bool ret;
599eed4e65fSPawel Jakub Dawidek
600eed4e65fSPawel Jakub Dawidek va_start(nameap, namefmt);
601eed4e65fSPawel Jakub Dawidek ret = nv_vexists(nv, namefmt, nameap);
602eed4e65fSPawel Jakub Dawidek va_end(nameap);
603eed4e65fSPawel Jakub Dawidek
604eed4e65fSPawel Jakub Dawidek return (ret);
605eed4e65fSPawel Jakub Dawidek }
606eed4e65fSPawel Jakub Dawidek
607eed4e65fSPawel Jakub Dawidek void
nv_assert(struct nv * nv,const char * namefmt,...)608eed4e65fSPawel Jakub Dawidek nv_assert(struct nv *nv, const char *namefmt, ...)
609eed4e65fSPawel Jakub Dawidek {
610eed4e65fSPawel Jakub Dawidek va_list nameap;
611eed4e65fSPawel Jakub Dawidek
612eed4e65fSPawel Jakub Dawidek va_start(nameap, namefmt);
613adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(nv_vexists(nv, namefmt, nameap));
614eed4e65fSPawel Jakub Dawidek va_end(nameap);
615eed4e65fSPawel Jakub Dawidek }
616eed4e65fSPawel Jakub Dawidek
61732115b10SPawel Jakub Dawidek /*
61832115b10SPawel Jakub Dawidek * Dump content of the nv structure.
61932115b10SPawel Jakub Dawidek */
62032115b10SPawel Jakub Dawidek void
nv_dump(struct nv * nv)62132115b10SPawel Jakub Dawidek nv_dump(struct nv *nv)
62232115b10SPawel Jakub Dawidek {
62332115b10SPawel Jakub Dawidek struct nvhdr *nvh;
62432115b10SPawel Jakub Dawidek unsigned char *data, *ptr;
62532115b10SPawel Jakub Dawidek size_t dsize, size;
62632115b10SPawel Jakub Dawidek unsigned int ii;
62732115b10SPawel Jakub Dawidek bool swap;
62832115b10SPawel Jakub Dawidek
6292b1b224dSPawel Jakub Dawidek if (nv_validate(nv, NULL) == -1) {
63032115b10SPawel Jakub Dawidek printf("error: %d\n", errno);
63132115b10SPawel Jakub Dawidek return;
63232115b10SPawel Jakub Dawidek }
63332115b10SPawel Jakub Dawidek
63432115b10SPawel Jakub Dawidek NV_CHECK(nv);
635adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(nv->nv_error == 0);
63632115b10SPawel Jakub Dawidek
63732115b10SPawel Jakub Dawidek ptr = ebuf_data(nv->nv_ebuf, &size);
63832115b10SPawel Jakub Dawidek while (size > 0) {
639adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(size >= sizeof(*nvh) + 2);
64032115b10SPawel Jakub Dawidek nvh = (struct nvhdr *)ptr;
641adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(size >= NVH_SIZE(nvh));
64232115b10SPawel Jakub Dawidek swap = ((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_NETWORK);
64332115b10SPawel Jakub Dawidek dsize = NVH_DSIZE(nvh);
64432115b10SPawel Jakub Dawidek data = NVH_DATA(nvh);
64532115b10SPawel Jakub Dawidek printf(" %s", nvh->nvh_name);
64632115b10SPawel Jakub Dawidek switch (nvh->nvh_type & NV_TYPE_MASK) {
64732115b10SPawel Jakub Dawidek case NV_TYPE_INT8:
64832115b10SPawel Jakub Dawidek printf("(int8): %jd", (intmax_t)(*(int8_t *)data));
64932115b10SPawel Jakub Dawidek break;
65032115b10SPawel Jakub Dawidek case NV_TYPE_UINT8:
65132115b10SPawel Jakub Dawidek printf("(uint8): %ju", (uintmax_t)(*(uint8_t *)data));
65232115b10SPawel Jakub Dawidek break;
65332115b10SPawel Jakub Dawidek case NV_TYPE_INT16:
65432115b10SPawel Jakub Dawidek printf("(int16): %jd", swap ?
65532115b10SPawel Jakub Dawidek (intmax_t)le16toh(*(int16_t *)(void *)data) :
65632115b10SPawel Jakub Dawidek (intmax_t)*(int16_t *)(void *)data);
65732115b10SPawel Jakub Dawidek break;
65832115b10SPawel Jakub Dawidek case NV_TYPE_UINT16:
65932115b10SPawel Jakub Dawidek printf("(uint16): %ju", swap ?
66032115b10SPawel Jakub Dawidek (uintmax_t)le16toh(*(uint16_t *)(void *)data) :
66132115b10SPawel Jakub Dawidek (uintmax_t)*(uint16_t *)(void *)data);
66232115b10SPawel Jakub Dawidek break;
66332115b10SPawel Jakub Dawidek case NV_TYPE_INT32:
66432115b10SPawel Jakub Dawidek printf("(int32): %jd", swap ?
66532115b10SPawel Jakub Dawidek (intmax_t)le32toh(*(int32_t *)(void *)data) :
66632115b10SPawel Jakub Dawidek (intmax_t)*(int32_t *)(void *)data);
66732115b10SPawel Jakub Dawidek break;
66832115b10SPawel Jakub Dawidek case NV_TYPE_UINT32:
66932115b10SPawel Jakub Dawidek printf("(uint32): %ju", swap ?
67032115b10SPawel Jakub Dawidek (uintmax_t)le32toh(*(uint32_t *)(void *)data) :
67132115b10SPawel Jakub Dawidek (uintmax_t)*(uint32_t *)(void *)data);
67232115b10SPawel Jakub Dawidek break;
67332115b10SPawel Jakub Dawidek case NV_TYPE_INT64:
67432115b10SPawel Jakub Dawidek printf("(int64): %jd", swap ?
67532115b10SPawel Jakub Dawidek (intmax_t)le64toh(*(int64_t *)(void *)data) :
67632115b10SPawel Jakub Dawidek (intmax_t)*(int64_t *)(void *)data);
67732115b10SPawel Jakub Dawidek break;
67832115b10SPawel Jakub Dawidek case NV_TYPE_UINT64:
67932115b10SPawel Jakub Dawidek printf("(uint64): %ju", swap ?
68032115b10SPawel Jakub Dawidek (uintmax_t)le64toh(*(uint64_t *)(void *)data) :
68132115b10SPawel Jakub Dawidek (uintmax_t)*(uint64_t *)(void *)data);
68232115b10SPawel Jakub Dawidek break;
68332115b10SPawel Jakub Dawidek case NV_TYPE_INT8_ARRAY:
68432115b10SPawel Jakub Dawidek printf("(int8 array):");
68532115b10SPawel Jakub Dawidek for (ii = 0; ii < dsize; ii++)
68632115b10SPawel Jakub Dawidek printf(" %jd", (intmax_t)((int8_t *)data)[ii]);
68732115b10SPawel Jakub Dawidek break;
68832115b10SPawel Jakub Dawidek case NV_TYPE_UINT8_ARRAY:
68932115b10SPawel Jakub Dawidek printf("(uint8 array):");
69032115b10SPawel Jakub Dawidek for (ii = 0; ii < dsize; ii++)
69132115b10SPawel Jakub Dawidek printf(" %ju", (uintmax_t)((uint8_t *)data)[ii]);
69232115b10SPawel Jakub Dawidek break;
69332115b10SPawel Jakub Dawidek case NV_TYPE_INT16_ARRAY:
69432115b10SPawel Jakub Dawidek printf("(int16 array):");
69532115b10SPawel Jakub Dawidek for (ii = 0; ii < dsize / 2; ii++) {
69632115b10SPawel Jakub Dawidek printf(" %jd", swap ?
69732115b10SPawel Jakub Dawidek (intmax_t)le16toh(((int16_t *)(void *)data)[ii]) :
69832115b10SPawel Jakub Dawidek (intmax_t)((int16_t *)(void *)data)[ii]);
69932115b10SPawel Jakub Dawidek }
70032115b10SPawel Jakub Dawidek break;
70132115b10SPawel Jakub Dawidek case NV_TYPE_UINT16_ARRAY:
70232115b10SPawel Jakub Dawidek printf("(uint16 array):");
70332115b10SPawel Jakub Dawidek for (ii = 0; ii < dsize / 2; ii++) {
70432115b10SPawel Jakub Dawidek printf(" %ju", swap ?
70532115b10SPawel Jakub Dawidek (uintmax_t)le16toh(((uint16_t *)(void *)data)[ii]) :
70632115b10SPawel Jakub Dawidek (uintmax_t)((uint16_t *)(void *)data)[ii]);
70732115b10SPawel Jakub Dawidek }
70832115b10SPawel Jakub Dawidek break;
70932115b10SPawel Jakub Dawidek case NV_TYPE_INT32_ARRAY:
71032115b10SPawel Jakub Dawidek printf("(int32 array):");
71132115b10SPawel Jakub Dawidek for (ii = 0; ii < dsize / 4; ii++) {
71232115b10SPawel Jakub Dawidek printf(" %jd", swap ?
71332115b10SPawel Jakub Dawidek (intmax_t)le32toh(((int32_t *)(void *)data)[ii]) :
71432115b10SPawel Jakub Dawidek (intmax_t)((int32_t *)(void *)data)[ii]);
71532115b10SPawel Jakub Dawidek }
71632115b10SPawel Jakub Dawidek break;
71732115b10SPawel Jakub Dawidek case NV_TYPE_UINT32_ARRAY:
71832115b10SPawel Jakub Dawidek printf("(uint32 array):");
71932115b10SPawel Jakub Dawidek for (ii = 0; ii < dsize / 4; ii++) {
72032115b10SPawel Jakub Dawidek printf(" %ju", swap ?
72132115b10SPawel Jakub Dawidek (uintmax_t)le32toh(((uint32_t *)(void *)data)[ii]) :
72232115b10SPawel Jakub Dawidek (uintmax_t)((uint32_t *)(void *)data)[ii]);
72332115b10SPawel Jakub Dawidek }
72432115b10SPawel Jakub Dawidek break;
72532115b10SPawel Jakub Dawidek case NV_TYPE_INT64_ARRAY:
72632115b10SPawel Jakub Dawidek printf("(int64 array):");
72732115b10SPawel Jakub Dawidek for (ii = 0; ii < dsize / 8; ii++) {
72832115b10SPawel Jakub Dawidek printf(" %ju", swap ?
72932115b10SPawel Jakub Dawidek (uintmax_t)le64toh(((uint64_t *)(void *)data)[ii]) :
73032115b10SPawel Jakub Dawidek (uintmax_t)((uint64_t *)(void *)data)[ii]);
73132115b10SPawel Jakub Dawidek }
73232115b10SPawel Jakub Dawidek break;
73332115b10SPawel Jakub Dawidek case NV_TYPE_UINT64_ARRAY:
73432115b10SPawel Jakub Dawidek printf("(uint64 array):");
73532115b10SPawel Jakub Dawidek for (ii = 0; ii < dsize / 8; ii++) {
73632115b10SPawel Jakub Dawidek printf(" %ju", swap ?
73732115b10SPawel Jakub Dawidek (uintmax_t)le64toh(((uint64_t *)(void *)data)[ii]) :
73832115b10SPawel Jakub Dawidek (uintmax_t)((uint64_t *)(void *)data)[ii]);
73932115b10SPawel Jakub Dawidek }
74032115b10SPawel Jakub Dawidek break;
74132115b10SPawel Jakub Dawidek case NV_TYPE_STRING:
74232115b10SPawel Jakub Dawidek printf("(string): %s", (char *)data);
74332115b10SPawel Jakub Dawidek break;
74432115b10SPawel Jakub Dawidek default:
745adf8002bSPawel Jakub Dawidek PJDLOG_ABORT("invalid condition");
74632115b10SPawel Jakub Dawidek }
74732115b10SPawel Jakub Dawidek printf("\n");
74832115b10SPawel Jakub Dawidek ptr += NVH_SIZE(nvh);
74932115b10SPawel Jakub Dawidek size -= NVH_SIZE(nvh);
75032115b10SPawel Jakub Dawidek }
75132115b10SPawel Jakub Dawidek }
75232115b10SPawel Jakub Dawidek
75332115b10SPawel Jakub Dawidek /*
75432115b10SPawel Jakub Dawidek * Local routines below.
75532115b10SPawel Jakub Dawidek */
75632115b10SPawel Jakub Dawidek
75732115b10SPawel Jakub Dawidek static void
nv_add(struct nv * nv,const unsigned char * value,size_t vsize,int type,const char * name)75832115b10SPawel Jakub Dawidek nv_add(struct nv *nv, const unsigned char *value, size_t vsize, int type,
75932115b10SPawel Jakub Dawidek const char *name)
76032115b10SPawel Jakub Dawidek {
76132115b10SPawel Jakub Dawidek static unsigned char align[7];
76232115b10SPawel Jakub Dawidek struct nvhdr *nvh;
76332115b10SPawel Jakub Dawidek size_t namesize;
76432115b10SPawel Jakub Dawidek
76532115b10SPawel Jakub Dawidek if (nv == NULL) {
76632115b10SPawel Jakub Dawidek errno = ENOMEM;
76732115b10SPawel Jakub Dawidek return;
76832115b10SPawel Jakub Dawidek }
76932115b10SPawel Jakub Dawidek
77032115b10SPawel Jakub Dawidek NV_CHECK(nv);
77132115b10SPawel Jakub Dawidek
77232115b10SPawel Jakub Dawidek namesize = strlen(name) + 1;
77332115b10SPawel Jakub Dawidek
77432115b10SPawel Jakub Dawidek nvh = malloc(sizeof(*nvh) + roundup2(namesize, 8));
77532115b10SPawel Jakub Dawidek if (nvh == NULL) {
77632115b10SPawel Jakub Dawidek if (nv->nv_error == 0)
77732115b10SPawel Jakub Dawidek nv->nv_error = ENOMEM;
77832115b10SPawel Jakub Dawidek return;
77932115b10SPawel Jakub Dawidek }
78032115b10SPawel Jakub Dawidek nvh->nvh_type = NV_ORDER_HOST | type;
78132115b10SPawel Jakub Dawidek nvh->nvh_namesize = (uint8_t)namesize;
78232115b10SPawel Jakub Dawidek nvh->nvh_dsize = (uint32_t)vsize;
78332115b10SPawel Jakub Dawidek bcopy(name, nvh->nvh_name, namesize);
78432115b10SPawel Jakub Dawidek
78532115b10SPawel Jakub Dawidek /* Add header first. */
7862b1b224dSPawel Jakub Dawidek if (ebuf_add_tail(nv->nv_ebuf, nvh, NVH_HSIZE(nvh)) == -1) {
787adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(errno != 0);
78832115b10SPawel Jakub Dawidek if (nv->nv_error == 0)
78932115b10SPawel Jakub Dawidek nv->nv_error = errno;
7909f31eddbSPawel Jakub Dawidek free(nvh);
79132115b10SPawel Jakub Dawidek return;
79232115b10SPawel Jakub Dawidek }
7939f31eddbSPawel Jakub Dawidek free(nvh);
79432115b10SPawel Jakub Dawidek /* Add the actual data. */
7952b1b224dSPawel Jakub Dawidek if (ebuf_add_tail(nv->nv_ebuf, value, vsize) == -1) {
796adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(errno != 0);
79732115b10SPawel Jakub Dawidek if (nv->nv_error == 0)
79832115b10SPawel Jakub Dawidek nv->nv_error = errno;
79932115b10SPawel Jakub Dawidek return;
80032115b10SPawel Jakub Dawidek }
80132115b10SPawel Jakub Dawidek /* Align the data (if needed). */
80232115b10SPawel Jakub Dawidek vsize = roundup2(vsize, 8) - vsize;
80332115b10SPawel Jakub Dawidek if (vsize == 0)
80432115b10SPawel Jakub Dawidek return;
805adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(vsize > 0 && vsize <= sizeof(align));
8062b1b224dSPawel Jakub Dawidek if (ebuf_add_tail(nv->nv_ebuf, align, vsize) == -1) {
807adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(errno != 0);
80832115b10SPawel Jakub Dawidek if (nv->nv_error == 0)
80932115b10SPawel Jakub Dawidek nv->nv_error = errno;
81032115b10SPawel Jakub Dawidek return;
81132115b10SPawel Jakub Dawidek }
81232115b10SPawel Jakub Dawidek }
81332115b10SPawel Jakub Dawidek
81432115b10SPawel Jakub Dawidek static void
nv_addv(struct nv * nv,const unsigned char * value,size_t vsize,int type,const char * namefmt,va_list nameap)81532115b10SPawel Jakub Dawidek nv_addv(struct nv *nv, const unsigned char *value, size_t vsize, int type,
81632115b10SPawel Jakub Dawidek const char *namefmt, va_list nameap)
81732115b10SPawel Jakub Dawidek {
81832115b10SPawel Jakub Dawidek char name[255];
81932115b10SPawel Jakub Dawidek size_t namesize;
82032115b10SPawel Jakub Dawidek
82132115b10SPawel Jakub Dawidek namesize = vsnprintf(name, sizeof(name), namefmt, nameap);
822adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(namesize > 0 && namesize < sizeof(name));
82332115b10SPawel Jakub Dawidek
82432115b10SPawel Jakub Dawidek nv_add(nv, value, vsize, type, name);
82532115b10SPawel Jakub Dawidek }
82632115b10SPawel Jakub Dawidek
82732115b10SPawel Jakub Dawidek static struct nvhdr *
nv_find(struct nv * nv,int type,const char * namefmt,va_list nameap)82832115b10SPawel Jakub Dawidek nv_find(struct nv *nv, int type, const char *namefmt, va_list nameap)
82932115b10SPawel Jakub Dawidek {
83032115b10SPawel Jakub Dawidek char name[255];
83132115b10SPawel Jakub Dawidek struct nvhdr *nvh;
83232115b10SPawel Jakub Dawidek unsigned char *ptr;
83332115b10SPawel Jakub Dawidek size_t size, namesize;
83432115b10SPawel Jakub Dawidek
83532115b10SPawel Jakub Dawidek if (nv == NULL) {
83632115b10SPawel Jakub Dawidek errno = ENOMEM;
83732115b10SPawel Jakub Dawidek return (NULL);
83832115b10SPawel Jakub Dawidek }
83932115b10SPawel Jakub Dawidek
84032115b10SPawel Jakub Dawidek NV_CHECK(nv);
84132115b10SPawel Jakub Dawidek
84232115b10SPawel Jakub Dawidek namesize = vsnprintf(name, sizeof(name), namefmt, nameap);
843adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(namesize > 0 && namesize < sizeof(name));
84432115b10SPawel Jakub Dawidek namesize++;
84532115b10SPawel Jakub Dawidek
84632115b10SPawel Jakub Dawidek ptr = ebuf_data(nv->nv_ebuf, &size);
84732115b10SPawel Jakub Dawidek while (size > 0) {
848adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(size >= sizeof(*nvh) + 2);
84932115b10SPawel Jakub Dawidek nvh = (struct nvhdr *)ptr;
850adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(size >= NVH_SIZE(nvh));
85132115b10SPawel Jakub Dawidek nv_swap(nvh, true);
85232115b10SPawel Jakub Dawidek if (strcmp(nvh->nvh_name, name) == 0) {
853b9ffbb0aSPawel Jakub Dawidek if (type != NV_TYPE_NONE &&
854b9ffbb0aSPawel Jakub Dawidek (nvh->nvh_type & NV_TYPE_MASK) != type) {
85532115b10SPawel Jakub Dawidek errno = EINVAL;
85632115b10SPawel Jakub Dawidek if (nv->nv_error == 0)
85732115b10SPawel Jakub Dawidek nv->nv_error = EINVAL;
85832115b10SPawel Jakub Dawidek return (NULL);
85932115b10SPawel Jakub Dawidek }
86032115b10SPawel Jakub Dawidek return (nvh);
86132115b10SPawel Jakub Dawidek }
86232115b10SPawel Jakub Dawidek ptr += NVH_SIZE(nvh);
86332115b10SPawel Jakub Dawidek size -= NVH_SIZE(nvh);
86432115b10SPawel Jakub Dawidek }
86532115b10SPawel Jakub Dawidek errno = ENOENT;
86632115b10SPawel Jakub Dawidek if (nv->nv_error == 0)
86732115b10SPawel Jakub Dawidek nv->nv_error = ENOENT;
86832115b10SPawel Jakub Dawidek return (NULL);
86932115b10SPawel Jakub Dawidek }
87032115b10SPawel Jakub Dawidek
87132115b10SPawel Jakub Dawidek static void
nv_swap(struct nvhdr * nvh,bool tohost)87232115b10SPawel Jakub Dawidek nv_swap(struct nvhdr *nvh, bool tohost)
87332115b10SPawel Jakub Dawidek {
87432115b10SPawel Jakub Dawidek unsigned char *data, *end, *p;
87532115b10SPawel Jakub Dawidek size_t vsize;
87632115b10SPawel Jakub Dawidek
87732115b10SPawel Jakub Dawidek data = NVH_DATA(nvh);
87832115b10SPawel Jakub Dawidek if (tohost) {
87932115b10SPawel Jakub Dawidek if ((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST)
88032115b10SPawel Jakub Dawidek return;
88132115b10SPawel Jakub Dawidek nvh->nvh_dsize = le32toh(nvh->nvh_dsize);
88232115b10SPawel Jakub Dawidek end = data + nvh->nvh_dsize;
88332115b10SPawel Jakub Dawidek nvh->nvh_type &= ~NV_ORDER_MASK;
88432115b10SPawel Jakub Dawidek nvh->nvh_type |= NV_ORDER_HOST;
88532115b10SPawel Jakub Dawidek } else {
88632115b10SPawel Jakub Dawidek if ((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_NETWORK)
88732115b10SPawel Jakub Dawidek return;
88832115b10SPawel Jakub Dawidek end = data + nvh->nvh_dsize;
88932115b10SPawel Jakub Dawidek nvh->nvh_dsize = htole32(nvh->nvh_dsize);
89032115b10SPawel Jakub Dawidek nvh->nvh_type &= ~NV_ORDER_MASK;
89132115b10SPawel Jakub Dawidek nvh->nvh_type |= NV_ORDER_NETWORK;
89232115b10SPawel Jakub Dawidek }
89332115b10SPawel Jakub Dawidek
89432115b10SPawel Jakub Dawidek vsize = 0;
89532115b10SPawel Jakub Dawidek
89632115b10SPawel Jakub Dawidek switch (nvh->nvh_type & NV_TYPE_MASK) {
89732115b10SPawel Jakub Dawidek case NV_TYPE_INT8:
89832115b10SPawel Jakub Dawidek case NV_TYPE_UINT8:
89932115b10SPawel Jakub Dawidek case NV_TYPE_INT8_ARRAY:
90032115b10SPawel Jakub Dawidek case NV_TYPE_UINT8_ARRAY:
90132115b10SPawel Jakub Dawidek break;
90232115b10SPawel Jakub Dawidek case NV_TYPE_INT16:
90332115b10SPawel Jakub Dawidek case NV_TYPE_UINT16:
90432115b10SPawel Jakub Dawidek case NV_TYPE_INT16_ARRAY:
90532115b10SPawel Jakub Dawidek case NV_TYPE_UINT16_ARRAY:
90632115b10SPawel Jakub Dawidek if (vsize == 0)
90732115b10SPawel Jakub Dawidek vsize = 2;
908f9c5a09cSMikolaj Golub /* FALLTHROUGH */
90932115b10SPawel Jakub Dawidek case NV_TYPE_INT32:
91032115b10SPawel Jakub Dawidek case NV_TYPE_UINT32:
91132115b10SPawel Jakub Dawidek case NV_TYPE_INT32_ARRAY:
91232115b10SPawel Jakub Dawidek case NV_TYPE_UINT32_ARRAY:
91332115b10SPawel Jakub Dawidek if (vsize == 0)
91432115b10SPawel Jakub Dawidek vsize = 4;
915f9c5a09cSMikolaj Golub /* FALLTHROUGH */
91632115b10SPawel Jakub Dawidek case NV_TYPE_INT64:
91732115b10SPawel Jakub Dawidek case NV_TYPE_UINT64:
91832115b10SPawel Jakub Dawidek case NV_TYPE_INT64_ARRAY:
91932115b10SPawel Jakub Dawidek case NV_TYPE_UINT64_ARRAY:
92032115b10SPawel Jakub Dawidek if (vsize == 0)
92132115b10SPawel Jakub Dawidek vsize = 8;
92232115b10SPawel Jakub Dawidek for (p = data; p < end; p += vsize) {
92332115b10SPawel Jakub Dawidek if (tohost) {
92432115b10SPawel Jakub Dawidek switch (vsize) {
92532115b10SPawel Jakub Dawidek case 2:
92632115b10SPawel Jakub Dawidek *(uint16_t *)(void *)p =
92732115b10SPawel Jakub Dawidek le16toh(*(uint16_t *)(void *)p);
92832115b10SPawel Jakub Dawidek break;
92932115b10SPawel Jakub Dawidek case 4:
93032115b10SPawel Jakub Dawidek *(uint32_t *)(void *)p =
93132115b10SPawel Jakub Dawidek le32toh(*(uint32_t *)(void *)p);
93232115b10SPawel Jakub Dawidek break;
93332115b10SPawel Jakub Dawidek case 8:
93432115b10SPawel Jakub Dawidek *(uint64_t *)(void *)p =
93532115b10SPawel Jakub Dawidek le64toh(*(uint64_t *)(void *)p);
93632115b10SPawel Jakub Dawidek break;
93732115b10SPawel Jakub Dawidek default:
938adf8002bSPawel Jakub Dawidek PJDLOG_ABORT("invalid condition");
93932115b10SPawel Jakub Dawidek }
94032115b10SPawel Jakub Dawidek } else {
94132115b10SPawel Jakub Dawidek switch (vsize) {
94232115b10SPawel Jakub Dawidek case 2:
94332115b10SPawel Jakub Dawidek *(uint16_t *)(void *)p =
94432115b10SPawel Jakub Dawidek htole16(*(uint16_t *)(void *)p);
94532115b10SPawel Jakub Dawidek break;
94632115b10SPawel Jakub Dawidek case 4:
94732115b10SPawel Jakub Dawidek *(uint32_t *)(void *)p =
94832115b10SPawel Jakub Dawidek htole32(*(uint32_t *)(void *)p);
94932115b10SPawel Jakub Dawidek break;
95032115b10SPawel Jakub Dawidek case 8:
95132115b10SPawel Jakub Dawidek *(uint64_t *)(void *)p =
95232115b10SPawel Jakub Dawidek htole64(*(uint64_t *)(void *)p);
95332115b10SPawel Jakub Dawidek break;
95432115b10SPawel Jakub Dawidek default:
955adf8002bSPawel Jakub Dawidek PJDLOG_ABORT("invalid condition");
95632115b10SPawel Jakub Dawidek }
95732115b10SPawel Jakub Dawidek }
95832115b10SPawel Jakub Dawidek }
95932115b10SPawel Jakub Dawidek break;
96032115b10SPawel Jakub Dawidek case NV_TYPE_STRING:
96132115b10SPawel Jakub Dawidek break;
96232115b10SPawel Jakub Dawidek default:
963adf8002bSPawel Jakub Dawidek PJDLOG_ABORT("unrecognized type");
96432115b10SPawel Jakub Dawidek }
96532115b10SPawel Jakub Dawidek }
966