17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 53bb79becSeschrock * Common Development and Distribution License (the "License"). 63bb79becSeschrock * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21d9638e54Smws 227c478bd9Sstevel@tonic-gate /* 23f6e214c7SGavin Maltby * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. 24*843c2111SMatthew Ahrens * Copyright (c) 2015, 2017 by Delphix. All rights reserved. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 287c478bd9Sstevel@tonic-gate #include <sys/debug.h> 297c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h> 307c478bd9Sstevel@tonic-gate #include <sys/int_limits.h> 317c478bd9Sstevel@tonic-gate #include <sys/nvpair.h> 327c478bd9Sstevel@tonic-gate #include <sys/nvpair_impl.h> 337c478bd9Sstevel@tonic-gate #include <rpc/types.h> 347c478bd9Sstevel@tonic-gate #include <rpc/xdr.h> 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && !defined(_BOOT) 377c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 38602ca9eaScth #include <sys/ddi.h> 39602ca9eaScth #include <sys/sunddi.h> 405c5f1371SRichard Lowe #include <sys/sysmacros.h> 417c478bd9Sstevel@tonic-gate #else 427c478bd9Sstevel@tonic-gate #include <stdarg.h> 43602ca9eaScth #include <stdlib.h> 44602ca9eaScth #include <string.h> 457c478bd9Sstevel@tonic-gate #include <strings.h> 465c5f1371SRichard Lowe #include <stddef.h> 477c478bd9Sstevel@tonic-gate #endif 487c478bd9Sstevel@tonic-gate 49602ca9eaScth #define skip_whitespace(p) while ((*(p) == ' ') || (*(p) == '\t')) p++ 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate /* 527c478bd9Sstevel@tonic-gate * nvpair.c - Provides kernel & userland interfaces for manipulating 537c478bd9Sstevel@tonic-gate * name-value pairs. 547c478bd9Sstevel@tonic-gate * 557c478bd9Sstevel@tonic-gate * Overview Diagram 567c478bd9Sstevel@tonic-gate * 577c478bd9Sstevel@tonic-gate * +--------------+ 587c478bd9Sstevel@tonic-gate * | nvlist_t | 597c478bd9Sstevel@tonic-gate * |--------------| 607c478bd9Sstevel@tonic-gate * | nvl_version | 617c478bd9Sstevel@tonic-gate * | nvl_nvflag | 627c478bd9Sstevel@tonic-gate * | nvl_priv -+-+ 637c478bd9Sstevel@tonic-gate * | nvl_flag | | 647c478bd9Sstevel@tonic-gate * | nvl_pad | | 657c478bd9Sstevel@tonic-gate * +--------------+ | 667c478bd9Sstevel@tonic-gate * V 677c478bd9Sstevel@tonic-gate * +--------------+ last i_nvp in list 687c478bd9Sstevel@tonic-gate * | nvpriv_t | +---------------------> 697c478bd9Sstevel@tonic-gate * |--------------| | 707c478bd9Sstevel@tonic-gate * +--+- nvp_list | | +------------+ 717c478bd9Sstevel@tonic-gate * | | nvp_last -+--+ + nv_alloc_t | 727c478bd9Sstevel@tonic-gate * | | nvp_curr | |------------| 737c478bd9Sstevel@tonic-gate * | | nvp_nva -+----> | nva_ops | 747c478bd9Sstevel@tonic-gate * | | nvp_stat | | nva_arg | 757c478bd9Sstevel@tonic-gate * | +--------------+ +------------+ 767c478bd9Sstevel@tonic-gate * | 777c478bd9Sstevel@tonic-gate * +-------+ 787c478bd9Sstevel@tonic-gate * V 797c478bd9Sstevel@tonic-gate * +---------------------+ +-------------------+ 807c478bd9Sstevel@tonic-gate * | i_nvp_t | +-->| i_nvp_t | +--> 817c478bd9Sstevel@tonic-gate * |---------------------| | |-------------------| | 827c478bd9Sstevel@tonic-gate * | nvi_next -+--+ | nvi_next -+--+ 837c478bd9Sstevel@tonic-gate * | nvi_prev (NULL) | <----+ nvi_prev | 847c478bd9Sstevel@tonic-gate * | . . . . . . . . . . | | . . . . . . . . . | 857c478bd9Sstevel@tonic-gate * | nvp (nvpair_t) | | nvp (nvpair_t) | 867c478bd9Sstevel@tonic-gate * | - nvp_size | | - nvp_size | 877c478bd9Sstevel@tonic-gate * | - nvp_name_sz | | - nvp_name_sz | 887c478bd9Sstevel@tonic-gate * | - nvp_value_elem | | - nvp_value_elem | 897c478bd9Sstevel@tonic-gate * | - nvp_type | | - nvp_type | 907c478bd9Sstevel@tonic-gate * | - data ... | | - data ... | 917c478bd9Sstevel@tonic-gate * +---------------------+ +-------------------+ 927c478bd9Sstevel@tonic-gate * 937c478bd9Sstevel@tonic-gate * 947c478bd9Sstevel@tonic-gate * 957c478bd9Sstevel@tonic-gate * +---------------------+ +---------------------+ 967c478bd9Sstevel@tonic-gate * | i_nvp_t | +--> +-->| i_nvp_t (last) | 977c478bd9Sstevel@tonic-gate * |---------------------| | | |---------------------| 987c478bd9Sstevel@tonic-gate * | nvi_next -+--+ ... --+ | nvi_next (NULL) | 997c478bd9Sstevel@tonic-gate * <-+- nvi_prev |<-- ... <----+ nvi_prev | 1007c478bd9Sstevel@tonic-gate * | . . . . . . . . . | | . . . . . . . . . | 1017c478bd9Sstevel@tonic-gate * | nvp (nvpair_t) | | nvp (nvpair_t) | 1027c478bd9Sstevel@tonic-gate * | - nvp_size | | - nvp_size | 1037c478bd9Sstevel@tonic-gate * | - nvp_name_sz | | - nvp_name_sz | 1047c478bd9Sstevel@tonic-gate * | - nvp_value_elem | | - nvp_value_elem | 1057c478bd9Sstevel@tonic-gate * | - DATA_TYPE_NVLIST | | - nvp_type | 1067c478bd9Sstevel@tonic-gate * | - data (embedded) | | - data ... | 1077c478bd9Sstevel@tonic-gate * | nvlist name | +---------------------+ 1087c478bd9Sstevel@tonic-gate * | +--------------+ | 1097c478bd9Sstevel@tonic-gate * | | nvlist_t | | 1107c478bd9Sstevel@tonic-gate * | |--------------| | 1117c478bd9Sstevel@tonic-gate * | | nvl_version | | 1127c478bd9Sstevel@tonic-gate * | | nvl_nvflag | | 1137c478bd9Sstevel@tonic-gate * | | nvl_priv --+---+----> 1147c478bd9Sstevel@tonic-gate * | | nvl_flag | | 1157c478bd9Sstevel@tonic-gate * | | nvl_pad | | 1167c478bd9Sstevel@tonic-gate * | +--------------+ | 1177c478bd9Sstevel@tonic-gate * +---------------------+ 1187c478bd9Sstevel@tonic-gate * 1197c478bd9Sstevel@tonic-gate * 1207c478bd9Sstevel@tonic-gate * N.B. nvpair_t may be aligned on 4 byte boundary, so +4 will 1217c478bd9Sstevel@tonic-gate * allow value to be aligned on 8 byte boundary 1227c478bd9Sstevel@tonic-gate * 1237c478bd9Sstevel@tonic-gate * name_len is the length of the name string including the null terminator 1247c478bd9Sstevel@tonic-gate * so it must be >= 1 1257c478bd9Sstevel@tonic-gate */ 1267c478bd9Sstevel@tonic-gate #define NVP_SIZE_CALC(name_len, data_len) \ 1277c478bd9Sstevel@tonic-gate (NV_ALIGN((sizeof (nvpair_t)) + name_len) + NV_ALIGN(data_len)) 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate static int i_get_value_size(data_type_t type, const void *data, uint_t nelem); 1307c478bd9Sstevel@tonic-gate static int nvlist_add_common(nvlist_t *nvl, const char *name, data_type_t type, 1317c478bd9Sstevel@tonic-gate uint_t nelem, const void *data); 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate #define NV_STAT_EMBEDDED 0x1 1347c478bd9Sstevel@tonic-gate #define EMBEDDED_NVL(nvp) ((nvlist_t *)(void *)NVP_VALUE(nvp)) 1357c478bd9Sstevel@tonic-gate #define EMBEDDED_NVL_ARRAY(nvp) ((nvlist_t **)(void *)NVP_VALUE(nvp)) 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate #define NVP_VALOFF(nvp) (NV_ALIGN(sizeof (nvpair_t) + (nvp)->nvp_name_sz)) 1387c478bd9Sstevel@tonic-gate #define NVPAIR2I_NVP(nvp) \ 1397c478bd9Sstevel@tonic-gate ((i_nvp_t *)((size_t)(nvp) - offsetof(i_nvp_t, nvi_nvp))) 1407c478bd9Sstevel@tonic-gate 1419ca527c3SMatthew Ahrens #ifdef _KERNEL 1429ca527c3SMatthew Ahrens int nvpair_max_recursion = 20; 1439ca527c3SMatthew Ahrens #else 1449ca527c3SMatthew Ahrens int nvpair_max_recursion = 100; 1459ca527c3SMatthew Ahrens #endif 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate int 1487c478bd9Sstevel@tonic-gate nv_alloc_init(nv_alloc_t *nva, const nv_alloc_ops_t *nvo, /* args */ ...) 1497c478bd9Sstevel@tonic-gate { 1507c478bd9Sstevel@tonic-gate va_list valist; 1517c478bd9Sstevel@tonic-gate int err = 0; 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate nva->nva_ops = nvo; 1547c478bd9Sstevel@tonic-gate nva->nva_arg = NULL; 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate va_start(valist, nvo); 1577c478bd9Sstevel@tonic-gate if (nva->nva_ops->nv_ao_init != NULL) 1587c478bd9Sstevel@tonic-gate err = nva->nva_ops->nv_ao_init(nva, valist); 1597c478bd9Sstevel@tonic-gate va_end(valist); 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate return (err); 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate void 1657c478bd9Sstevel@tonic-gate nv_alloc_reset(nv_alloc_t *nva) 1667c478bd9Sstevel@tonic-gate { 1677c478bd9Sstevel@tonic-gate if (nva->nva_ops->nv_ao_reset != NULL) 1687c478bd9Sstevel@tonic-gate nva->nva_ops->nv_ao_reset(nva); 1697c478bd9Sstevel@tonic-gate } 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate void 1727c478bd9Sstevel@tonic-gate nv_alloc_fini(nv_alloc_t *nva) 1737c478bd9Sstevel@tonic-gate { 1747c478bd9Sstevel@tonic-gate if (nva->nva_ops->nv_ao_fini != NULL) 1757c478bd9Sstevel@tonic-gate nva->nva_ops->nv_ao_fini(nva); 1767c478bd9Sstevel@tonic-gate } 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate nv_alloc_t * 1797c478bd9Sstevel@tonic-gate nvlist_lookup_nv_alloc(nvlist_t *nvl) 1807c478bd9Sstevel@tonic-gate { 1817c478bd9Sstevel@tonic-gate nvpriv_t *priv; 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate if (nvl == NULL || 1847c478bd9Sstevel@tonic-gate (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 1857c478bd9Sstevel@tonic-gate return (NULL); 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate return (priv->nvp_nva); 1887c478bd9Sstevel@tonic-gate } 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate static void * 1917c478bd9Sstevel@tonic-gate nv_mem_zalloc(nvpriv_t *nvp, size_t size) 1927c478bd9Sstevel@tonic-gate { 1937c478bd9Sstevel@tonic-gate nv_alloc_t *nva = nvp->nvp_nva; 1947c478bd9Sstevel@tonic-gate void *buf; 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate if ((buf = nva->nva_ops->nv_ao_alloc(nva, size)) != NULL) 1977c478bd9Sstevel@tonic-gate bzero(buf, size); 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate return (buf); 2007c478bd9Sstevel@tonic-gate } 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate static void 2037c478bd9Sstevel@tonic-gate nv_mem_free(nvpriv_t *nvp, void *buf, size_t size) 2047c478bd9Sstevel@tonic-gate { 2057c478bd9Sstevel@tonic-gate nv_alloc_t *nva = nvp->nvp_nva; 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate nva->nva_ops->nv_ao_free(nva, buf, size); 2087c478bd9Sstevel@tonic-gate } 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate static void 2117c478bd9Sstevel@tonic-gate nv_priv_init(nvpriv_t *priv, nv_alloc_t *nva, uint32_t stat) 2127c478bd9Sstevel@tonic-gate { 213c5904d13Seschrock bzero(priv, sizeof (nvpriv_t)); 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate priv->nvp_nva = nva; 2167c478bd9Sstevel@tonic-gate priv->nvp_stat = stat; 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate static nvpriv_t * 2207c478bd9Sstevel@tonic-gate nv_priv_alloc(nv_alloc_t *nva) 2217c478bd9Sstevel@tonic-gate { 2227c478bd9Sstevel@tonic-gate nvpriv_t *priv; 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate /* 2257c478bd9Sstevel@tonic-gate * nv_mem_alloc() cannot called here because it needs the priv 2267c478bd9Sstevel@tonic-gate * argument. 2277c478bd9Sstevel@tonic-gate */ 2287c478bd9Sstevel@tonic-gate if ((priv = nva->nva_ops->nv_ao_alloc(nva, sizeof (nvpriv_t))) == NULL) 2297c478bd9Sstevel@tonic-gate return (NULL); 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate nv_priv_init(priv, nva, 0); 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate return (priv); 2347c478bd9Sstevel@tonic-gate } 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate /* 2377c478bd9Sstevel@tonic-gate * Embedded lists need their own nvpriv_t's. We create a new 2387c478bd9Sstevel@tonic-gate * nvpriv_t using the parameters and allocator from the parent 2397c478bd9Sstevel@tonic-gate * list's nvpriv_t. 2407c478bd9Sstevel@tonic-gate */ 2417c478bd9Sstevel@tonic-gate static nvpriv_t * 2427c478bd9Sstevel@tonic-gate nv_priv_alloc_embedded(nvpriv_t *priv) 2437c478bd9Sstevel@tonic-gate { 2447c478bd9Sstevel@tonic-gate nvpriv_t *emb_priv; 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate if ((emb_priv = nv_mem_zalloc(priv, sizeof (nvpriv_t))) == NULL) 2477c478bd9Sstevel@tonic-gate return (NULL); 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate nv_priv_init(emb_priv, priv->nvp_nva, NV_STAT_EMBEDDED); 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate return (emb_priv); 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate static void 2557c478bd9Sstevel@tonic-gate nvlist_init(nvlist_t *nvl, uint32_t nvflag, nvpriv_t *priv) 2567c478bd9Sstevel@tonic-gate { 2577c478bd9Sstevel@tonic-gate nvl->nvl_version = NV_VERSION; 2587c478bd9Sstevel@tonic-gate nvl->nvl_nvflag = nvflag & (NV_UNIQUE_NAME|NV_UNIQUE_NAME_TYPE); 2597c478bd9Sstevel@tonic-gate nvl->nvl_priv = (uint64_t)(uintptr_t)priv; 2607c478bd9Sstevel@tonic-gate nvl->nvl_flag = 0; 2617c478bd9Sstevel@tonic-gate nvl->nvl_pad = 0; 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate 264f6e214c7SGavin Maltby uint_t 265f6e214c7SGavin Maltby nvlist_nvflag(nvlist_t *nvl) 266f6e214c7SGavin Maltby { 267f6e214c7SGavin Maltby return (nvl->nvl_nvflag); 268f6e214c7SGavin Maltby } 269f6e214c7SGavin Maltby 2707c478bd9Sstevel@tonic-gate /* 2717c478bd9Sstevel@tonic-gate * nvlist_alloc - Allocate nvlist. 2727c478bd9Sstevel@tonic-gate */ 2737c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 2747c478bd9Sstevel@tonic-gate int 2757c478bd9Sstevel@tonic-gate nvlist_alloc(nvlist_t **nvlp, uint_t nvflag, int kmflag) 2767c478bd9Sstevel@tonic-gate { 2777c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && !defined(_BOOT) 2787c478bd9Sstevel@tonic-gate return (nvlist_xalloc(nvlp, nvflag, 2797c478bd9Sstevel@tonic-gate (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep))); 2807c478bd9Sstevel@tonic-gate #else 2817c478bd9Sstevel@tonic-gate return (nvlist_xalloc(nvlp, nvflag, nv_alloc_nosleep)); 2827c478bd9Sstevel@tonic-gate #endif 2837c478bd9Sstevel@tonic-gate } 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate int 2867c478bd9Sstevel@tonic-gate nvlist_xalloc(nvlist_t **nvlp, uint_t nvflag, nv_alloc_t *nva) 2877c478bd9Sstevel@tonic-gate { 2887c478bd9Sstevel@tonic-gate nvpriv_t *priv; 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate if (nvlp == NULL || nva == NULL) 2917c478bd9Sstevel@tonic-gate return (EINVAL); 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate if ((priv = nv_priv_alloc(nva)) == NULL) 2947c478bd9Sstevel@tonic-gate return (ENOMEM); 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate if ((*nvlp = nv_mem_zalloc(priv, 2977c478bd9Sstevel@tonic-gate NV_ALIGN(sizeof (nvlist_t)))) == NULL) { 2987c478bd9Sstevel@tonic-gate nv_mem_free(priv, priv, sizeof (nvpriv_t)); 2997c478bd9Sstevel@tonic-gate return (ENOMEM); 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate nvlist_init(*nvlp, nvflag, priv); 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate return (0); 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate /* 3087c478bd9Sstevel@tonic-gate * nvp_buf_alloc - Allocate i_nvp_t for storing a new nv pair. 3097c478bd9Sstevel@tonic-gate */ 3107c478bd9Sstevel@tonic-gate static nvpair_t * 3117c478bd9Sstevel@tonic-gate nvp_buf_alloc(nvlist_t *nvl, size_t len) 3127c478bd9Sstevel@tonic-gate { 3137c478bd9Sstevel@tonic-gate nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 3147c478bd9Sstevel@tonic-gate i_nvp_t *buf; 3157c478bd9Sstevel@tonic-gate nvpair_t *nvp; 3167c478bd9Sstevel@tonic-gate size_t nvsize; 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate /* 3197c478bd9Sstevel@tonic-gate * Allocate the buffer 3207c478bd9Sstevel@tonic-gate */ 3217c478bd9Sstevel@tonic-gate nvsize = len + offsetof(i_nvp_t, nvi_nvp); 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate if ((buf = nv_mem_zalloc(priv, nvsize)) == NULL) 3247c478bd9Sstevel@tonic-gate return (NULL); 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate nvp = &buf->nvi_nvp; 3277c478bd9Sstevel@tonic-gate nvp->nvp_size = len; 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate return (nvp); 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate /* 3337c478bd9Sstevel@tonic-gate * nvp_buf_free - de-Allocate an i_nvp_t. 3347c478bd9Sstevel@tonic-gate */ 3357c478bd9Sstevel@tonic-gate static void 3367c478bd9Sstevel@tonic-gate nvp_buf_free(nvlist_t *nvl, nvpair_t *nvp) 3377c478bd9Sstevel@tonic-gate { 3387c478bd9Sstevel@tonic-gate nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 3397c478bd9Sstevel@tonic-gate size_t nvsize = nvp->nvp_size + offsetof(i_nvp_t, nvi_nvp); 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate nv_mem_free(priv, NVPAIR2I_NVP(nvp), nvsize); 3427c478bd9Sstevel@tonic-gate } 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate /* 3457c478bd9Sstevel@tonic-gate * nvp_buf_link - link a new nv pair into the nvlist. 3467c478bd9Sstevel@tonic-gate */ 3477c478bd9Sstevel@tonic-gate static void 3487c478bd9Sstevel@tonic-gate nvp_buf_link(nvlist_t *nvl, nvpair_t *nvp) 3497c478bd9Sstevel@tonic-gate { 3507c478bd9Sstevel@tonic-gate nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 3517c478bd9Sstevel@tonic-gate i_nvp_t *curr = NVPAIR2I_NVP(nvp); 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate /* Put element at end of nvlist */ 3547c478bd9Sstevel@tonic-gate if (priv->nvp_list == NULL) { 3557c478bd9Sstevel@tonic-gate priv->nvp_list = priv->nvp_last = curr; 3567c478bd9Sstevel@tonic-gate } else { 3577c478bd9Sstevel@tonic-gate curr->nvi_prev = priv->nvp_last; 3587c478bd9Sstevel@tonic-gate priv->nvp_last->nvi_next = curr; 3597c478bd9Sstevel@tonic-gate priv->nvp_last = curr; 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate } 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate /* 3647c478bd9Sstevel@tonic-gate * nvp_buf_unlink - unlink an removed nvpair out of the nvlist. 3657c478bd9Sstevel@tonic-gate */ 3667c478bd9Sstevel@tonic-gate static void 3677c478bd9Sstevel@tonic-gate nvp_buf_unlink(nvlist_t *nvl, nvpair_t *nvp) 3687c478bd9Sstevel@tonic-gate { 3697c478bd9Sstevel@tonic-gate nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 3707c478bd9Sstevel@tonic-gate i_nvp_t *curr = NVPAIR2I_NVP(nvp); 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate /* 3737c478bd9Sstevel@tonic-gate * protect nvlist_next_nvpair() against walking on freed memory. 3747c478bd9Sstevel@tonic-gate */ 3757c478bd9Sstevel@tonic-gate if (priv->nvp_curr == curr) 3767c478bd9Sstevel@tonic-gate priv->nvp_curr = curr->nvi_next; 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate if (curr == priv->nvp_list) 3797c478bd9Sstevel@tonic-gate priv->nvp_list = curr->nvi_next; 3807c478bd9Sstevel@tonic-gate else 3817c478bd9Sstevel@tonic-gate curr->nvi_prev->nvi_next = curr->nvi_next; 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate if (curr == priv->nvp_last) 3847c478bd9Sstevel@tonic-gate priv->nvp_last = curr->nvi_prev; 3857c478bd9Sstevel@tonic-gate else 3867c478bd9Sstevel@tonic-gate curr->nvi_next->nvi_prev = curr->nvi_prev; 3877c478bd9Sstevel@tonic-gate } 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate /* 3907c478bd9Sstevel@tonic-gate * take a nvpair type and number of elements and make sure the are valid 3917c478bd9Sstevel@tonic-gate */ 3927c478bd9Sstevel@tonic-gate static int 3937c478bd9Sstevel@tonic-gate i_validate_type_nelem(data_type_t type, uint_t nelem) 3947c478bd9Sstevel@tonic-gate { 3957c478bd9Sstevel@tonic-gate switch (type) { 3967c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN: 3977c478bd9Sstevel@tonic-gate if (nelem != 0) 3987c478bd9Sstevel@tonic-gate return (EINVAL); 3997c478bd9Sstevel@tonic-gate break; 4007c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_VALUE: 4017c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE: 4027c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8: 4037c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8: 4047c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16: 4057c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16: 4067c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32: 4077c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32: 4087c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64: 4097c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64: 4107c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING: 4117c478bd9Sstevel@tonic-gate case DATA_TYPE_HRTIME: 4127c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST: 413825ba0f2Srobj #if !defined(_KERNEL) 414825ba0f2Srobj case DATA_TYPE_DOUBLE: 415825ba0f2Srobj #endif 4167c478bd9Sstevel@tonic-gate if (nelem != 1) 4177c478bd9Sstevel@tonic-gate return (EINVAL); 4187c478bd9Sstevel@tonic-gate break; 4197c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_ARRAY: 4207c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE_ARRAY: 4217c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8_ARRAY: 4227c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8_ARRAY: 4237c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16_ARRAY: 4247c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16_ARRAY: 4257c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32_ARRAY: 4267c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32_ARRAY: 4277c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64_ARRAY: 4287c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64_ARRAY: 4297c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY: 4307c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: 4317c478bd9Sstevel@tonic-gate /* we allow arrays with 0 elements */ 4327c478bd9Sstevel@tonic-gate break; 4337c478bd9Sstevel@tonic-gate default: 4347c478bd9Sstevel@tonic-gate return (EINVAL); 4357c478bd9Sstevel@tonic-gate } 4367c478bd9Sstevel@tonic-gate return (0); 4377c478bd9Sstevel@tonic-gate } 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate /* 4407c478bd9Sstevel@tonic-gate * Verify nvp_name_sz and check the name string length. 4417c478bd9Sstevel@tonic-gate */ 4427c478bd9Sstevel@tonic-gate static int 4437c478bd9Sstevel@tonic-gate i_validate_nvpair_name(nvpair_t *nvp) 4447c478bd9Sstevel@tonic-gate { 4457c478bd9Sstevel@tonic-gate if ((nvp->nvp_name_sz <= 0) || 4467c478bd9Sstevel@tonic-gate (nvp->nvp_size < NVP_SIZE_CALC(nvp->nvp_name_sz, 0))) 4477c478bd9Sstevel@tonic-gate return (EFAULT); 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate /* verify the name string, make sure its terminated */ 4507c478bd9Sstevel@tonic-gate if (NVP_NAME(nvp)[nvp->nvp_name_sz - 1] != '\0') 4517c478bd9Sstevel@tonic-gate return (EFAULT); 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate return (strlen(NVP_NAME(nvp)) == nvp->nvp_name_sz - 1 ? 0 : EFAULT); 4547c478bd9Sstevel@tonic-gate } 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate static int 4577c478bd9Sstevel@tonic-gate i_validate_nvpair_value(data_type_t type, uint_t nelem, const void *data) 4587c478bd9Sstevel@tonic-gate { 4597c478bd9Sstevel@tonic-gate switch (type) { 4607c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_VALUE: 4617c478bd9Sstevel@tonic-gate if (*(boolean_t *)data != B_TRUE && 4627c478bd9Sstevel@tonic-gate *(boolean_t *)data != B_FALSE) 4637c478bd9Sstevel@tonic-gate return (EINVAL); 4647c478bd9Sstevel@tonic-gate break; 4657c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_ARRAY: { 4667c478bd9Sstevel@tonic-gate int i; 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate for (i = 0; i < nelem; i++) 4697c478bd9Sstevel@tonic-gate if (((boolean_t *)data)[i] != B_TRUE && 4707c478bd9Sstevel@tonic-gate ((boolean_t *)data)[i] != B_FALSE) 4717c478bd9Sstevel@tonic-gate return (EINVAL); 4727c478bd9Sstevel@tonic-gate break; 4737c478bd9Sstevel@tonic-gate } 4747c478bd9Sstevel@tonic-gate default: 4757c478bd9Sstevel@tonic-gate break; 4767c478bd9Sstevel@tonic-gate } 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate return (0); 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate /* 4827c478bd9Sstevel@tonic-gate * This function takes a pointer to what should be a nvpair and it's size 4837c478bd9Sstevel@tonic-gate * and then verifies that all the nvpair fields make sense and can be 4847c478bd9Sstevel@tonic-gate * trusted. This function is used when decoding packed nvpairs. 4857c478bd9Sstevel@tonic-gate */ 4867c478bd9Sstevel@tonic-gate static int 4877c478bd9Sstevel@tonic-gate i_validate_nvpair(nvpair_t *nvp) 4887c478bd9Sstevel@tonic-gate { 4897c478bd9Sstevel@tonic-gate data_type_t type = NVP_TYPE(nvp); 4907c478bd9Sstevel@tonic-gate int size1, size2; 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate /* verify nvp_name_sz, check the name string length */ 4937c478bd9Sstevel@tonic-gate if (i_validate_nvpair_name(nvp) != 0) 4947c478bd9Sstevel@tonic-gate return (EFAULT); 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate if (i_validate_nvpair_value(type, NVP_NELEM(nvp), NVP_VALUE(nvp)) != 0) 4977c478bd9Sstevel@tonic-gate return (EFAULT); 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate /* 5007c478bd9Sstevel@tonic-gate * verify nvp_type, nvp_value_elem, and also possibly 5017c478bd9Sstevel@tonic-gate * verify string values and get the value size. 5027c478bd9Sstevel@tonic-gate */ 5037c478bd9Sstevel@tonic-gate size2 = i_get_value_size(type, NVP_VALUE(nvp), NVP_NELEM(nvp)); 5047c478bd9Sstevel@tonic-gate size1 = nvp->nvp_size - NVP_VALOFF(nvp); 5057c478bd9Sstevel@tonic-gate if (size2 < 0 || size1 != NV_ALIGN(size2)) 5067c478bd9Sstevel@tonic-gate return (EFAULT); 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate return (0); 5097c478bd9Sstevel@tonic-gate } 5107c478bd9Sstevel@tonic-gate 5117c478bd9Sstevel@tonic-gate static int 5127c478bd9Sstevel@tonic-gate nvlist_copy_pairs(nvlist_t *snvl, nvlist_t *dnvl) 5137c478bd9Sstevel@tonic-gate { 5147c478bd9Sstevel@tonic-gate nvpriv_t *priv; 5157c478bd9Sstevel@tonic-gate i_nvp_t *curr; 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate if ((priv = (nvpriv_t *)(uintptr_t)snvl->nvl_priv) == NULL) 5187c478bd9Sstevel@tonic-gate return (EINVAL); 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) { 5217c478bd9Sstevel@tonic-gate nvpair_t *nvp = &curr->nvi_nvp; 5227c478bd9Sstevel@tonic-gate int err; 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate if ((err = nvlist_add_common(dnvl, NVP_NAME(nvp), NVP_TYPE(nvp), 5257c478bd9Sstevel@tonic-gate NVP_NELEM(nvp), NVP_VALUE(nvp))) != 0) 5267c478bd9Sstevel@tonic-gate return (err); 5277c478bd9Sstevel@tonic-gate } 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate return (0); 5307c478bd9Sstevel@tonic-gate } 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate /* 5337c478bd9Sstevel@tonic-gate * Frees all memory allocated for an nvpair (like embedded lists) with 5347c478bd9Sstevel@tonic-gate * the exception of the nvpair buffer itself. 5357c478bd9Sstevel@tonic-gate */ 5367c478bd9Sstevel@tonic-gate static void 5377c478bd9Sstevel@tonic-gate nvpair_free(nvpair_t *nvp) 5387c478bd9Sstevel@tonic-gate { 5397c478bd9Sstevel@tonic-gate switch (NVP_TYPE(nvp)) { 5407c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST: 5417c478bd9Sstevel@tonic-gate nvlist_free(EMBEDDED_NVL(nvp)); 5427c478bd9Sstevel@tonic-gate break; 5437c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: { 5447c478bd9Sstevel@tonic-gate nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp); 5457c478bd9Sstevel@tonic-gate int i; 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate for (i = 0; i < NVP_NELEM(nvp); i++) 548aab83bb8SJosef 'Jeff' Sipek nvlist_free(nvlp[i]); 5497c478bd9Sstevel@tonic-gate break; 5507c478bd9Sstevel@tonic-gate } 5517c478bd9Sstevel@tonic-gate default: 5527c478bd9Sstevel@tonic-gate break; 5537c478bd9Sstevel@tonic-gate } 5547c478bd9Sstevel@tonic-gate } 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate /* 5577c478bd9Sstevel@tonic-gate * nvlist_free - free an unpacked nvlist 5587c478bd9Sstevel@tonic-gate */ 5597c478bd9Sstevel@tonic-gate void 5607c478bd9Sstevel@tonic-gate nvlist_free(nvlist_t *nvl) 5617c478bd9Sstevel@tonic-gate { 5627c478bd9Sstevel@tonic-gate nvpriv_t *priv; 5637c478bd9Sstevel@tonic-gate i_nvp_t *curr; 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate if (nvl == NULL || 5667c478bd9Sstevel@tonic-gate (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 5677c478bd9Sstevel@tonic-gate return; 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate /* 5707c478bd9Sstevel@tonic-gate * Unpacked nvlist are linked through i_nvp_t 5717c478bd9Sstevel@tonic-gate */ 5727c478bd9Sstevel@tonic-gate curr = priv->nvp_list; 5737c478bd9Sstevel@tonic-gate while (curr != NULL) { 5747c478bd9Sstevel@tonic-gate nvpair_t *nvp = &curr->nvi_nvp; 5757c478bd9Sstevel@tonic-gate curr = curr->nvi_next; 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate nvpair_free(nvp); 5787c478bd9Sstevel@tonic-gate nvp_buf_free(nvl, nvp); 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate if (!(priv->nvp_stat & NV_STAT_EMBEDDED)) 5827c478bd9Sstevel@tonic-gate nv_mem_free(priv, nvl, NV_ALIGN(sizeof (nvlist_t))); 5837c478bd9Sstevel@tonic-gate else 5845ad82045Snd nvl->nvl_priv = 0; 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate nv_mem_free(priv, priv, sizeof (nvpriv_t)); 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate static int 5907c478bd9Sstevel@tonic-gate nvlist_contains_nvp(nvlist_t *nvl, nvpair_t *nvp) 5917c478bd9Sstevel@tonic-gate { 5927c478bd9Sstevel@tonic-gate nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 5937c478bd9Sstevel@tonic-gate i_nvp_t *curr; 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate if (nvp == NULL) 5967c478bd9Sstevel@tonic-gate return (0); 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) 5997c478bd9Sstevel@tonic-gate if (&curr->nvi_nvp == nvp) 6007c478bd9Sstevel@tonic-gate return (1); 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate return (0); 6037c478bd9Sstevel@tonic-gate } 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate /* 6067c478bd9Sstevel@tonic-gate * Make a copy of nvlist 6077c478bd9Sstevel@tonic-gate */ 6087c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 6097c478bd9Sstevel@tonic-gate int 6107c478bd9Sstevel@tonic-gate nvlist_dup(nvlist_t *nvl, nvlist_t **nvlp, int kmflag) 6117c478bd9Sstevel@tonic-gate { 6127c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && !defined(_BOOT) 6137c478bd9Sstevel@tonic-gate return (nvlist_xdup(nvl, nvlp, 6147c478bd9Sstevel@tonic-gate (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep))); 6157c478bd9Sstevel@tonic-gate #else 6167c478bd9Sstevel@tonic-gate return (nvlist_xdup(nvl, nvlp, nv_alloc_nosleep)); 6177c478bd9Sstevel@tonic-gate #endif 6187c478bd9Sstevel@tonic-gate } 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate int 6217c478bd9Sstevel@tonic-gate nvlist_xdup(nvlist_t *nvl, nvlist_t **nvlp, nv_alloc_t *nva) 6227c478bd9Sstevel@tonic-gate { 6237c478bd9Sstevel@tonic-gate int err; 6243bb79becSeschrock nvlist_t *ret; 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate if (nvl == NULL || nvlp == NULL) 6277c478bd9Sstevel@tonic-gate return (EINVAL); 6287c478bd9Sstevel@tonic-gate 6293bb79becSeschrock if ((err = nvlist_xalloc(&ret, nvl->nvl_nvflag, nva)) != 0) 6307c478bd9Sstevel@tonic-gate return (err); 6317c478bd9Sstevel@tonic-gate 6323bb79becSeschrock if ((err = nvlist_copy_pairs(nvl, ret)) != 0) 6333bb79becSeschrock nvlist_free(ret); 6343bb79becSeschrock else 6353bb79becSeschrock *nvlp = ret; 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate return (err); 6387c478bd9Sstevel@tonic-gate } 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate /* 6417c478bd9Sstevel@tonic-gate * Remove all with matching name 6427c478bd9Sstevel@tonic-gate */ 6437c478bd9Sstevel@tonic-gate int 6447c478bd9Sstevel@tonic-gate nvlist_remove_all(nvlist_t *nvl, const char *name) 6457c478bd9Sstevel@tonic-gate { 6467c478bd9Sstevel@tonic-gate nvpriv_t *priv; 6477c478bd9Sstevel@tonic-gate i_nvp_t *curr; 6487c478bd9Sstevel@tonic-gate int error = ENOENT; 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate if (nvl == NULL || name == NULL || 6517c478bd9Sstevel@tonic-gate (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 6527c478bd9Sstevel@tonic-gate return (EINVAL); 6537c478bd9Sstevel@tonic-gate 6547c478bd9Sstevel@tonic-gate curr = priv->nvp_list; 6557c478bd9Sstevel@tonic-gate while (curr != NULL) { 6567c478bd9Sstevel@tonic-gate nvpair_t *nvp = &curr->nvi_nvp; 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate curr = curr->nvi_next; 6597c478bd9Sstevel@tonic-gate if (strcmp(name, NVP_NAME(nvp)) != 0) 6607c478bd9Sstevel@tonic-gate continue; 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate nvp_buf_unlink(nvl, nvp); 6637c478bd9Sstevel@tonic-gate nvpair_free(nvp); 6647c478bd9Sstevel@tonic-gate nvp_buf_free(nvl, nvp); 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate error = 0; 6677c478bd9Sstevel@tonic-gate } 6687c478bd9Sstevel@tonic-gate 6697c478bd9Sstevel@tonic-gate return (error); 6707c478bd9Sstevel@tonic-gate } 6717c478bd9Sstevel@tonic-gate 6727c478bd9Sstevel@tonic-gate /* 6737c478bd9Sstevel@tonic-gate * Remove first one with matching name and type 6747c478bd9Sstevel@tonic-gate */ 6757c478bd9Sstevel@tonic-gate int 6767c478bd9Sstevel@tonic-gate nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type) 6777c478bd9Sstevel@tonic-gate { 6787c478bd9Sstevel@tonic-gate nvpriv_t *priv; 6797c478bd9Sstevel@tonic-gate i_nvp_t *curr; 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate if (nvl == NULL || name == NULL || 6827c478bd9Sstevel@tonic-gate (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 6837c478bd9Sstevel@tonic-gate return (EINVAL); 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate curr = priv->nvp_list; 6867c478bd9Sstevel@tonic-gate while (curr != NULL) { 6877c478bd9Sstevel@tonic-gate nvpair_t *nvp = &curr->nvi_nvp; 6887c478bd9Sstevel@tonic-gate 6897c478bd9Sstevel@tonic-gate if (strcmp(name, NVP_NAME(nvp)) == 0 && NVP_TYPE(nvp) == type) { 6907c478bd9Sstevel@tonic-gate nvp_buf_unlink(nvl, nvp); 6917c478bd9Sstevel@tonic-gate nvpair_free(nvp); 6927c478bd9Sstevel@tonic-gate nvp_buf_free(nvl, nvp); 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate return (0); 6957c478bd9Sstevel@tonic-gate } 6967c478bd9Sstevel@tonic-gate curr = curr->nvi_next; 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate return (ENOENT); 7007c478bd9Sstevel@tonic-gate } 7017c478bd9Sstevel@tonic-gate 70292241e0bSTom Erickson int 70392241e0bSTom Erickson nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp) 70492241e0bSTom Erickson { 70592241e0bSTom Erickson if (nvl == NULL || nvp == NULL) 70692241e0bSTom Erickson return (EINVAL); 70792241e0bSTom Erickson 70892241e0bSTom Erickson nvp_buf_unlink(nvl, nvp); 70992241e0bSTom Erickson nvpair_free(nvp); 71092241e0bSTom Erickson nvp_buf_free(nvl, nvp); 71192241e0bSTom Erickson return (0); 71292241e0bSTom Erickson } 71392241e0bSTom Erickson 7147c478bd9Sstevel@tonic-gate /* 7157c478bd9Sstevel@tonic-gate * This function calculates the size of an nvpair value. 7167c478bd9Sstevel@tonic-gate * 7177c478bd9Sstevel@tonic-gate * The data argument controls the behavior in case of the data types 7187c478bd9Sstevel@tonic-gate * DATA_TYPE_STRING and 7197c478bd9Sstevel@tonic-gate * DATA_TYPE_STRING_ARRAY 7207c478bd9Sstevel@tonic-gate * Is data == NULL then the size of the string(s) is excluded. 7217c478bd9Sstevel@tonic-gate */ 7227c478bd9Sstevel@tonic-gate static int 7237c478bd9Sstevel@tonic-gate i_get_value_size(data_type_t type, const void *data, uint_t nelem) 7247c478bd9Sstevel@tonic-gate { 7257c478bd9Sstevel@tonic-gate uint64_t value_sz; 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate if (i_validate_type_nelem(type, nelem) != 0) 7287c478bd9Sstevel@tonic-gate return (-1); 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate /* Calculate required size for holding value */ 7317c478bd9Sstevel@tonic-gate switch (type) { 7327c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN: 7337c478bd9Sstevel@tonic-gate value_sz = 0; 7347c478bd9Sstevel@tonic-gate break; 7357c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_VALUE: 7367c478bd9Sstevel@tonic-gate value_sz = sizeof (boolean_t); 7377c478bd9Sstevel@tonic-gate break; 7387c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE: 7397c478bd9Sstevel@tonic-gate value_sz = sizeof (uchar_t); 7407c478bd9Sstevel@tonic-gate break; 7417c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8: 7427c478bd9Sstevel@tonic-gate value_sz = sizeof (int8_t); 7437c478bd9Sstevel@tonic-gate break; 7447c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8: 7457c478bd9Sstevel@tonic-gate value_sz = sizeof (uint8_t); 7467c478bd9Sstevel@tonic-gate break; 7477c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16: 7487c478bd9Sstevel@tonic-gate value_sz = sizeof (int16_t); 7497c478bd9Sstevel@tonic-gate break; 7507c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16: 7517c478bd9Sstevel@tonic-gate value_sz = sizeof (uint16_t); 7527c478bd9Sstevel@tonic-gate break; 7537c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32: 7547c478bd9Sstevel@tonic-gate value_sz = sizeof (int32_t); 7557c478bd9Sstevel@tonic-gate break; 7567c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32: 7577c478bd9Sstevel@tonic-gate value_sz = sizeof (uint32_t); 7587c478bd9Sstevel@tonic-gate break; 7597c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64: 7607c478bd9Sstevel@tonic-gate value_sz = sizeof (int64_t); 7617c478bd9Sstevel@tonic-gate break; 7627c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64: 7637c478bd9Sstevel@tonic-gate value_sz = sizeof (uint64_t); 7647c478bd9Sstevel@tonic-gate break; 765825ba0f2Srobj #if !defined(_KERNEL) 766825ba0f2Srobj case DATA_TYPE_DOUBLE: 767825ba0f2Srobj value_sz = sizeof (double); 768825ba0f2Srobj break; 769825ba0f2Srobj #endif 7707c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING: 7717c478bd9Sstevel@tonic-gate if (data == NULL) 7727c478bd9Sstevel@tonic-gate value_sz = 0; 7737c478bd9Sstevel@tonic-gate else 7747c478bd9Sstevel@tonic-gate value_sz = strlen(data) + 1; 7757c478bd9Sstevel@tonic-gate break; 7767c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_ARRAY: 7777c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (boolean_t); 7787c478bd9Sstevel@tonic-gate break; 7797c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE_ARRAY: 7807c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (uchar_t); 7817c478bd9Sstevel@tonic-gate break; 7827c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8_ARRAY: 7837c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (int8_t); 7847c478bd9Sstevel@tonic-gate break; 7857c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8_ARRAY: 7867c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (uint8_t); 7877c478bd9Sstevel@tonic-gate break; 7887c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16_ARRAY: 7897c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (int16_t); 7907c478bd9Sstevel@tonic-gate break; 7917c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16_ARRAY: 7927c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (uint16_t); 7937c478bd9Sstevel@tonic-gate break; 7947c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32_ARRAY: 7957c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (int32_t); 7967c478bd9Sstevel@tonic-gate break; 7977c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32_ARRAY: 7987c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (uint32_t); 7997c478bd9Sstevel@tonic-gate break; 8007c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64_ARRAY: 8017c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (int64_t); 8027c478bd9Sstevel@tonic-gate break; 8037c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64_ARRAY: 8047c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (uint64_t); 8057c478bd9Sstevel@tonic-gate break; 8067c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY: 8077c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (uint64_t); 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate if (data != NULL) { 8107c478bd9Sstevel@tonic-gate char *const *strs = data; 8117c478bd9Sstevel@tonic-gate uint_t i; 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate /* no alignment requirement for strings */ 8147c478bd9Sstevel@tonic-gate for (i = 0; i < nelem; i++) { 8157c478bd9Sstevel@tonic-gate if (strs[i] == NULL) 8167c478bd9Sstevel@tonic-gate return (-1); 8177c478bd9Sstevel@tonic-gate value_sz += strlen(strs[i]) + 1; 8187c478bd9Sstevel@tonic-gate } 8197c478bd9Sstevel@tonic-gate } 8207c478bd9Sstevel@tonic-gate break; 8217c478bd9Sstevel@tonic-gate case DATA_TYPE_HRTIME: 8227c478bd9Sstevel@tonic-gate value_sz = sizeof (hrtime_t); 8237c478bd9Sstevel@tonic-gate break; 8247c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST: 8257c478bd9Sstevel@tonic-gate value_sz = NV_ALIGN(sizeof (nvlist_t)); 8267c478bd9Sstevel@tonic-gate break; 8277c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: 8287c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (uint64_t) + 8297c478bd9Sstevel@tonic-gate (uint64_t)nelem * NV_ALIGN(sizeof (nvlist_t)); 8307c478bd9Sstevel@tonic-gate break; 8317c478bd9Sstevel@tonic-gate default: 8327c478bd9Sstevel@tonic-gate return (-1); 8337c478bd9Sstevel@tonic-gate } 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate return (value_sz > INT32_MAX ? -1 : (int)value_sz); 8367c478bd9Sstevel@tonic-gate } 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate static int 8397c478bd9Sstevel@tonic-gate nvlist_copy_embedded(nvlist_t *nvl, nvlist_t *onvl, nvlist_t *emb_nvl) 8407c478bd9Sstevel@tonic-gate { 8417c478bd9Sstevel@tonic-gate nvpriv_t *priv; 8427c478bd9Sstevel@tonic-gate int err; 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate if ((priv = nv_priv_alloc_embedded((nvpriv_t *)(uintptr_t) 8457c478bd9Sstevel@tonic-gate nvl->nvl_priv)) == NULL) 8467c478bd9Sstevel@tonic-gate return (ENOMEM); 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate nvlist_init(emb_nvl, onvl->nvl_nvflag, priv); 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate if ((err = nvlist_copy_pairs(onvl, emb_nvl)) != 0) { 8517c478bd9Sstevel@tonic-gate nvlist_free(emb_nvl); 8527c478bd9Sstevel@tonic-gate emb_nvl->nvl_priv = 0; 8537c478bd9Sstevel@tonic-gate } 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate return (err); 8567c478bd9Sstevel@tonic-gate } 8577c478bd9Sstevel@tonic-gate 8587c478bd9Sstevel@tonic-gate /* 8597c478bd9Sstevel@tonic-gate * nvlist_add_common - Add new <name,value> pair to nvlist 8607c478bd9Sstevel@tonic-gate */ 8617c478bd9Sstevel@tonic-gate static int 8627c478bd9Sstevel@tonic-gate nvlist_add_common(nvlist_t *nvl, const char *name, 8637c478bd9Sstevel@tonic-gate data_type_t type, uint_t nelem, const void *data) 8647c478bd9Sstevel@tonic-gate { 8657c478bd9Sstevel@tonic-gate nvpair_t *nvp; 866d9638e54Smws uint_t i; 867d9638e54Smws 8687c478bd9Sstevel@tonic-gate int nvp_sz, name_sz, value_sz; 8697c478bd9Sstevel@tonic-gate int err = 0; 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate if (name == NULL || nvl == NULL || nvl->nvl_priv == 0) 8727c478bd9Sstevel@tonic-gate return (EINVAL); 8737c478bd9Sstevel@tonic-gate 8747c478bd9Sstevel@tonic-gate if (nelem != 0 && data == NULL) 8757c478bd9Sstevel@tonic-gate return (EINVAL); 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate /* 8787c478bd9Sstevel@tonic-gate * Verify type and nelem and get the value size. 8797c478bd9Sstevel@tonic-gate * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY 8807c478bd9Sstevel@tonic-gate * is the size of the string(s) included. 8817c478bd9Sstevel@tonic-gate */ 8827c478bd9Sstevel@tonic-gate if ((value_sz = i_get_value_size(type, data, nelem)) < 0) 8837c478bd9Sstevel@tonic-gate return (EINVAL); 8847c478bd9Sstevel@tonic-gate 8857c478bd9Sstevel@tonic-gate if (i_validate_nvpair_value(type, nelem, data) != 0) 8867c478bd9Sstevel@tonic-gate return (EINVAL); 8877c478bd9Sstevel@tonic-gate 888d9638e54Smws /* 889d9638e54Smws * If we're adding an nvlist or nvlist array, ensure that we are not 890d9638e54Smws * adding the input nvlist to itself, which would cause recursion, 891d9638e54Smws * and ensure that no NULL nvlist pointers are present. 892d9638e54Smws */ 8937c478bd9Sstevel@tonic-gate switch (type) { 8947c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST: 895d9638e54Smws if (data == nvl || data == NULL) 8967c478bd9Sstevel@tonic-gate return (EINVAL); 8977c478bd9Sstevel@tonic-gate break; 8987c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: { 899d9638e54Smws nvlist_t **onvlp = (nvlist_t **)data; 900d9638e54Smws for (i = 0; i < nelem; i++) { 901d9638e54Smws if (onvlp[i] == nvl || onvlp[i] == NULL) 9027c478bd9Sstevel@tonic-gate return (EINVAL); 9037c478bd9Sstevel@tonic-gate } 9047c478bd9Sstevel@tonic-gate break; 905d9638e54Smws } 9065ad82045Snd default: 9075ad82045Snd break; 9087c478bd9Sstevel@tonic-gate } 9097c478bd9Sstevel@tonic-gate 9107c478bd9Sstevel@tonic-gate /* calculate sizes of the nvpair elements and the nvpair itself */ 9117c478bd9Sstevel@tonic-gate name_sz = strlen(name) + 1; 91248dd5e63SMatthew Ahrens if (name_sz >= 1ULL << (sizeof (nvp->nvp_name_sz) * NBBY - 1)) 91348dd5e63SMatthew Ahrens return (EINVAL); 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate nvp_sz = NVP_SIZE_CALC(name_sz, value_sz); 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate if ((nvp = nvp_buf_alloc(nvl, nvp_sz)) == NULL) 9187c478bd9Sstevel@tonic-gate return (ENOMEM); 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate ASSERT(nvp->nvp_size == nvp_sz); 9217c478bd9Sstevel@tonic-gate nvp->nvp_name_sz = name_sz; 9227c478bd9Sstevel@tonic-gate nvp->nvp_value_elem = nelem; 9237c478bd9Sstevel@tonic-gate nvp->nvp_type = type; 9247c478bd9Sstevel@tonic-gate bcopy(name, NVP_NAME(nvp), name_sz); 9257c478bd9Sstevel@tonic-gate 9267c478bd9Sstevel@tonic-gate switch (type) { 9277c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN: 9287c478bd9Sstevel@tonic-gate break; 9297c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY: { 9307c478bd9Sstevel@tonic-gate char *const *strs = data; 9317c478bd9Sstevel@tonic-gate char *buf = NVP_VALUE(nvp); 9327c478bd9Sstevel@tonic-gate char **cstrs = (void *)buf; 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate /* skip pre-allocated space for pointer array */ 9357c478bd9Sstevel@tonic-gate buf += nelem * sizeof (uint64_t); 9367c478bd9Sstevel@tonic-gate for (i = 0; i < nelem; i++) { 9377c478bd9Sstevel@tonic-gate int slen = strlen(strs[i]) + 1; 9387c478bd9Sstevel@tonic-gate bcopy(strs[i], buf, slen); 9397c478bd9Sstevel@tonic-gate cstrs[i] = buf; 9407c478bd9Sstevel@tonic-gate buf += slen; 9417c478bd9Sstevel@tonic-gate } 9427c478bd9Sstevel@tonic-gate break; 9437c478bd9Sstevel@tonic-gate } 9447c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST: { 9457c478bd9Sstevel@tonic-gate nvlist_t *nnvl = EMBEDDED_NVL(nvp); 9467c478bd9Sstevel@tonic-gate nvlist_t *onvl = (nvlist_t *)data; 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate if ((err = nvlist_copy_embedded(nvl, onvl, nnvl)) != 0) { 9497c478bd9Sstevel@tonic-gate nvp_buf_free(nvl, nvp); 9507c478bd9Sstevel@tonic-gate return (err); 9517c478bd9Sstevel@tonic-gate } 9527c478bd9Sstevel@tonic-gate break; 9537c478bd9Sstevel@tonic-gate } 9547c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: { 9557c478bd9Sstevel@tonic-gate nvlist_t **onvlp = (nvlist_t **)data; 9567c478bd9Sstevel@tonic-gate nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp); 9577c478bd9Sstevel@tonic-gate nvlist_t *embedded = (nvlist_t *) 9587c478bd9Sstevel@tonic-gate ((uintptr_t)nvlp + nelem * sizeof (uint64_t)); 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate for (i = 0; i < nelem; i++) { 9617c478bd9Sstevel@tonic-gate if ((err = nvlist_copy_embedded(nvl, 9627c478bd9Sstevel@tonic-gate onvlp[i], embedded)) != 0) { 9637c478bd9Sstevel@tonic-gate /* 9647c478bd9Sstevel@tonic-gate * Free any successfully created lists 9657c478bd9Sstevel@tonic-gate */ 9667c478bd9Sstevel@tonic-gate nvpair_free(nvp); 9677c478bd9Sstevel@tonic-gate nvp_buf_free(nvl, nvp); 9687c478bd9Sstevel@tonic-gate return (err); 9697c478bd9Sstevel@tonic-gate } 9707c478bd9Sstevel@tonic-gate 9717c478bd9Sstevel@tonic-gate nvlp[i] = embedded++; 9727c478bd9Sstevel@tonic-gate } 9737c478bd9Sstevel@tonic-gate break; 9747c478bd9Sstevel@tonic-gate } 9757c478bd9Sstevel@tonic-gate default: 9767c478bd9Sstevel@tonic-gate bcopy(data, NVP_VALUE(nvp), value_sz); 9777c478bd9Sstevel@tonic-gate } 9787c478bd9Sstevel@tonic-gate 9797c478bd9Sstevel@tonic-gate /* if unique name, remove before add */ 9807c478bd9Sstevel@tonic-gate if (nvl->nvl_nvflag & NV_UNIQUE_NAME) 9817c478bd9Sstevel@tonic-gate (void) nvlist_remove_all(nvl, name); 9827c478bd9Sstevel@tonic-gate else if (nvl->nvl_nvflag & NV_UNIQUE_NAME_TYPE) 9837c478bd9Sstevel@tonic-gate (void) nvlist_remove(nvl, name, type); 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate nvp_buf_link(nvl, nvp); 9867c478bd9Sstevel@tonic-gate 9877c478bd9Sstevel@tonic-gate return (0); 9887c478bd9Sstevel@tonic-gate } 9897c478bd9Sstevel@tonic-gate 9907c478bd9Sstevel@tonic-gate int 9917c478bd9Sstevel@tonic-gate nvlist_add_boolean(nvlist_t *nvl, const char *name) 9927c478bd9Sstevel@tonic-gate { 9937c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN, 0, NULL)); 9947c478bd9Sstevel@tonic-gate } 9957c478bd9Sstevel@tonic-gate 9967c478bd9Sstevel@tonic-gate int 9977c478bd9Sstevel@tonic-gate nvlist_add_boolean_value(nvlist_t *nvl, const char *name, boolean_t val) 9987c478bd9Sstevel@tonic-gate { 9997c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_VALUE, 1, &val)); 10007c478bd9Sstevel@tonic-gate } 10017c478bd9Sstevel@tonic-gate 10027c478bd9Sstevel@tonic-gate int 10037c478bd9Sstevel@tonic-gate nvlist_add_byte(nvlist_t *nvl, const char *name, uchar_t val) 10047c478bd9Sstevel@tonic-gate { 10057c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE, 1, &val)); 10067c478bd9Sstevel@tonic-gate } 10077c478bd9Sstevel@tonic-gate 10087c478bd9Sstevel@tonic-gate int 10097c478bd9Sstevel@tonic-gate nvlist_add_int8(nvlist_t *nvl, const char *name, int8_t val) 10107c478bd9Sstevel@tonic-gate { 10117c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_INT8, 1, &val)); 10127c478bd9Sstevel@tonic-gate } 10137c478bd9Sstevel@tonic-gate 10147c478bd9Sstevel@tonic-gate int 10157c478bd9Sstevel@tonic-gate nvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t val) 10167c478bd9Sstevel@tonic-gate { 10177c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8, 1, &val)); 10187c478bd9Sstevel@tonic-gate } 10197c478bd9Sstevel@tonic-gate 10207c478bd9Sstevel@tonic-gate int 10217c478bd9Sstevel@tonic-gate nvlist_add_int16(nvlist_t *nvl, const char *name, int16_t val) 10227c478bd9Sstevel@tonic-gate { 10237c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_INT16, 1, &val)); 10247c478bd9Sstevel@tonic-gate } 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate int 10277c478bd9Sstevel@tonic-gate nvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t val) 10287c478bd9Sstevel@tonic-gate { 10297c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16, 1, &val)); 10307c478bd9Sstevel@tonic-gate } 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate int 10337c478bd9Sstevel@tonic-gate nvlist_add_int32(nvlist_t *nvl, const char *name, int32_t val) 10347c478bd9Sstevel@tonic-gate { 10357c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_INT32, 1, &val)); 10367c478bd9Sstevel@tonic-gate } 10377c478bd9Sstevel@tonic-gate 10387c478bd9Sstevel@tonic-gate int 10397c478bd9Sstevel@tonic-gate nvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t val) 10407c478bd9Sstevel@tonic-gate { 10417c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32, 1, &val)); 10427c478bd9Sstevel@tonic-gate } 10437c478bd9Sstevel@tonic-gate 10447c478bd9Sstevel@tonic-gate int 10457c478bd9Sstevel@tonic-gate nvlist_add_int64(nvlist_t *nvl, const char *name, int64_t val) 10467c478bd9Sstevel@tonic-gate { 10477c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_INT64, 1, &val)); 10487c478bd9Sstevel@tonic-gate } 10497c478bd9Sstevel@tonic-gate 10507c478bd9Sstevel@tonic-gate int 10517c478bd9Sstevel@tonic-gate nvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t val) 10527c478bd9Sstevel@tonic-gate { 10537c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64, 1, &val)); 10547c478bd9Sstevel@tonic-gate } 10557c478bd9Sstevel@tonic-gate 1056825ba0f2Srobj #if !defined(_KERNEL) 1057825ba0f2Srobj int 1058825ba0f2Srobj nvlist_add_double(nvlist_t *nvl, const char *name, double val) 1059825ba0f2Srobj { 1060825ba0f2Srobj return (nvlist_add_common(nvl, name, DATA_TYPE_DOUBLE, 1, &val)); 1061825ba0f2Srobj } 1062825ba0f2Srobj #endif 1063825ba0f2Srobj 10647c478bd9Sstevel@tonic-gate int 10657c478bd9Sstevel@tonic-gate nvlist_add_string(nvlist_t *nvl, const char *name, const char *val) 10667c478bd9Sstevel@tonic-gate { 10677c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_STRING, 1, (void *)val)); 10687c478bd9Sstevel@tonic-gate } 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate int 10717c478bd9Sstevel@tonic-gate nvlist_add_boolean_array(nvlist_t *nvl, const char *name, 10727c478bd9Sstevel@tonic-gate boolean_t *a, uint_t n) 10737c478bd9Sstevel@tonic-gate { 10747c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_ARRAY, n, a)); 10757c478bd9Sstevel@tonic-gate } 10767c478bd9Sstevel@tonic-gate 10777c478bd9Sstevel@tonic-gate int 10787c478bd9Sstevel@tonic-gate nvlist_add_byte_array(nvlist_t *nvl, const char *name, uchar_t *a, uint_t n) 10797c478bd9Sstevel@tonic-gate { 10807c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a)); 10817c478bd9Sstevel@tonic-gate } 10827c478bd9Sstevel@tonic-gate 10837c478bd9Sstevel@tonic-gate int 10847c478bd9Sstevel@tonic-gate nvlist_add_int8_array(nvlist_t *nvl, const char *name, int8_t *a, uint_t n) 10857c478bd9Sstevel@tonic-gate { 10867c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a)); 10877c478bd9Sstevel@tonic-gate } 10887c478bd9Sstevel@tonic-gate 10897c478bd9Sstevel@tonic-gate int 10907c478bd9Sstevel@tonic-gate nvlist_add_uint8_array(nvlist_t *nvl, const char *name, uint8_t *a, uint_t n) 10917c478bd9Sstevel@tonic-gate { 10927c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a)); 10937c478bd9Sstevel@tonic-gate } 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate int 10967c478bd9Sstevel@tonic-gate nvlist_add_int16_array(nvlist_t *nvl, const char *name, int16_t *a, uint_t n) 10977c478bd9Sstevel@tonic-gate { 10987c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a)); 10997c478bd9Sstevel@tonic-gate } 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate int 11027c478bd9Sstevel@tonic-gate nvlist_add_uint16_array(nvlist_t *nvl, const char *name, uint16_t *a, uint_t n) 11037c478bd9Sstevel@tonic-gate { 11047c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a)); 11057c478bd9Sstevel@tonic-gate } 11067c478bd9Sstevel@tonic-gate 11077c478bd9Sstevel@tonic-gate int 11087c478bd9Sstevel@tonic-gate nvlist_add_int32_array(nvlist_t *nvl, const char *name, int32_t *a, uint_t n) 11097c478bd9Sstevel@tonic-gate { 11107c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a)); 11117c478bd9Sstevel@tonic-gate } 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate int 11147c478bd9Sstevel@tonic-gate nvlist_add_uint32_array(nvlist_t *nvl, const char *name, uint32_t *a, uint_t n) 11157c478bd9Sstevel@tonic-gate { 11167c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a)); 11177c478bd9Sstevel@tonic-gate } 11187c478bd9Sstevel@tonic-gate 11197c478bd9Sstevel@tonic-gate int 11207c478bd9Sstevel@tonic-gate nvlist_add_int64_array(nvlist_t *nvl, const char *name, int64_t *a, uint_t n) 11217c478bd9Sstevel@tonic-gate { 11227c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a)); 11237c478bd9Sstevel@tonic-gate } 11247c478bd9Sstevel@tonic-gate 11257c478bd9Sstevel@tonic-gate int 11267c478bd9Sstevel@tonic-gate nvlist_add_uint64_array(nvlist_t *nvl, const char *name, uint64_t *a, uint_t n) 11277c478bd9Sstevel@tonic-gate { 11287c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a)); 11297c478bd9Sstevel@tonic-gate } 11307c478bd9Sstevel@tonic-gate 11317c478bd9Sstevel@tonic-gate int 11327c478bd9Sstevel@tonic-gate nvlist_add_string_array(nvlist_t *nvl, const char *name, 11337c478bd9Sstevel@tonic-gate char *const *a, uint_t n) 11347c478bd9Sstevel@tonic-gate { 11357c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a)); 11367c478bd9Sstevel@tonic-gate } 11377c478bd9Sstevel@tonic-gate 11387c478bd9Sstevel@tonic-gate int 11397c478bd9Sstevel@tonic-gate nvlist_add_hrtime(nvlist_t *nvl, const char *name, hrtime_t val) 11407c478bd9Sstevel@tonic-gate { 11417c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_HRTIME, 1, &val)); 11427c478bd9Sstevel@tonic-gate } 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate int 11457c478bd9Sstevel@tonic-gate nvlist_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val) 11467c478bd9Sstevel@tonic-gate { 11477c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST, 1, val)); 11487c478bd9Sstevel@tonic-gate } 11497c478bd9Sstevel@tonic-gate 11507c478bd9Sstevel@tonic-gate int 11517c478bd9Sstevel@tonic-gate nvlist_add_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **a, uint_t n) 11527c478bd9Sstevel@tonic-gate { 11537c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a)); 11547c478bd9Sstevel@tonic-gate } 11557c478bd9Sstevel@tonic-gate 11567c478bd9Sstevel@tonic-gate /* reading name-value pairs */ 11577c478bd9Sstevel@tonic-gate nvpair_t * 11587c478bd9Sstevel@tonic-gate nvlist_next_nvpair(nvlist_t *nvl, nvpair_t *nvp) 11597c478bd9Sstevel@tonic-gate { 11607c478bd9Sstevel@tonic-gate nvpriv_t *priv; 11617c478bd9Sstevel@tonic-gate i_nvp_t *curr; 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate if (nvl == NULL || 11647c478bd9Sstevel@tonic-gate (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 11657c478bd9Sstevel@tonic-gate return (NULL); 11667c478bd9Sstevel@tonic-gate 11677c478bd9Sstevel@tonic-gate curr = NVPAIR2I_NVP(nvp); 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate /* 11703cb34c60Sahrens * Ensure that nvp is a valid nvpair on this nvlist. 11713cb34c60Sahrens * NB: nvp_curr is used only as a hint so that we don't always 11723cb34c60Sahrens * have to walk the list to determine if nvp is still on the list. 11737c478bd9Sstevel@tonic-gate */ 11747c478bd9Sstevel@tonic-gate if (nvp == NULL) 11757c478bd9Sstevel@tonic-gate curr = priv->nvp_list; 11763cb34c60Sahrens else if (priv->nvp_curr == curr || nvlist_contains_nvp(nvl, nvp)) 11777c478bd9Sstevel@tonic-gate curr = curr->nvi_next; 11783cb34c60Sahrens else 11797c478bd9Sstevel@tonic-gate curr = NULL; 11807c478bd9Sstevel@tonic-gate 11817c478bd9Sstevel@tonic-gate priv->nvp_curr = curr; 11827c478bd9Sstevel@tonic-gate 11837c478bd9Sstevel@tonic-gate return (curr != NULL ? &curr->nvi_nvp : NULL); 11847c478bd9Sstevel@tonic-gate } 11857c478bd9Sstevel@tonic-gate 118692241e0bSTom Erickson nvpair_t * 118792241e0bSTom Erickson nvlist_prev_nvpair(nvlist_t *nvl, nvpair_t *nvp) 118892241e0bSTom Erickson { 118992241e0bSTom Erickson nvpriv_t *priv; 119092241e0bSTom Erickson i_nvp_t *curr; 119192241e0bSTom Erickson 119292241e0bSTom Erickson if (nvl == NULL || 119392241e0bSTom Erickson (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 119492241e0bSTom Erickson return (NULL); 119592241e0bSTom Erickson 119692241e0bSTom Erickson curr = NVPAIR2I_NVP(nvp); 119792241e0bSTom Erickson 119892241e0bSTom Erickson if (nvp == NULL) 119992241e0bSTom Erickson curr = priv->nvp_last; 120092241e0bSTom Erickson else if (priv->nvp_curr == curr || nvlist_contains_nvp(nvl, nvp)) 120192241e0bSTom Erickson curr = curr->nvi_prev; 120292241e0bSTom Erickson else 120392241e0bSTom Erickson curr = NULL; 120492241e0bSTom Erickson 120592241e0bSTom Erickson priv->nvp_curr = curr; 120692241e0bSTom Erickson 120792241e0bSTom Erickson return (curr != NULL ? &curr->nvi_nvp : NULL); 120892241e0bSTom Erickson } 120992241e0bSTom Erickson 121092241e0bSTom Erickson boolean_t 121192241e0bSTom Erickson nvlist_empty(nvlist_t *nvl) 121292241e0bSTom Erickson { 121392241e0bSTom Erickson nvpriv_t *priv; 121492241e0bSTom Erickson 121592241e0bSTom Erickson if (nvl == NULL || 121692241e0bSTom Erickson (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 121792241e0bSTom Erickson return (B_TRUE); 121892241e0bSTom Erickson 121992241e0bSTom Erickson return (priv->nvp_list == NULL); 122092241e0bSTom Erickson } 122192241e0bSTom Erickson 12227c478bd9Sstevel@tonic-gate char * 12237c478bd9Sstevel@tonic-gate nvpair_name(nvpair_t *nvp) 12247c478bd9Sstevel@tonic-gate { 12257c478bd9Sstevel@tonic-gate return (NVP_NAME(nvp)); 12267c478bd9Sstevel@tonic-gate } 12277c478bd9Sstevel@tonic-gate 12287c478bd9Sstevel@tonic-gate data_type_t 12297c478bd9Sstevel@tonic-gate nvpair_type(nvpair_t *nvp) 12307c478bd9Sstevel@tonic-gate { 12317c478bd9Sstevel@tonic-gate return (NVP_TYPE(nvp)); 12327c478bd9Sstevel@tonic-gate } 12337c478bd9Sstevel@tonic-gate 1234602ca9eaScth int 1235602ca9eaScth nvpair_type_is_array(nvpair_t *nvp) 1236602ca9eaScth { 1237602ca9eaScth data_type_t type = NVP_TYPE(nvp); 1238602ca9eaScth 1239602ca9eaScth if ((type == DATA_TYPE_BYTE_ARRAY) || 1240bf4d553bSAndriy Gapon (type == DATA_TYPE_INT8_ARRAY) || 1241602ca9eaScth (type == DATA_TYPE_UINT8_ARRAY) || 1242602ca9eaScth (type == DATA_TYPE_INT16_ARRAY) || 1243602ca9eaScth (type == DATA_TYPE_UINT16_ARRAY) || 1244602ca9eaScth (type == DATA_TYPE_INT32_ARRAY) || 1245602ca9eaScth (type == DATA_TYPE_UINT32_ARRAY) || 1246602ca9eaScth (type == DATA_TYPE_INT64_ARRAY) || 1247602ca9eaScth (type == DATA_TYPE_UINT64_ARRAY) || 1248602ca9eaScth (type == DATA_TYPE_BOOLEAN_ARRAY) || 1249602ca9eaScth (type == DATA_TYPE_STRING_ARRAY) || 1250602ca9eaScth (type == DATA_TYPE_NVLIST_ARRAY)) 1251602ca9eaScth return (1); 1252602ca9eaScth return (0); 1253602ca9eaScth 1254602ca9eaScth } 1255602ca9eaScth 12567c478bd9Sstevel@tonic-gate static int 12577c478bd9Sstevel@tonic-gate nvpair_value_common(nvpair_t *nvp, data_type_t type, uint_t *nelem, void *data) 12587c478bd9Sstevel@tonic-gate { 12597c478bd9Sstevel@tonic-gate if (nvp == NULL || nvpair_type(nvp) != type) 12607c478bd9Sstevel@tonic-gate return (EINVAL); 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate /* 12637c478bd9Sstevel@tonic-gate * For non-array types, we copy the data. 12647c478bd9Sstevel@tonic-gate * For array types (including string), we set a pointer. 12657c478bd9Sstevel@tonic-gate */ 12667c478bd9Sstevel@tonic-gate switch (type) { 12677c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN: 12687c478bd9Sstevel@tonic-gate if (nelem != NULL) 12697c478bd9Sstevel@tonic-gate *nelem = 0; 12707c478bd9Sstevel@tonic-gate break; 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_VALUE: 12737c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE: 12747c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8: 12757c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8: 12767c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16: 12777c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16: 12787c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32: 12797c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32: 12807c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64: 12817c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64: 12827c478bd9Sstevel@tonic-gate case DATA_TYPE_HRTIME: 1283825ba0f2Srobj #if !defined(_KERNEL) 1284825ba0f2Srobj case DATA_TYPE_DOUBLE: 1285825ba0f2Srobj #endif 12867c478bd9Sstevel@tonic-gate if (data == NULL) 12877c478bd9Sstevel@tonic-gate return (EINVAL); 12887c478bd9Sstevel@tonic-gate bcopy(NVP_VALUE(nvp), data, 12897c478bd9Sstevel@tonic-gate (size_t)i_get_value_size(type, NULL, 1)); 12907c478bd9Sstevel@tonic-gate if (nelem != NULL) 12917c478bd9Sstevel@tonic-gate *nelem = 1; 12927c478bd9Sstevel@tonic-gate break; 12937c478bd9Sstevel@tonic-gate 12947c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST: 12957c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING: 12967c478bd9Sstevel@tonic-gate if (data == NULL) 12977c478bd9Sstevel@tonic-gate return (EINVAL); 12987c478bd9Sstevel@tonic-gate *(void **)data = (void *)NVP_VALUE(nvp); 12997c478bd9Sstevel@tonic-gate if (nelem != NULL) 13007c478bd9Sstevel@tonic-gate *nelem = 1; 13017c478bd9Sstevel@tonic-gate break; 13027c478bd9Sstevel@tonic-gate 13037c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_ARRAY: 13047c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE_ARRAY: 13057c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8_ARRAY: 13067c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8_ARRAY: 13077c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16_ARRAY: 13087c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16_ARRAY: 13097c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32_ARRAY: 13107c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32_ARRAY: 13117c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64_ARRAY: 13127c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64_ARRAY: 13137c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY: 13147c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: 13157c478bd9Sstevel@tonic-gate if (nelem == NULL || data == NULL) 13167c478bd9Sstevel@tonic-gate return (EINVAL); 13177c478bd9Sstevel@tonic-gate if ((*nelem = NVP_NELEM(nvp)) != 0) 13187c478bd9Sstevel@tonic-gate *(void **)data = (void *)NVP_VALUE(nvp); 13197c478bd9Sstevel@tonic-gate else 13207c478bd9Sstevel@tonic-gate *(void **)data = NULL; 13217c478bd9Sstevel@tonic-gate break; 13227c478bd9Sstevel@tonic-gate 13237c478bd9Sstevel@tonic-gate default: 13247c478bd9Sstevel@tonic-gate return (ENOTSUP); 13257c478bd9Sstevel@tonic-gate } 13267c478bd9Sstevel@tonic-gate 13277c478bd9Sstevel@tonic-gate return (0); 13287c478bd9Sstevel@tonic-gate } 13297c478bd9Sstevel@tonic-gate 13307c478bd9Sstevel@tonic-gate static int 13317c478bd9Sstevel@tonic-gate nvlist_lookup_common(nvlist_t *nvl, const char *name, data_type_t type, 13327c478bd9Sstevel@tonic-gate uint_t *nelem, void *data) 13337c478bd9Sstevel@tonic-gate { 13347c478bd9Sstevel@tonic-gate nvpriv_t *priv; 13357c478bd9Sstevel@tonic-gate nvpair_t *nvp; 13367c478bd9Sstevel@tonic-gate i_nvp_t *curr; 13377c478bd9Sstevel@tonic-gate 13387c478bd9Sstevel@tonic-gate if (name == NULL || nvl == NULL || 13397c478bd9Sstevel@tonic-gate (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 13407c478bd9Sstevel@tonic-gate return (EINVAL); 13417c478bd9Sstevel@tonic-gate 13427c478bd9Sstevel@tonic-gate if (!(nvl->nvl_nvflag & (NV_UNIQUE_NAME | NV_UNIQUE_NAME_TYPE))) 13437c478bd9Sstevel@tonic-gate return (ENOTSUP); 13447c478bd9Sstevel@tonic-gate 13457c478bd9Sstevel@tonic-gate for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) { 13467c478bd9Sstevel@tonic-gate nvp = &curr->nvi_nvp; 13477c478bd9Sstevel@tonic-gate 13487c478bd9Sstevel@tonic-gate if (strcmp(name, NVP_NAME(nvp)) == 0 && NVP_TYPE(nvp) == type) 13497c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, type, nelem, data)); 13507c478bd9Sstevel@tonic-gate } 13517c478bd9Sstevel@tonic-gate 13527c478bd9Sstevel@tonic-gate return (ENOENT); 13537c478bd9Sstevel@tonic-gate } 13547c478bd9Sstevel@tonic-gate 13557c478bd9Sstevel@tonic-gate int 13567c478bd9Sstevel@tonic-gate nvlist_lookup_boolean(nvlist_t *nvl, const char *name) 13577c478bd9Sstevel@tonic-gate { 13587c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_BOOLEAN, NULL, NULL)); 13597c478bd9Sstevel@tonic-gate } 13607c478bd9Sstevel@tonic-gate 13617c478bd9Sstevel@tonic-gate int 13627c478bd9Sstevel@tonic-gate nvlist_lookup_boolean_value(nvlist_t *nvl, const char *name, boolean_t *val) 13637c478bd9Sstevel@tonic-gate { 13647c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, 13657c478bd9Sstevel@tonic-gate DATA_TYPE_BOOLEAN_VALUE, NULL, val)); 13667c478bd9Sstevel@tonic-gate } 13677c478bd9Sstevel@tonic-gate 13687c478bd9Sstevel@tonic-gate int 13697c478bd9Sstevel@tonic-gate nvlist_lookup_byte(nvlist_t *nvl, const char *name, uchar_t *val) 13707c478bd9Sstevel@tonic-gate { 13717c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_BYTE, NULL, val)); 13727c478bd9Sstevel@tonic-gate } 13737c478bd9Sstevel@tonic-gate 13747c478bd9Sstevel@tonic-gate int 13757c478bd9Sstevel@tonic-gate nvlist_lookup_int8(nvlist_t *nvl, const char *name, int8_t *val) 13767c478bd9Sstevel@tonic-gate { 13777c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT8, NULL, val)); 13787c478bd9Sstevel@tonic-gate } 13797c478bd9Sstevel@tonic-gate 13807c478bd9Sstevel@tonic-gate int 13817c478bd9Sstevel@tonic-gate nvlist_lookup_uint8(nvlist_t *nvl, const char *name, uint8_t *val) 13827c478bd9Sstevel@tonic-gate { 13837c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT8, NULL, val)); 13847c478bd9Sstevel@tonic-gate } 13857c478bd9Sstevel@tonic-gate 13867c478bd9Sstevel@tonic-gate int 13877c478bd9Sstevel@tonic-gate nvlist_lookup_int16(nvlist_t *nvl, const char *name, int16_t *val) 13887c478bd9Sstevel@tonic-gate { 13897c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT16, NULL, val)); 13907c478bd9Sstevel@tonic-gate } 13917c478bd9Sstevel@tonic-gate 13927c478bd9Sstevel@tonic-gate int 13937c478bd9Sstevel@tonic-gate nvlist_lookup_uint16(nvlist_t *nvl, const char *name, uint16_t *val) 13947c478bd9Sstevel@tonic-gate { 13957c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT16, NULL, val)); 13967c478bd9Sstevel@tonic-gate } 13977c478bd9Sstevel@tonic-gate 13987c478bd9Sstevel@tonic-gate int 13997c478bd9Sstevel@tonic-gate nvlist_lookup_int32(nvlist_t *nvl, const char *name, int32_t *val) 14007c478bd9Sstevel@tonic-gate { 14017c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT32, NULL, val)); 14027c478bd9Sstevel@tonic-gate } 14037c478bd9Sstevel@tonic-gate 14047c478bd9Sstevel@tonic-gate int 14057c478bd9Sstevel@tonic-gate nvlist_lookup_uint32(nvlist_t *nvl, const char *name, uint32_t *val) 14067c478bd9Sstevel@tonic-gate { 14077c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT32, NULL, val)); 14087c478bd9Sstevel@tonic-gate } 14097c478bd9Sstevel@tonic-gate 14107c478bd9Sstevel@tonic-gate int 14117c478bd9Sstevel@tonic-gate nvlist_lookup_int64(nvlist_t *nvl, const char *name, int64_t *val) 14127c478bd9Sstevel@tonic-gate { 14137c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT64, NULL, val)); 14147c478bd9Sstevel@tonic-gate } 14157c478bd9Sstevel@tonic-gate 14167c478bd9Sstevel@tonic-gate int 14177c478bd9Sstevel@tonic-gate nvlist_lookup_uint64(nvlist_t *nvl, const char *name, uint64_t *val) 14187c478bd9Sstevel@tonic-gate { 14197c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT64, NULL, val)); 14207c478bd9Sstevel@tonic-gate } 14217c478bd9Sstevel@tonic-gate 1422825ba0f2Srobj #if !defined(_KERNEL) 1423825ba0f2Srobj int 1424825ba0f2Srobj nvlist_lookup_double(nvlist_t *nvl, const char *name, double *val) 1425825ba0f2Srobj { 1426825ba0f2Srobj return (nvlist_lookup_common(nvl, name, DATA_TYPE_DOUBLE, NULL, val)); 1427825ba0f2Srobj } 1428825ba0f2Srobj #endif 1429825ba0f2Srobj 14307c478bd9Sstevel@tonic-gate int 14317c478bd9Sstevel@tonic-gate nvlist_lookup_string(nvlist_t *nvl, const char *name, char **val) 14327c478bd9Sstevel@tonic-gate { 14337c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_STRING, NULL, val)); 14347c478bd9Sstevel@tonic-gate } 14357c478bd9Sstevel@tonic-gate 14367c478bd9Sstevel@tonic-gate int 14377c478bd9Sstevel@tonic-gate nvlist_lookup_nvlist(nvlist_t *nvl, const char *name, nvlist_t **val) 14387c478bd9Sstevel@tonic-gate { 14397c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_NVLIST, NULL, val)); 14407c478bd9Sstevel@tonic-gate } 14417c478bd9Sstevel@tonic-gate 14427c478bd9Sstevel@tonic-gate int 14437c478bd9Sstevel@tonic-gate nvlist_lookup_boolean_array(nvlist_t *nvl, const char *name, 14447c478bd9Sstevel@tonic-gate boolean_t **a, uint_t *n) 14457c478bd9Sstevel@tonic-gate { 14467c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, 14477c478bd9Sstevel@tonic-gate DATA_TYPE_BOOLEAN_ARRAY, n, a)); 14487c478bd9Sstevel@tonic-gate } 14497c478bd9Sstevel@tonic-gate 14507c478bd9Sstevel@tonic-gate int 14517c478bd9Sstevel@tonic-gate nvlist_lookup_byte_array(nvlist_t *nvl, const char *name, 14527c478bd9Sstevel@tonic-gate uchar_t **a, uint_t *n) 14537c478bd9Sstevel@tonic-gate { 14547c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a)); 14557c478bd9Sstevel@tonic-gate } 14567c478bd9Sstevel@tonic-gate 14577c478bd9Sstevel@tonic-gate int 14587c478bd9Sstevel@tonic-gate nvlist_lookup_int8_array(nvlist_t *nvl, const char *name, int8_t **a, uint_t *n) 14597c478bd9Sstevel@tonic-gate { 14607c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a)); 14617c478bd9Sstevel@tonic-gate } 14627c478bd9Sstevel@tonic-gate 14637c478bd9Sstevel@tonic-gate int 14647c478bd9Sstevel@tonic-gate nvlist_lookup_uint8_array(nvlist_t *nvl, const char *name, 14657c478bd9Sstevel@tonic-gate uint8_t **a, uint_t *n) 14667c478bd9Sstevel@tonic-gate { 14677c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a)); 14687c478bd9Sstevel@tonic-gate } 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate int 14717c478bd9Sstevel@tonic-gate nvlist_lookup_int16_array(nvlist_t *nvl, const char *name, 14727c478bd9Sstevel@tonic-gate int16_t **a, uint_t *n) 14737c478bd9Sstevel@tonic-gate { 14747c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a)); 14757c478bd9Sstevel@tonic-gate } 14767c478bd9Sstevel@tonic-gate 14777c478bd9Sstevel@tonic-gate int 14787c478bd9Sstevel@tonic-gate nvlist_lookup_uint16_array(nvlist_t *nvl, const char *name, 14797c478bd9Sstevel@tonic-gate uint16_t **a, uint_t *n) 14807c478bd9Sstevel@tonic-gate { 14817c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a)); 14827c478bd9Sstevel@tonic-gate } 14837c478bd9Sstevel@tonic-gate 14847c478bd9Sstevel@tonic-gate int 14857c478bd9Sstevel@tonic-gate nvlist_lookup_int32_array(nvlist_t *nvl, const char *name, 14867c478bd9Sstevel@tonic-gate int32_t **a, uint_t *n) 14877c478bd9Sstevel@tonic-gate { 14887c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a)); 14897c478bd9Sstevel@tonic-gate } 14907c478bd9Sstevel@tonic-gate 14917c478bd9Sstevel@tonic-gate int 14927c478bd9Sstevel@tonic-gate nvlist_lookup_uint32_array(nvlist_t *nvl, const char *name, 14937c478bd9Sstevel@tonic-gate uint32_t **a, uint_t *n) 14947c478bd9Sstevel@tonic-gate { 14957c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a)); 14967c478bd9Sstevel@tonic-gate } 14977c478bd9Sstevel@tonic-gate 14987c478bd9Sstevel@tonic-gate int 14997c478bd9Sstevel@tonic-gate nvlist_lookup_int64_array(nvlist_t *nvl, const char *name, 15007c478bd9Sstevel@tonic-gate int64_t **a, uint_t *n) 15017c478bd9Sstevel@tonic-gate { 15027c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a)); 15037c478bd9Sstevel@tonic-gate } 15047c478bd9Sstevel@tonic-gate 15057c478bd9Sstevel@tonic-gate int 15067c478bd9Sstevel@tonic-gate nvlist_lookup_uint64_array(nvlist_t *nvl, const char *name, 15077c478bd9Sstevel@tonic-gate uint64_t **a, uint_t *n) 15087c478bd9Sstevel@tonic-gate { 15097c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a)); 15107c478bd9Sstevel@tonic-gate } 15117c478bd9Sstevel@tonic-gate 15127c478bd9Sstevel@tonic-gate int 15137c478bd9Sstevel@tonic-gate nvlist_lookup_string_array(nvlist_t *nvl, const char *name, 15147c478bd9Sstevel@tonic-gate char ***a, uint_t *n) 15157c478bd9Sstevel@tonic-gate { 15167c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a)); 15177c478bd9Sstevel@tonic-gate } 15187c478bd9Sstevel@tonic-gate 15197c478bd9Sstevel@tonic-gate int 15207c478bd9Sstevel@tonic-gate nvlist_lookup_nvlist_array(nvlist_t *nvl, const char *name, 15217c478bd9Sstevel@tonic-gate nvlist_t ***a, uint_t *n) 15227c478bd9Sstevel@tonic-gate { 15237c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a)); 15247c478bd9Sstevel@tonic-gate } 15257c478bd9Sstevel@tonic-gate 15267c478bd9Sstevel@tonic-gate int 15277c478bd9Sstevel@tonic-gate nvlist_lookup_hrtime(nvlist_t *nvl, const char *name, hrtime_t *val) 15287c478bd9Sstevel@tonic-gate { 15297c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_HRTIME, NULL, val)); 15307c478bd9Sstevel@tonic-gate } 15317c478bd9Sstevel@tonic-gate 15327c478bd9Sstevel@tonic-gate int 15337c478bd9Sstevel@tonic-gate nvlist_lookup_pairs(nvlist_t *nvl, int flag, ...) 15347c478bd9Sstevel@tonic-gate { 15357c478bd9Sstevel@tonic-gate va_list ap; 15367c478bd9Sstevel@tonic-gate char *name; 15377c478bd9Sstevel@tonic-gate int noentok = (flag & NV_FLAG_NOENTOK ? 1 : 0); 15387c478bd9Sstevel@tonic-gate int ret = 0; 15397c478bd9Sstevel@tonic-gate 15407c478bd9Sstevel@tonic-gate va_start(ap, flag); 15417c478bd9Sstevel@tonic-gate while (ret == 0 && (name = va_arg(ap, char *)) != NULL) { 15427c478bd9Sstevel@tonic-gate data_type_t type; 15437c478bd9Sstevel@tonic-gate void *val; 15447c478bd9Sstevel@tonic-gate uint_t *nelem; 15457c478bd9Sstevel@tonic-gate 15467c478bd9Sstevel@tonic-gate switch (type = va_arg(ap, data_type_t)) { 15477c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN: 15487c478bd9Sstevel@tonic-gate ret = nvlist_lookup_common(nvl, name, type, NULL, NULL); 15497c478bd9Sstevel@tonic-gate break; 15507c478bd9Sstevel@tonic-gate 15517c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_VALUE: 15527c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE: 15537c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8: 15547c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8: 15557c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16: 15567c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16: 15577c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32: 15587c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32: 15597c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64: 15607c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64: 15617c478bd9Sstevel@tonic-gate case DATA_TYPE_HRTIME: 15627c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING: 15637c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST: 1564825ba0f2Srobj #if !defined(_KERNEL) 1565825ba0f2Srobj case DATA_TYPE_DOUBLE: 1566825ba0f2Srobj #endif 15677c478bd9Sstevel@tonic-gate val = va_arg(ap, void *); 15687c478bd9Sstevel@tonic-gate ret = nvlist_lookup_common(nvl, name, type, NULL, val); 15697c478bd9Sstevel@tonic-gate break; 15707c478bd9Sstevel@tonic-gate 15717c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE_ARRAY: 15727c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_ARRAY: 15737c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8_ARRAY: 15747c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8_ARRAY: 15757c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16_ARRAY: 15767c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16_ARRAY: 15777c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32_ARRAY: 15787c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32_ARRAY: 15797c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64_ARRAY: 15807c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64_ARRAY: 15817c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY: 15827c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: 15837c478bd9Sstevel@tonic-gate val = va_arg(ap, void *); 15847c478bd9Sstevel@tonic-gate nelem = va_arg(ap, uint_t *); 15857c478bd9Sstevel@tonic-gate ret = nvlist_lookup_common(nvl, name, type, nelem, val); 15867c478bd9Sstevel@tonic-gate break; 15877c478bd9Sstevel@tonic-gate 15887c478bd9Sstevel@tonic-gate default: 15897c478bd9Sstevel@tonic-gate ret = EINVAL; 15907c478bd9Sstevel@tonic-gate } 15917c478bd9Sstevel@tonic-gate 15927c478bd9Sstevel@tonic-gate if (ret == ENOENT && noentok) 15937c478bd9Sstevel@tonic-gate ret = 0; 15947c478bd9Sstevel@tonic-gate } 15957c478bd9Sstevel@tonic-gate va_end(ap); 15967c478bd9Sstevel@tonic-gate 15977c478bd9Sstevel@tonic-gate return (ret); 15987c478bd9Sstevel@tonic-gate } 15997c478bd9Sstevel@tonic-gate 1600602ca9eaScth /* 1601602ca9eaScth * Find the 'name'ed nvpair in the nvlist 'nvl'. If 'name' found, the function 1602602ca9eaScth * returns zero and a pointer to the matching nvpair is returned in '*ret' 1603602ca9eaScth * (given 'ret' is non-NULL). If 'sep' is specified then 'name' will penitrate 1604602ca9eaScth * multiple levels of embedded nvlists, with 'sep' as the separator. As an 1605602ca9eaScth * example, if sep is '.', name might look like: "a" or "a.b" or "a.c[3]" or 1606602ca9eaScth * "a.d[3].e[1]". This matches the C syntax for array embed (for convience, 1607602ca9eaScth * code also supports "a.d[3]e[1]" syntax). 1608602ca9eaScth * 1609602ca9eaScth * If 'ip' is non-NULL and the last name component is an array, return the 1610602ca9eaScth * value of the "...[index]" array index in *ip. For an array reference that 1611602ca9eaScth * is not indexed, *ip will be returned as -1. If there is a syntax error in 1612602ca9eaScth * 'name', and 'ep' is non-NULL then *ep will be set to point to the location 1613602ca9eaScth * inside the 'name' string where the syntax error was detected. 1614602ca9eaScth */ 1615602ca9eaScth static int 1616602ca9eaScth nvlist_lookup_nvpair_ei_sep(nvlist_t *nvl, const char *name, const char sep, 1617602ca9eaScth nvpair_t **ret, int *ip, char **ep) 1618602ca9eaScth { 1619602ca9eaScth nvpair_t *nvp; 1620602ca9eaScth const char *np; 1621602ca9eaScth char *sepp; 1622602ca9eaScth char *idxp, *idxep; 1623602ca9eaScth nvlist_t **nva; 1624602ca9eaScth long idx; 1625602ca9eaScth int n; 1626602ca9eaScth 1627602ca9eaScth if (ip) 1628602ca9eaScth *ip = -1; /* not indexed */ 1629602ca9eaScth if (ep) 1630602ca9eaScth *ep = NULL; 1631602ca9eaScth 1632602ca9eaScth if ((nvl == NULL) || (name == NULL)) 16331af98250Seschrock return (EINVAL); 16341af98250Seschrock 1635759e89beSSteve Dougherty sepp = NULL; 1636759e89beSSteve Dougherty idx = 0; 1637602ca9eaScth /* step through components of name */ 1638602ca9eaScth for (np = name; np && *np; np = sepp) { 1639602ca9eaScth /* ensure unique names */ 1640602ca9eaScth if (!(nvl->nvl_nvflag & NV_UNIQUE_NAME)) 1641602ca9eaScth return (ENOTSUP); 16421af98250Seschrock 1643602ca9eaScth /* skip white space */ 1644602ca9eaScth skip_whitespace(np); 1645602ca9eaScth if (*np == 0) 1646602ca9eaScth break; 16471af98250Seschrock 1648602ca9eaScth /* set 'sepp' to end of current component 'np' */ 1649602ca9eaScth if (sep) 1650602ca9eaScth sepp = strchr(np, sep); 1651602ca9eaScth else 1652602ca9eaScth sepp = NULL; 1653602ca9eaScth 1654602ca9eaScth /* find start of next "[ index ]..." */ 1655602ca9eaScth idxp = strchr(np, '['); 1656602ca9eaScth 1657602ca9eaScth /* if sepp comes first, set idxp to NULL */ 1658602ca9eaScth if (sepp && idxp && (sepp < idxp)) 1659602ca9eaScth idxp = NULL; 1660602ca9eaScth 1661602ca9eaScth /* 1662602ca9eaScth * At this point 'idxp' is set if there is an index 1663602ca9eaScth * expected for the current component. 1664602ca9eaScth */ 1665602ca9eaScth if (idxp) { 1666602ca9eaScth /* set 'n' to length of current 'np' name component */ 1667602ca9eaScth n = idxp++ - np; 1668602ca9eaScth 1669602ca9eaScth /* keep sepp up to date for *ep use as we advance */ 1670602ca9eaScth skip_whitespace(idxp); 1671602ca9eaScth sepp = idxp; 1672602ca9eaScth 1673602ca9eaScth /* determine the index value */ 1674602ca9eaScth #if defined(_KERNEL) && !defined(_BOOT) 1675602ca9eaScth if (ddi_strtol(idxp, &idxep, 0, &idx)) 1676602ca9eaScth goto fail; 1677602ca9eaScth #else 1678602ca9eaScth idx = strtol(idxp, &idxep, 0); 1679602ca9eaScth #endif 1680602ca9eaScth if (idxep == idxp) 1681602ca9eaScth goto fail; 1682602ca9eaScth 1683602ca9eaScth /* keep sepp up to date for *ep use as we advance */ 1684602ca9eaScth sepp = idxep; 1685602ca9eaScth 1686602ca9eaScth /* skip white space index value and check for ']' */ 1687602ca9eaScth skip_whitespace(sepp); 1688602ca9eaScth if (*sepp++ != ']') 1689602ca9eaScth goto fail; 1690602ca9eaScth 1691602ca9eaScth /* for embedded arrays, support C syntax: "a[1].b" */ 1692602ca9eaScth skip_whitespace(sepp); 1693602ca9eaScth if (sep && (*sepp == sep)) 1694602ca9eaScth sepp++; 1695602ca9eaScth } else if (sepp) { 1696602ca9eaScth n = sepp++ - np; 1697602ca9eaScth } else { 1698602ca9eaScth n = strlen(np); 1699602ca9eaScth } 1700602ca9eaScth 1701602ca9eaScth /* trim trailing whitespace by reducing length of 'np' */ 1702602ca9eaScth if (n == 0) 1703602ca9eaScth goto fail; 1704602ca9eaScth for (n--; (np[n] == ' ') || (np[n] == '\t'); n--) 1705602ca9eaScth ; 1706602ca9eaScth n++; 1707602ca9eaScth 1708602ca9eaScth /* skip whitespace, and set sepp to NULL if complete */ 1709602ca9eaScth if (sepp) { 1710602ca9eaScth skip_whitespace(sepp); 1711602ca9eaScth if (*sepp == 0) 1712602ca9eaScth sepp = NULL; 1713602ca9eaScth } 1714602ca9eaScth 1715602ca9eaScth /* 1716602ca9eaScth * At this point: 1717602ca9eaScth * o 'n' is the length of current 'np' component. 1718602ca9eaScth * o 'idxp' is set if there was an index, and value 'idx'. 1719602ca9eaScth * o 'sepp' is set to the beginning of the next component, 1720602ca9eaScth * and set to NULL if we have no more components. 1721602ca9eaScth * 1722602ca9eaScth * Search for nvpair with matching component name. 1723602ca9eaScth */ 1724602ca9eaScth for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 1725602ca9eaScth nvp = nvlist_next_nvpair(nvl, nvp)) { 1726602ca9eaScth 1727602ca9eaScth /* continue if no match on name */ 1728602ca9eaScth if (strncmp(np, nvpair_name(nvp), n) || 1729602ca9eaScth (strlen(nvpair_name(nvp)) != n)) 1730602ca9eaScth continue; 1731602ca9eaScth 1732602ca9eaScth /* if indexed, verify type is array oriented */ 1733602ca9eaScth if (idxp && !nvpair_type_is_array(nvp)) 1734602ca9eaScth goto fail; 1735602ca9eaScth 1736602ca9eaScth /* 1737602ca9eaScth * Full match found, return nvp and idx if this 1738602ca9eaScth * was the last component. 1739602ca9eaScth */ 1740602ca9eaScth if (sepp == NULL) { 1741602ca9eaScth if (ret) 1742602ca9eaScth *ret = nvp; 1743602ca9eaScth if (ip && idxp) 1744602ca9eaScth *ip = (int)idx; /* return index */ 1745602ca9eaScth return (0); /* found */ 1746602ca9eaScth } 1747602ca9eaScth 1748602ca9eaScth /* 1749602ca9eaScth * More components: current match must be 1750602ca9eaScth * of DATA_TYPE_NVLIST or DATA_TYPE_NVLIST_ARRAY 1751602ca9eaScth * to support going deeper. 1752602ca9eaScth */ 1753602ca9eaScth if (nvpair_type(nvp) == DATA_TYPE_NVLIST) { 1754602ca9eaScth nvl = EMBEDDED_NVL(nvp); 1755602ca9eaScth break; 1756602ca9eaScth } else if (nvpair_type(nvp) == DATA_TYPE_NVLIST_ARRAY) { 1757602ca9eaScth (void) nvpair_value_nvlist_array(nvp, 1758602ca9eaScth &nva, (uint_t *)&n); 1759602ca9eaScth if ((n < 0) || (idx >= n)) 1760602ca9eaScth goto fail; 1761602ca9eaScth nvl = nva[idx]; 1762602ca9eaScth break; 1763602ca9eaScth } 1764602ca9eaScth 1765602ca9eaScth /* type does not support more levels */ 1766602ca9eaScth goto fail; 17671af98250Seschrock } 1768602ca9eaScth if (nvp == NULL) 1769602ca9eaScth goto fail; /* 'name' not found */ 1770602ca9eaScth 1771602ca9eaScth /* search for match of next component in embedded 'nvl' list */ 17721af98250Seschrock } 17731af98250Seschrock 1774602ca9eaScth fail: if (ep && sepp) 1775602ca9eaScth *ep = sepp; 1776602ca9eaScth return (EINVAL); 1777602ca9eaScth } 1778602ca9eaScth 1779602ca9eaScth /* 1780602ca9eaScth * Return pointer to nvpair with specified 'name'. 1781602ca9eaScth */ 1782602ca9eaScth int 1783602ca9eaScth nvlist_lookup_nvpair(nvlist_t *nvl, const char *name, nvpair_t **ret) 1784602ca9eaScth { 1785602ca9eaScth return (nvlist_lookup_nvpair_ei_sep(nvl, name, 0, ret, NULL, NULL)); 1786602ca9eaScth } 1787602ca9eaScth 1788602ca9eaScth /* 1789602ca9eaScth * Determine if named nvpair exists in nvlist (use embedded separator of '.' 1790602ca9eaScth * and return array index). See nvlist_lookup_nvpair_ei_sep for more detailed 1791602ca9eaScth * description. 1792602ca9eaScth */ 1793602ca9eaScth int nvlist_lookup_nvpair_embedded_index(nvlist_t *nvl, 1794602ca9eaScth const char *name, nvpair_t **ret, int *ip, char **ep) 1795602ca9eaScth { 1796602ca9eaScth return (nvlist_lookup_nvpair_ei_sep(nvl, name, '.', ret, ip, ep)); 17971af98250Seschrock } 17981af98250Seschrock 17991af98250Seschrock boolean_t 18001af98250Seschrock nvlist_exists(nvlist_t *nvl, const char *name) 18011af98250Seschrock { 18021af98250Seschrock nvpriv_t *priv; 18031af98250Seschrock nvpair_t *nvp; 18041af98250Seschrock i_nvp_t *curr; 18051af98250Seschrock 18061af98250Seschrock if (name == NULL || nvl == NULL || 18071af98250Seschrock (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 18081af98250Seschrock return (B_FALSE); 18091af98250Seschrock 18101af98250Seschrock for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) { 18111af98250Seschrock nvp = &curr->nvi_nvp; 18121af98250Seschrock 18131af98250Seschrock if (strcmp(name, NVP_NAME(nvp)) == 0) 18141af98250Seschrock return (B_TRUE); 18151af98250Seschrock } 18161af98250Seschrock 18171af98250Seschrock return (B_FALSE); 18181af98250Seschrock } 18191af98250Seschrock 18207c478bd9Sstevel@tonic-gate int 18217c478bd9Sstevel@tonic-gate nvpair_value_boolean_value(nvpair_t *nvp, boolean_t *val) 18227c478bd9Sstevel@tonic-gate { 18237c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_VALUE, NULL, val)); 18247c478bd9Sstevel@tonic-gate } 18257c478bd9Sstevel@tonic-gate 18267c478bd9Sstevel@tonic-gate int 18277c478bd9Sstevel@tonic-gate nvpair_value_byte(nvpair_t *nvp, uchar_t *val) 18287c478bd9Sstevel@tonic-gate { 18297c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_BYTE, NULL, val)); 18307c478bd9Sstevel@tonic-gate } 18317c478bd9Sstevel@tonic-gate 18327c478bd9Sstevel@tonic-gate int 18337c478bd9Sstevel@tonic-gate nvpair_value_int8(nvpair_t *nvp, int8_t *val) 18347c478bd9Sstevel@tonic-gate { 18357c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_INT8, NULL, val)); 18367c478bd9Sstevel@tonic-gate } 18377c478bd9Sstevel@tonic-gate 18387c478bd9Sstevel@tonic-gate int 18397c478bd9Sstevel@tonic-gate nvpair_value_uint8(nvpair_t *nvp, uint8_t *val) 18407c478bd9Sstevel@tonic-gate { 18417c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_UINT8, NULL, val)); 18427c478bd9Sstevel@tonic-gate } 18437c478bd9Sstevel@tonic-gate 18447c478bd9Sstevel@tonic-gate int 18457c478bd9Sstevel@tonic-gate nvpair_value_int16(nvpair_t *nvp, int16_t *val) 18467c478bd9Sstevel@tonic-gate { 18477c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_INT16, NULL, val)); 18487c478bd9Sstevel@tonic-gate } 18497c478bd9Sstevel@tonic-gate 18507c478bd9Sstevel@tonic-gate int 18517c478bd9Sstevel@tonic-gate nvpair_value_uint16(nvpair_t *nvp, uint16_t *val) 18527c478bd9Sstevel@tonic-gate { 18537c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_UINT16, NULL, val)); 18547c478bd9Sstevel@tonic-gate } 18557c478bd9Sstevel@tonic-gate 18567c478bd9Sstevel@tonic-gate int 18577c478bd9Sstevel@tonic-gate nvpair_value_int32(nvpair_t *nvp, int32_t *val) 18587c478bd9Sstevel@tonic-gate { 18597c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_INT32, NULL, val)); 18607c478bd9Sstevel@tonic-gate } 18617c478bd9Sstevel@tonic-gate 18627c478bd9Sstevel@tonic-gate int 18637c478bd9Sstevel@tonic-gate nvpair_value_uint32(nvpair_t *nvp, uint32_t *val) 18647c478bd9Sstevel@tonic-gate { 18657c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_UINT32, NULL, val)); 18667c478bd9Sstevel@tonic-gate } 18677c478bd9Sstevel@tonic-gate 18687c478bd9Sstevel@tonic-gate int 18697c478bd9Sstevel@tonic-gate nvpair_value_int64(nvpair_t *nvp, int64_t *val) 18707c478bd9Sstevel@tonic-gate { 18717c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_INT64, NULL, val)); 18727c478bd9Sstevel@tonic-gate } 18737c478bd9Sstevel@tonic-gate 18747c478bd9Sstevel@tonic-gate int 18757c478bd9Sstevel@tonic-gate nvpair_value_uint64(nvpair_t *nvp, uint64_t *val) 18767c478bd9Sstevel@tonic-gate { 18777c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_UINT64, NULL, val)); 18787c478bd9Sstevel@tonic-gate } 18797c478bd9Sstevel@tonic-gate 1880825ba0f2Srobj #if !defined(_KERNEL) 1881825ba0f2Srobj int 1882825ba0f2Srobj nvpair_value_double(nvpair_t *nvp, double *val) 1883825ba0f2Srobj { 1884825ba0f2Srobj return (nvpair_value_common(nvp, DATA_TYPE_DOUBLE, NULL, val)); 1885825ba0f2Srobj } 1886825ba0f2Srobj #endif 1887825ba0f2Srobj 18887c478bd9Sstevel@tonic-gate int 18897c478bd9Sstevel@tonic-gate nvpair_value_string(nvpair_t *nvp, char **val) 18907c478bd9Sstevel@tonic-gate { 18917c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_STRING, NULL, val)); 18927c478bd9Sstevel@tonic-gate } 18937c478bd9Sstevel@tonic-gate 18947c478bd9Sstevel@tonic-gate int 18957c478bd9Sstevel@tonic-gate nvpair_value_nvlist(nvpair_t *nvp, nvlist_t **val) 18967c478bd9Sstevel@tonic-gate { 18977c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_NVLIST, NULL, val)); 18987c478bd9Sstevel@tonic-gate } 18997c478bd9Sstevel@tonic-gate 19007c478bd9Sstevel@tonic-gate int 19017c478bd9Sstevel@tonic-gate nvpair_value_boolean_array(nvpair_t *nvp, boolean_t **val, uint_t *nelem) 19027c478bd9Sstevel@tonic-gate { 19037c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_ARRAY, nelem, val)); 19047c478bd9Sstevel@tonic-gate } 19057c478bd9Sstevel@tonic-gate 19067c478bd9Sstevel@tonic-gate int 19077c478bd9Sstevel@tonic-gate nvpair_value_byte_array(nvpair_t *nvp, uchar_t **val, uint_t *nelem) 19087c478bd9Sstevel@tonic-gate { 19097c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_BYTE_ARRAY, nelem, val)); 19107c478bd9Sstevel@tonic-gate } 19117c478bd9Sstevel@tonic-gate 19127c478bd9Sstevel@tonic-gate int 19137c478bd9Sstevel@tonic-gate nvpair_value_int8_array(nvpair_t *nvp, int8_t **val, uint_t *nelem) 19147c478bd9Sstevel@tonic-gate { 19157c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_INT8_ARRAY, nelem, val)); 19167c478bd9Sstevel@tonic-gate } 19177c478bd9Sstevel@tonic-gate 19187c478bd9Sstevel@tonic-gate int 19197c478bd9Sstevel@tonic-gate nvpair_value_uint8_array(nvpair_t *nvp, uint8_t **val, uint_t *nelem) 19207c478bd9Sstevel@tonic-gate { 19217c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_UINT8_ARRAY, nelem, val)); 19227c478bd9Sstevel@tonic-gate } 19237c478bd9Sstevel@tonic-gate 19247c478bd9Sstevel@tonic-gate int 19257c478bd9Sstevel@tonic-gate nvpair_value_int16_array(nvpair_t *nvp, int16_t **val, uint_t *nelem) 19267c478bd9Sstevel@tonic-gate { 19277c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_INT16_ARRAY, nelem, val)); 19287c478bd9Sstevel@tonic-gate } 19297c478bd9Sstevel@tonic-gate 19307c478bd9Sstevel@tonic-gate int 19317c478bd9Sstevel@tonic-gate nvpair_value_uint16_array(nvpair_t *nvp, uint16_t **val, uint_t *nelem) 19327c478bd9Sstevel@tonic-gate { 19337c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_UINT16_ARRAY, nelem, val)); 19347c478bd9Sstevel@tonic-gate } 19357c478bd9Sstevel@tonic-gate 19367c478bd9Sstevel@tonic-gate int 19377c478bd9Sstevel@tonic-gate nvpair_value_int32_array(nvpair_t *nvp, int32_t **val, uint_t *nelem) 19387c478bd9Sstevel@tonic-gate { 19397c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_INT32_ARRAY, nelem, val)); 19407c478bd9Sstevel@tonic-gate } 19417c478bd9Sstevel@tonic-gate 19427c478bd9Sstevel@tonic-gate int 19437c478bd9Sstevel@tonic-gate nvpair_value_uint32_array(nvpair_t *nvp, uint32_t **val, uint_t *nelem) 19447c478bd9Sstevel@tonic-gate { 19457c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_UINT32_ARRAY, nelem, val)); 19467c478bd9Sstevel@tonic-gate } 19477c478bd9Sstevel@tonic-gate 19487c478bd9Sstevel@tonic-gate int 19497c478bd9Sstevel@tonic-gate nvpair_value_int64_array(nvpair_t *nvp, int64_t **val, uint_t *nelem) 19507c478bd9Sstevel@tonic-gate { 19517c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_INT64_ARRAY, nelem, val)); 19527c478bd9Sstevel@tonic-gate } 19537c478bd9Sstevel@tonic-gate 19547c478bd9Sstevel@tonic-gate int 19557c478bd9Sstevel@tonic-gate nvpair_value_uint64_array(nvpair_t *nvp, uint64_t **val, uint_t *nelem) 19567c478bd9Sstevel@tonic-gate { 19577c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_UINT64_ARRAY, nelem, val)); 19587c478bd9Sstevel@tonic-gate } 19597c478bd9Sstevel@tonic-gate 19607c478bd9Sstevel@tonic-gate int 19617c478bd9Sstevel@tonic-gate nvpair_value_string_array(nvpair_t *nvp, char ***val, uint_t *nelem) 19627c478bd9Sstevel@tonic-gate { 19637c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_STRING_ARRAY, nelem, val)); 19647c478bd9Sstevel@tonic-gate } 19657c478bd9Sstevel@tonic-gate 19667c478bd9Sstevel@tonic-gate int 19677c478bd9Sstevel@tonic-gate nvpair_value_nvlist_array(nvpair_t *nvp, nvlist_t ***val, uint_t *nelem) 19687c478bd9Sstevel@tonic-gate { 19697c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_NVLIST_ARRAY, nelem, val)); 19707c478bd9Sstevel@tonic-gate } 19717c478bd9Sstevel@tonic-gate 19727c478bd9Sstevel@tonic-gate int 19737c478bd9Sstevel@tonic-gate nvpair_value_hrtime(nvpair_t *nvp, hrtime_t *val) 19747c478bd9Sstevel@tonic-gate { 19757c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_HRTIME, NULL, val)); 19767c478bd9Sstevel@tonic-gate } 19777c478bd9Sstevel@tonic-gate 19787c478bd9Sstevel@tonic-gate /* 19797c478bd9Sstevel@tonic-gate * Add specified pair to the list. 19807c478bd9Sstevel@tonic-gate */ 19817c478bd9Sstevel@tonic-gate int 19827c478bd9Sstevel@tonic-gate nvlist_add_nvpair(nvlist_t *nvl, nvpair_t *nvp) 19837c478bd9Sstevel@tonic-gate { 19847c478bd9Sstevel@tonic-gate if (nvl == NULL || nvp == NULL) 19857c478bd9Sstevel@tonic-gate return (EINVAL); 19867c478bd9Sstevel@tonic-gate 19877c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, NVP_NAME(nvp), NVP_TYPE(nvp), 19887c478bd9Sstevel@tonic-gate NVP_NELEM(nvp), NVP_VALUE(nvp))); 19897c478bd9Sstevel@tonic-gate } 19907c478bd9Sstevel@tonic-gate 19917c478bd9Sstevel@tonic-gate /* 19927c478bd9Sstevel@tonic-gate * Merge the supplied nvlists and put the result in dst. 19937c478bd9Sstevel@tonic-gate * The merged list will contain all names specified in both lists, 19947c478bd9Sstevel@tonic-gate * the values are taken from nvl in the case of duplicates. 19957c478bd9Sstevel@tonic-gate * Return 0 on success. 19967c478bd9Sstevel@tonic-gate */ 19977c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 19987c478bd9Sstevel@tonic-gate int 19997c478bd9Sstevel@tonic-gate nvlist_merge(nvlist_t *dst, nvlist_t *nvl, int flag) 20007c478bd9Sstevel@tonic-gate { 20017c478bd9Sstevel@tonic-gate if (nvl == NULL || dst == NULL) 20027c478bd9Sstevel@tonic-gate return (EINVAL); 20037c478bd9Sstevel@tonic-gate 20047c478bd9Sstevel@tonic-gate if (dst != nvl) 20057c478bd9Sstevel@tonic-gate return (nvlist_copy_pairs(nvl, dst)); 20067c478bd9Sstevel@tonic-gate 20077c478bd9Sstevel@tonic-gate return (0); 20087c478bd9Sstevel@tonic-gate } 20097c478bd9Sstevel@tonic-gate 20107c478bd9Sstevel@tonic-gate /* 20117c478bd9Sstevel@tonic-gate * Encoding related routines 20127c478bd9Sstevel@tonic-gate */ 20137c478bd9Sstevel@tonic-gate #define NVS_OP_ENCODE 0 20147c478bd9Sstevel@tonic-gate #define NVS_OP_DECODE 1 20157c478bd9Sstevel@tonic-gate #define NVS_OP_GETSIZE 2 20167c478bd9Sstevel@tonic-gate 20177c478bd9Sstevel@tonic-gate typedef struct nvs_ops nvs_ops_t; 20187c478bd9Sstevel@tonic-gate 20197c478bd9Sstevel@tonic-gate typedef struct { 20207c478bd9Sstevel@tonic-gate int nvs_op; 20217c478bd9Sstevel@tonic-gate const nvs_ops_t *nvs_ops; 20227c478bd9Sstevel@tonic-gate void *nvs_private; 20237c478bd9Sstevel@tonic-gate nvpriv_t *nvs_priv; 20249ca527c3SMatthew Ahrens int nvs_recursion; 20257c478bd9Sstevel@tonic-gate } nvstream_t; 20267c478bd9Sstevel@tonic-gate 20277c478bd9Sstevel@tonic-gate /* 20287c478bd9Sstevel@tonic-gate * nvs operations are: 20297c478bd9Sstevel@tonic-gate * - nvs_nvlist 20307c478bd9Sstevel@tonic-gate * encoding / decoding of a nvlist header (nvlist_t) 20317c478bd9Sstevel@tonic-gate * calculates the size used for header and end detection 20327c478bd9Sstevel@tonic-gate * 20337c478bd9Sstevel@tonic-gate * - nvs_nvpair 20347c478bd9Sstevel@tonic-gate * responsible for the first part of encoding / decoding of an nvpair 20357c478bd9Sstevel@tonic-gate * calculates the decoded size of an nvpair 20367c478bd9Sstevel@tonic-gate * 20377c478bd9Sstevel@tonic-gate * - nvs_nvp_op 20387c478bd9Sstevel@tonic-gate * second part of encoding / decoding of an nvpair 20397c478bd9Sstevel@tonic-gate * 20407c478bd9Sstevel@tonic-gate * - nvs_nvp_size 20417c478bd9Sstevel@tonic-gate * calculates the encoding size of an nvpair 20427c478bd9Sstevel@tonic-gate * 20437c478bd9Sstevel@tonic-gate * - nvs_nvl_fini 20447c478bd9Sstevel@tonic-gate * encodes the end detection mark (zeros). 20457c478bd9Sstevel@tonic-gate */ 20467c478bd9Sstevel@tonic-gate struct nvs_ops { 20477c478bd9Sstevel@tonic-gate int (*nvs_nvlist)(nvstream_t *, nvlist_t *, size_t *); 20487c478bd9Sstevel@tonic-gate int (*nvs_nvpair)(nvstream_t *, nvpair_t *, size_t *); 20497c478bd9Sstevel@tonic-gate int (*nvs_nvp_op)(nvstream_t *, nvpair_t *); 20507c478bd9Sstevel@tonic-gate int (*nvs_nvp_size)(nvstream_t *, nvpair_t *, size_t *); 20517c478bd9Sstevel@tonic-gate int (*nvs_nvl_fini)(nvstream_t *); 20527c478bd9Sstevel@tonic-gate }; 20537c478bd9Sstevel@tonic-gate 20547c478bd9Sstevel@tonic-gate typedef struct { 20557c478bd9Sstevel@tonic-gate char nvh_encoding; /* nvs encoding method */ 20567c478bd9Sstevel@tonic-gate char nvh_endian; /* nvs endian */ 20577c478bd9Sstevel@tonic-gate char nvh_reserved1; /* reserved for future use */ 20587c478bd9Sstevel@tonic-gate char nvh_reserved2; /* reserved for future use */ 20597c478bd9Sstevel@tonic-gate } nvs_header_t; 20607c478bd9Sstevel@tonic-gate 20617c478bd9Sstevel@tonic-gate static int 20627c478bd9Sstevel@tonic-gate nvs_encode_pairs(nvstream_t *nvs, nvlist_t *nvl) 20637c478bd9Sstevel@tonic-gate { 20647c478bd9Sstevel@tonic-gate nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 20657c478bd9Sstevel@tonic-gate i_nvp_t *curr; 20667c478bd9Sstevel@tonic-gate 20677c478bd9Sstevel@tonic-gate /* 20687c478bd9Sstevel@tonic-gate * Walk nvpair in list and encode each nvpair 20697c478bd9Sstevel@tonic-gate */ 20707c478bd9Sstevel@tonic-gate for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) 20717c478bd9Sstevel@tonic-gate if (nvs->nvs_ops->nvs_nvpair(nvs, &curr->nvi_nvp, NULL) != 0) 20727c478bd9Sstevel@tonic-gate return (EFAULT); 20737c478bd9Sstevel@tonic-gate 20747c478bd9Sstevel@tonic-gate return (nvs->nvs_ops->nvs_nvl_fini(nvs)); 20757c478bd9Sstevel@tonic-gate } 20767c478bd9Sstevel@tonic-gate 20777c478bd9Sstevel@tonic-gate static int 20787c478bd9Sstevel@tonic-gate nvs_decode_pairs(nvstream_t *nvs, nvlist_t *nvl) 20797c478bd9Sstevel@tonic-gate { 20807c478bd9Sstevel@tonic-gate nvpair_t *nvp; 20817c478bd9Sstevel@tonic-gate size_t nvsize; 20827c478bd9Sstevel@tonic-gate int err; 20837c478bd9Sstevel@tonic-gate 20847c478bd9Sstevel@tonic-gate /* 20857c478bd9Sstevel@tonic-gate * Get decoded size of next pair in stream, alloc 20867c478bd9Sstevel@tonic-gate * memory for nvpair_t, then decode the nvpair 20877c478bd9Sstevel@tonic-gate */ 20887c478bd9Sstevel@tonic-gate while ((err = nvs->nvs_ops->nvs_nvpair(nvs, NULL, &nvsize)) == 0) { 20897c478bd9Sstevel@tonic-gate if (nvsize == 0) /* end of list */ 20907c478bd9Sstevel@tonic-gate break; 20917c478bd9Sstevel@tonic-gate 20927c478bd9Sstevel@tonic-gate /* make sure len makes sense */ 20937c478bd9Sstevel@tonic-gate if (nvsize < NVP_SIZE_CALC(1, 0)) 20947c478bd9Sstevel@tonic-gate return (EFAULT); 20957c478bd9Sstevel@tonic-gate 20967c478bd9Sstevel@tonic-gate if ((nvp = nvp_buf_alloc(nvl, nvsize)) == NULL) 20977c478bd9Sstevel@tonic-gate return (ENOMEM); 20987c478bd9Sstevel@tonic-gate 20997c478bd9Sstevel@tonic-gate if ((err = nvs->nvs_ops->nvs_nvp_op(nvs, nvp)) != 0) { 21007c478bd9Sstevel@tonic-gate nvp_buf_free(nvl, nvp); 21017c478bd9Sstevel@tonic-gate return (err); 21027c478bd9Sstevel@tonic-gate } 21037c478bd9Sstevel@tonic-gate 21047c478bd9Sstevel@tonic-gate if (i_validate_nvpair(nvp) != 0) { 21057c478bd9Sstevel@tonic-gate nvpair_free(nvp); 21067c478bd9Sstevel@tonic-gate nvp_buf_free(nvl, nvp); 21077c478bd9Sstevel@tonic-gate return (EFAULT); 21087c478bd9Sstevel@tonic-gate } 21097c478bd9Sstevel@tonic-gate 21107c478bd9Sstevel@tonic-gate nvp_buf_link(nvl, nvp); 21117c478bd9Sstevel@tonic-gate } 21127c478bd9Sstevel@tonic-gate return (err); 21137c478bd9Sstevel@tonic-gate } 21147c478bd9Sstevel@tonic-gate 21157c478bd9Sstevel@tonic-gate static int 21167c478bd9Sstevel@tonic-gate nvs_getsize_pairs(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen) 21177c478bd9Sstevel@tonic-gate { 21187c478bd9Sstevel@tonic-gate nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 21197c478bd9Sstevel@tonic-gate i_nvp_t *curr; 21207c478bd9Sstevel@tonic-gate uint64_t nvsize = *buflen; 21217c478bd9Sstevel@tonic-gate size_t size; 21227c478bd9Sstevel@tonic-gate 21237c478bd9Sstevel@tonic-gate /* 21247c478bd9Sstevel@tonic-gate * Get encoded size of nvpairs in nvlist 21257c478bd9Sstevel@tonic-gate */ 21267c478bd9Sstevel@tonic-gate for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) { 21277c478bd9Sstevel@tonic-gate if (nvs->nvs_ops->nvs_nvp_size(nvs, &curr->nvi_nvp, &size) != 0) 21287c478bd9Sstevel@tonic-gate return (EINVAL); 21297c478bd9Sstevel@tonic-gate 21307c478bd9Sstevel@tonic-gate if ((nvsize += size) > INT32_MAX) 21317c478bd9Sstevel@tonic-gate return (EINVAL); 21327c478bd9Sstevel@tonic-gate } 21337c478bd9Sstevel@tonic-gate 21347c478bd9Sstevel@tonic-gate *buflen = nvsize; 21357c478bd9Sstevel@tonic-gate return (0); 21367c478bd9Sstevel@tonic-gate } 21377c478bd9Sstevel@tonic-gate 21387c478bd9Sstevel@tonic-gate static int 21397c478bd9Sstevel@tonic-gate nvs_operation(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen) 21407c478bd9Sstevel@tonic-gate { 21417c478bd9Sstevel@tonic-gate int err; 21427c478bd9Sstevel@tonic-gate 21435ad82045Snd if (nvl->nvl_priv == 0) 21447c478bd9Sstevel@tonic-gate return (EFAULT); 21457c478bd9Sstevel@tonic-gate 21467c478bd9Sstevel@tonic-gate /* 21477c478bd9Sstevel@tonic-gate * Perform the operation, starting with header, then each nvpair 21487c478bd9Sstevel@tonic-gate */ 21497c478bd9Sstevel@tonic-gate if ((err = nvs->nvs_ops->nvs_nvlist(nvs, nvl, buflen)) != 0) 21507c478bd9Sstevel@tonic-gate return (err); 21517c478bd9Sstevel@tonic-gate 21527c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) { 21537c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: 21547c478bd9Sstevel@tonic-gate err = nvs_encode_pairs(nvs, nvl); 21557c478bd9Sstevel@tonic-gate break; 21567c478bd9Sstevel@tonic-gate 21577c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: 21587c478bd9Sstevel@tonic-gate err = nvs_decode_pairs(nvs, nvl); 21597c478bd9Sstevel@tonic-gate break; 21607c478bd9Sstevel@tonic-gate 21617c478bd9Sstevel@tonic-gate case NVS_OP_GETSIZE: 21627c478bd9Sstevel@tonic-gate err = nvs_getsize_pairs(nvs, nvl, buflen); 21637c478bd9Sstevel@tonic-gate break; 21647c478bd9Sstevel@tonic-gate 21657c478bd9Sstevel@tonic-gate default: 21667c478bd9Sstevel@tonic-gate err = EINVAL; 21677c478bd9Sstevel@tonic-gate } 21687c478bd9Sstevel@tonic-gate 21697c478bd9Sstevel@tonic-gate return (err); 21707c478bd9Sstevel@tonic-gate } 21717c478bd9Sstevel@tonic-gate 21727c478bd9Sstevel@tonic-gate static int 21737c478bd9Sstevel@tonic-gate nvs_embedded(nvstream_t *nvs, nvlist_t *embedded) 21747c478bd9Sstevel@tonic-gate { 21757c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) { 21769ca527c3SMatthew Ahrens case NVS_OP_ENCODE: { 21779ca527c3SMatthew Ahrens int err; 21787c478bd9Sstevel@tonic-gate 21799ca527c3SMatthew Ahrens if (nvs->nvs_recursion >= nvpair_max_recursion) 21809ca527c3SMatthew Ahrens return (EINVAL); 21819ca527c3SMatthew Ahrens nvs->nvs_recursion++; 21829ca527c3SMatthew Ahrens err = nvs_operation(nvs, embedded, NULL); 21839ca527c3SMatthew Ahrens nvs->nvs_recursion--; 21849ca527c3SMatthew Ahrens return (err); 21859ca527c3SMatthew Ahrens } 21867c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: { 21877c478bd9Sstevel@tonic-gate nvpriv_t *priv; 21887c478bd9Sstevel@tonic-gate int err; 21897c478bd9Sstevel@tonic-gate 21907c478bd9Sstevel@tonic-gate if (embedded->nvl_version != NV_VERSION) 21917c478bd9Sstevel@tonic-gate return (ENOTSUP); 21927c478bd9Sstevel@tonic-gate 21937c478bd9Sstevel@tonic-gate if ((priv = nv_priv_alloc_embedded(nvs->nvs_priv)) == NULL) 21947c478bd9Sstevel@tonic-gate return (ENOMEM); 21957c478bd9Sstevel@tonic-gate 21967c478bd9Sstevel@tonic-gate nvlist_init(embedded, embedded->nvl_nvflag, priv); 21977c478bd9Sstevel@tonic-gate 2198*843c2111SMatthew Ahrens if (nvs->nvs_recursion >= nvpair_max_recursion) { 2199*843c2111SMatthew Ahrens nvlist_free(embedded); 22009ca527c3SMatthew Ahrens return (EINVAL); 2201*843c2111SMatthew Ahrens } 22029ca527c3SMatthew Ahrens nvs->nvs_recursion++; 22037c478bd9Sstevel@tonic-gate if ((err = nvs_operation(nvs, embedded, NULL)) != 0) 22047c478bd9Sstevel@tonic-gate nvlist_free(embedded); 22059ca527c3SMatthew Ahrens nvs->nvs_recursion--; 22067c478bd9Sstevel@tonic-gate return (err); 22077c478bd9Sstevel@tonic-gate } 22087c478bd9Sstevel@tonic-gate default: 22097c478bd9Sstevel@tonic-gate break; 22107c478bd9Sstevel@tonic-gate } 22117c478bd9Sstevel@tonic-gate 22127c478bd9Sstevel@tonic-gate return (EINVAL); 22137c478bd9Sstevel@tonic-gate } 22147c478bd9Sstevel@tonic-gate 22157c478bd9Sstevel@tonic-gate static int 22167c478bd9Sstevel@tonic-gate nvs_embedded_nvl_array(nvstream_t *nvs, nvpair_t *nvp, size_t *size) 22177c478bd9Sstevel@tonic-gate { 22187c478bd9Sstevel@tonic-gate size_t nelem = NVP_NELEM(nvp); 22197c478bd9Sstevel@tonic-gate nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp); 22207c478bd9Sstevel@tonic-gate int i; 22217c478bd9Sstevel@tonic-gate 22227c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) { 22237c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: 22247c478bd9Sstevel@tonic-gate for (i = 0; i < nelem; i++) 22257c478bd9Sstevel@tonic-gate if (nvs_embedded(nvs, nvlp[i]) != 0) 22267c478bd9Sstevel@tonic-gate return (EFAULT); 22277c478bd9Sstevel@tonic-gate break; 22287c478bd9Sstevel@tonic-gate 22297c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: { 22307c478bd9Sstevel@tonic-gate size_t len = nelem * sizeof (uint64_t); 22317c478bd9Sstevel@tonic-gate nvlist_t *embedded = (nvlist_t *)((uintptr_t)nvlp + len); 22327c478bd9Sstevel@tonic-gate 22337c478bd9Sstevel@tonic-gate bzero(nvlp, len); /* don't trust packed data */ 22347c478bd9Sstevel@tonic-gate for (i = 0; i < nelem; i++) { 22357c478bd9Sstevel@tonic-gate if (nvs_embedded(nvs, embedded) != 0) { 22367c478bd9Sstevel@tonic-gate nvpair_free(nvp); 22377c478bd9Sstevel@tonic-gate return (EFAULT); 22387c478bd9Sstevel@tonic-gate } 22397c478bd9Sstevel@tonic-gate 22407c478bd9Sstevel@tonic-gate nvlp[i] = embedded++; 22417c478bd9Sstevel@tonic-gate } 22427c478bd9Sstevel@tonic-gate break; 22437c478bd9Sstevel@tonic-gate } 22447c478bd9Sstevel@tonic-gate case NVS_OP_GETSIZE: { 22457c478bd9Sstevel@tonic-gate uint64_t nvsize = 0; 22467c478bd9Sstevel@tonic-gate 22477c478bd9Sstevel@tonic-gate for (i = 0; i < nelem; i++) { 22487c478bd9Sstevel@tonic-gate size_t nvp_sz = 0; 22497c478bd9Sstevel@tonic-gate 22507c478bd9Sstevel@tonic-gate if (nvs_operation(nvs, nvlp[i], &nvp_sz) != 0) 22517c478bd9Sstevel@tonic-gate return (EINVAL); 22527c478bd9Sstevel@tonic-gate 22537c478bd9Sstevel@tonic-gate if ((nvsize += nvp_sz) > INT32_MAX) 22547c478bd9Sstevel@tonic-gate return (EINVAL); 22557c478bd9Sstevel@tonic-gate } 22567c478bd9Sstevel@tonic-gate 22577c478bd9Sstevel@tonic-gate *size = nvsize; 22587c478bd9Sstevel@tonic-gate break; 22597c478bd9Sstevel@tonic-gate } 22607c478bd9Sstevel@tonic-gate default: 22617c478bd9Sstevel@tonic-gate return (EINVAL); 22627c478bd9Sstevel@tonic-gate } 22637c478bd9Sstevel@tonic-gate 22647c478bd9Sstevel@tonic-gate return (0); 22657c478bd9Sstevel@tonic-gate } 22667c478bd9Sstevel@tonic-gate 22677c478bd9Sstevel@tonic-gate static int nvs_native(nvstream_t *, nvlist_t *, char *, size_t *); 22687c478bd9Sstevel@tonic-gate static int nvs_xdr(nvstream_t *, nvlist_t *, char *, size_t *); 22697c478bd9Sstevel@tonic-gate 22707c478bd9Sstevel@tonic-gate /* 22717c478bd9Sstevel@tonic-gate * Common routine for nvlist operations: 22727c478bd9Sstevel@tonic-gate * encode, decode, getsize (encoded size). 22737c478bd9Sstevel@tonic-gate */ 22747c478bd9Sstevel@tonic-gate static int 22757c478bd9Sstevel@tonic-gate nvlist_common(nvlist_t *nvl, char *buf, size_t *buflen, int encoding, 22767c478bd9Sstevel@tonic-gate int nvs_op) 22777c478bd9Sstevel@tonic-gate { 22787c478bd9Sstevel@tonic-gate int err = 0; 22797c478bd9Sstevel@tonic-gate nvstream_t nvs; 22807c478bd9Sstevel@tonic-gate int nvl_endian; 22817c478bd9Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN 22827c478bd9Sstevel@tonic-gate int host_endian = 1; 22837c478bd9Sstevel@tonic-gate #else 22847c478bd9Sstevel@tonic-gate int host_endian = 0; 22857c478bd9Sstevel@tonic-gate #endif /* _LITTLE_ENDIAN */ 22867c478bd9Sstevel@tonic-gate nvs_header_t *nvh = (void *)buf; 22877c478bd9Sstevel@tonic-gate 22887c478bd9Sstevel@tonic-gate if (buflen == NULL || nvl == NULL || 22897c478bd9Sstevel@tonic-gate (nvs.nvs_priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 22907c478bd9Sstevel@tonic-gate return (EINVAL); 22917c478bd9Sstevel@tonic-gate 22927c478bd9Sstevel@tonic-gate nvs.nvs_op = nvs_op; 22939ca527c3SMatthew Ahrens nvs.nvs_recursion = 0; 22947c478bd9Sstevel@tonic-gate 22957c478bd9Sstevel@tonic-gate /* 22967c478bd9Sstevel@tonic-gate * For NVS_OP_ENCODE and NVS_OP_DECODE make sure an nvlist and 22977c478bd9Sstevel@tonic-gate * a buffer is allocated. The first 4 bytes in the buffer are 22987c478bd9Sstevel@tonic-gate * used for encoding method and host endian. 22997c478bd9Sstevel@tonic-gate */ 23007c478bd9Sstevel@tonic-gate switch (nvs_op) { 23017c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: 23027c478bd9Sstevel@tonic-gate if (buf == NULL || *buflen < sizeof (nvs_header_t)) 23037c478bd9Sstevel@tonic-gate return (EINVAL); 23047c478bd9Sstevel@tonic-gate 23057c478bd9Sstevel@tonic-gate nvh->nvh_encoding = encoding; 23067c478bd9Sstevel@tonic-gate nvh->nvh_endian = nvl_endian = host_endian; 23077c478bd9Sstevel@tonic-gate nvh->nvh_reserved1 = 0; 23087c478bd9Sstevel@tonic-gate nvh->nvh_reserved2 = 0; 23097c478bd9Sstevel@tonic-gate break; 23107c478bd9Sstevel@tonic-gate 23117c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: 23127c478bd9Sstevel@tonic-gate if (buf == NULL || *buflen < sizeof (nvs_header_t)) 23137c478bd9Sstevel@tonic-gate return (EINVAL); 23147c478bd9Sstevel@tonic-gate 23157c478bd9Sstevel@tonic-gate /* get method of encoding from first byte */ 23167c478bd9Sstevel@tonic-gate encoding = nvh->nvh_encoding; 23177c478bd9Sstevel@tonic-gate nvl_endian = nvh->nvh_endian; 23187c478bd9Sstevel@tonic-gate break; 23197c478bd9Sstevel@tonic-gate 23207c478bd9Sstevel@tonic-gate case NVS_OP_GETSIZE: 23217c478bd9Sstevel@tonic-gate nvl_endian = host_endian; 23227c478bd9Sstevel@tonic-gate 23237c478bd9Sstevel@tonic-gate /* 23247c478bd9Sstevel@tonic-gate * add the size for encoding 23257c478bd9Sstevel@tonic-gate */ 23267c478bd9Sstevel@tonic-gate *buflen = sizeof (nvs_header_t); 23277c478bd9Sstevel@tonic-gate break; 23287c478bd9Sstevel@tonic-gate 23297c478bd9Sstevel@tonic-gate default: 23307c478bd9Sstevel@tonic-gate return (ENOTSUP); 23317c478bd9Sstevel@tonic-gate } 23327c478bd9Sstevel@tonic-gate 23337c478bd9Sstevel@tonic-gate /* 23347c478bd9Sstevel@tonic-gate * Create an nvstream with proper encoding method 23357c478bd9Sstevel@tonic-gate */ 23367c478bd9Sstevel@tonic-gate switch (encoding) { 23377c478bd9Sstevel@tonic-gate case NV_ENCODE_NATIVE: 23387c478bd9Sstevel@tonic-gate /* 23397c478bd9Sstevel@tonic-gate * check endianness, in case we are unpacking 23407c478bd9Sstevel@tonic-gate * from a file 23417c478bd9Sstevel@tonic-gate */ 23427c478bd9Sstevel@tonic-gate if (nvl_endian != host_endian) 23437c478bd9Sstevel@tonic-gate return (ENOTSUP); 23447c478bd9Sstevel@tonic-gate err = nvs_native(&nvs, nvl, buf, buflen); 23457c478bd9Sstevel@tonic-gate break; 23467c478bd9Sstevel@tonic-gate case NV_ENCODE_XDR: 23477c478bd9Sstevel@tonic-gate err = nvs_xdr(&nvs, nvl, buf, buflen); 23487c478bd9Sstevel@tonic-gate break; 23497c478bd9Sstevel@tonic-gate default: 23507c478bd9Sstevel@tonic-gate err = ENOTSUP; 23517c478bd9Sstevel@tonic-gate break; 23527c478bd9Sstevel@tonic-gate } 23537c478bd9Sstevel@tonic-gate 23547c478bd9Sstevel@tonic-gate return (err); 23557c478bd9Sstevel@tonic-gate } 23567c478bd9Sstevel@tonic-gate 23577c478bd9Sstevel@tonic-gate int 23587c478bd9Sstevel@tonic-gate nvlist_size(nvlist_t *nvl, size_t *size, int encoding) 23597c478bd9Sstevel@tonic-gate { 23607c478bd9Sstevel@tonic-gate return (nvlist_common(nvl, NULL, size, encoding, NVS_OP_GETSIZE)); 23617c478bd9Sstevel@tonic-gate } 23627c478bd9Sstevel@tonic-gate 23637c478bd9Sstevel@tonic-gate /* 23647c478bd9Sstevel@tonic-gate * Pack nvlist into contiguous memory 23657c478bd9Sstevel@tonic-gate */ 23667c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 23677c478bd9Sstevel@tonic-gate int 23687c478bd9Sstevel@tonic-gate nvlist_pack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding, 23697c478bd9Sstevel@tonic-gate int kmflag) 23707c478bd9Sstevel@tonic-gate { 23717c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && !defined(_BOOT) 23727c478bd9Sstevel@tonic-gate return (nvlist_xpack(nvl, bufp, buflen, encoding, 23737c478bd9Sstevel@tonic-gate (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep))); 23747c478bd9Sstevel@tonic-gate #else 23757c478bd9Sstevel@tonic-gate return (nvlist_xpack(nvl, bufp, buflen, encoding, nv_alloc_nosleep)); 23767c478bd9Sstevel@tonic-gate #endif 23777c478bd9Sstevel@tonic-gate } 23787c478bd9Sstevel@tonic-gate 23797c478bd9Sstevel@tonic-gate int 23807c478bd9Sstevel@tonic-gate nvlist_xpack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding, 23817c478bd9Sstevel@tonic-gate nv_alloc_t *nva) 23827c478bd9Sstevel@tonic-gate { 23837c478bd9Sstevel@tonic-gate nvpriv_t nvpriv; 23847c478bd9Sstevel@tonic-gate size_t alloc_size; 23857c478bd9Sstevel@tonic-gate char *buf; 23867c478bd9Sstevel@tonic-gate int err; 23877c478bd9Sstevel@tonic-gate 23887c478bd9Sstevel@tonic-gate if (nva == NULL || nvl == NULL || bufp == NULL || buflen == NULL) 23897c478bd9Sstevel@tonic-gate return (EINVAL); 23907c478bd9Sstevel@tonic-gate 23917c478bd9Sstevel@tonic-gate if (*bufp != NULL) 23927c478bd9Sstevel@tonic-gate return (nvlist_common(nvl, *bufp, buflen, encoding, 23937c478bd9Sstevel@tonic-gate NVS_OP_ENCODE)); 23947c478bd9Sstevel@tonic-gate 23957c478bd9Sstevel@tonic-gate /* 23967c478bd9Sstevel@tonic-gate * Here is a difficult situation: 23977c478bd9Sstevel@tonic-gate * 1. The nvlist has fixed allocator properties. 23987c478bd9Sstevel@tonic-gate * All other nvlist routines (like nvlist_add_*, ...) use 23997c478bd9Sstevel@tonic-gate * these properties. 240048bbca81SDaniel Hoffman * 2. When using nvlist_pack() the user can specify their own 24017c478bd9Sstevel@tonic-gate * allocator properties (e.g. by using KM_NOSLEEP). 24027c478bd9Sstevel@tonic-gate * 24037c478bd9Sstevel@tonic-gate * We use the user specified properties (2). A clearer solution 24047c478bd9Sstevel@tonic-gate * will be to remove the kmflag from nvlist_pack(), but we will 24057c478bd9Sstevel@tonic-gate * not change the interface. 24067c478bd9Sstevel@tonic-gate */ 24077c478bd9Sstevel@tonic-gate nv_priv_init(&nvpriv, nva, 0); 24087c478bd9Sstevel@tonic-gate 2409759e89beSSteve Dougherty if ((err = nvlist_size(nvl, &alloc_size, encoding))) 24107c478bd9Sstevel@tonic-gate return (err); 24117c478bd9Sstevel@tonic-gate 24127c478bd9Sstevel@tonic-gate if ((buf = nv_mem_zalloc(&nvpriv, alloc_size)) == NULL) 24137c478bd9Sstevel@tonic-gate return (ENOMEM); 24147c478bd9Sstevel@tonic-gate 24157c478bd9Sstevel@tonic-gate if ((err = nvlist_common(nvl, buf, &alloc_size, encoding, 24167c478bd9Sstevel@tonic-gate NVS_OP_ENCODE)) != 0) { 24177c478bd9Sstevel@tonic-gate nv_mem_free(&nvpriv, buf, alloc_size); 24187c478bd9Sstevel@tonic-gate } else { 24197c478bd9Sstevel@tonic-gate *buflen = alloc_size; 24207c478bd9Sstevel@tonic-gate *bufp = buf; 24217c478bd9Sstevel@tonic-gate } 24227c478bd9Sstevel@tonic-gate 24237c478bd9Sstevel@tonic-gate return (err); 24247c478bd9Sstevel@tonic-gate } 24257c478bd9Sstevel@tonic-gate 24267c478bd9Sstevel@tonic-gate /* 24277c478bd9Sstevel@tonic-gate * Unpack buf into an nvlist_t 24287c478bd9Sstevel@tonic-gate */ 24297c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 24307c478bd9Sstevel@tonic-gate int 24317c478bd9Sstevel@tonic-gate nvlist_unpack(char *buf, size_t buflen, nvlist_t **nvlp, int kmflag) 24327c478bd9Sstevel@tonic-gate { 24337c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && !defined(_BOOT) 24347c478bd9Sstevel@tonic-gate return (nvlist_xunpack(buf, buflen, nvlp, 24357c478bd9Sstevel@tonic-gate (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep))); 24367c478bd9Sstevel@tonic-gate #else 24377c478bd9Sstevel@tonic-gate return (nvlist_xunpack(buf, buflen, nvlp, nv_alloc_nosleep)); 24387c478bd9Sstevel@tonic-gate #endif 24397c478bd9Sstevel@tonic-gate } 24407c478bd9Sstevel@tonic-gate 24417c478bd9Sstevel@tonic-gate int 24427c478bd9Sstevel@tonic-gate nvlist_xunpack(char *buf, size_t buflen, nvlist_t **nvlp, nv_alloc_t *nva) 24437c478bd9Sstevel@tonic-gate { 24447c478bd9Sstevel@tonic-gate nvlist_t *nvl; 24457c478bd9Sstevel@tonic-gate int err; 24467c478bd9Sstevel@tonic-gate 24477c478bd9Sstevel@tonic-gate if (nvlp == NULL) 24487c478bd9Sstevel@tonic-gate return (EINVAL); 24497c478bd9Sstevel@tonic-gate 24507c478bd9Sstevel@tonic-gate if ((err = nvlist_xalloc(&nvl, 0, nva)) != 0) 24517c478bd9Sstevel@tonic-gate return (err); 24527c478bd9Sstevel@tonic-gate 24537c478bd9Sstevel@tonic-gate if ((err = nvlist_common(nvl, buf, &buflen, 0, NVS_OP_DECODE)) != 0) 24547c478bd9Sstevel@tonic-gate nvlist_free(nvl); 24557c478bd9Sstevel@tonic-gate else 24567c478bd9Sstevel@tonic-gate *nvlp = nvl; 24577c478bd9Sstevel@tonic-gate 24587c478bd9Sstevel@tonic-gate return (err); 24597c478bd9Sstevel@tonic-gate } 24607c478bd9Sstevel@tonic-gate 24617c478bd9Sstevel@tonic-gate /* 24627c478bd9Sstevel@tonic-gate * Native encoding functions 24637c478bd9Sstevel@tonic-gate */ 24647c478bd9Sstevel@tonic-gate typedef struct { 24657c478bd9Sstevel@tonic-gate /* 24667c478bd9Sstevel@tonic-gate * This structure is used when decoding a packed nvpair in 24677c478bd9Sstevel@tonic-gate * the native format. n_base points to a buffer containing the 24687c478bd9Sstevel@tonic-gate * packed nvpair. n_end is a pointer to the end of the buffer. 24697c478bd9Sstevel@tonic-gate * (n_end actually points to the first byte past the end of the 24707c478bd9Sstevel@tonic-gate * buffer.) n_curr is a pointer that lies between n_base and n_end. 24717c478bd9Sstevel@tonic-gate * It points to the current data that we are decoding. 24727c478bd9Sstevel@tonic-gate * The amount of data left in the buffer is equal to n_end - n_curr. 24737c478bd9Sstevel@tonic-gate * n_flag is used to recognize a packed embedded list. 24747c478bd9Sstevel@tonic-gate */ 24757c478bd9Sstevel@tonic-gate caddr_t n_base; 24767c478bd9Sstevel@tonic-gate caddr_t n_end; 24777c478bd9Sstevel@tonic-gate caddr_t n_curr; 24787c478bd9Sstevel@tonic-gate uint_t n_flag; 24797c478bd9Sstevel@tonic-gate } nvs_native_t; 24807c478bd9Sstevel@tonic-gate 24817c478bd9Sstevel@tonic-gate static int 24827c478bd9Sstevel@tonic-gate nvs_native_create(nvstream_t *nvs, nvs_native_t *native, char *buf, 24837c478bd9Sstevel@tonic-gate size_t buflen) 24847c478bd9Sstevel@tonic-gate { 24857c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) { 24867c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: 24877c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: 24887c478bd9Sstevel@tonic-gate nvs->nvs_private = native; 24897c478bd9Sstevel@tonic-gate native->n_curr = native->n_base = buf; 24907c478bd9Sstevel@tonic-gate native->n_end = buf + buflen; 24917c478bd9Sstevel@tonic-gate native->n_flag = 0; 24927c478bd9Sstevel@tonic-gate return (0); 24937c478bd9Sstevel@tonic-gate 24947c478bd9Sstevel@tonic-gate case NVS_OP_GETSIZE: 24957c478bd9Sstevel@tonic-gate nvs->nvs_private = native; 24967c478bd9Sstevel@tonic-gate native->n_curr = native->n_base = native->n_end = NULL; 24977c478bd9Sstevel@tonic-gate native->n_flag = 0; 24987c478bd9Sstevel@tonic-gate return (0); 24997c478bd9Sstevel@tonic-gate default: 25007c478bd9Sstevel@tonic-gate return (EINVAL); 25017c478bd9Sstevel@tonic-gate } 25027c478bd9Sstevel@tonic-gate } 25037c478bd9Sstevel@tonic-gate 25047c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 25057c478bd9Sstevel@tonic-gate static void 25067c478bd9Sstevel@tonic-gate nvs_native_destroy(nvstream_t *nvs) 25077c478bd9Sstevel@tonic-gate { 25087c478bd9Sstevel@tonic-gate } 25097c478bd9Sstevel@tonic-gate 25107c478bd9Sstevel@tonic-gate static int 25117c478bd9Sstevel@tonic-gate native_cp(nvstream_t *nvs, void *buf, size_t size) 25127c478bd9Sstevel@tonic-gate { 25137c478bd9Sstevel@tonic-gate nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 25147c478bd9Sstevel@tonic-gate 25157c478bd9Sstevel@tonic-gate if (native->n_curr + size > native->n_end) 25167c478bd9Sstevel@tonic-gate return (EFAULT); 25177c478bd9Sstevel@tonic-gate 25187c478bd9Sstevel@tonic-gate /* 25197c478bd9Sstevel@tonic-gate * The bcopy() below eliminates alignment requirement 25207c478bd9Sstevel@tonic-gate * on the buffer (stream) and is preferred over direct access. 25217c478bd9Sstevel@tonic-gate */ 25227c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) { 25237c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: 25247c478bd9Sstevel@tonic-gate bcopy(buf, native->n_curr, size); 25257c478bd9Sstevel@tonic-gate break; 25267c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: 25277c478bd9Sstevel@tonic-gate bcopy(native->n_curr, buf, size); 25287c478bd9Sstevel@tonic-gate break; 25297c478bd9Sstevel@tonic-gate default: 25307c478bd9Sstevel@tonic-gate return (EINVAL); 25317c478bd9Sstevel@tonic-gate } 25327c478bd9Sstevel@tonic-gate 25337c478bd9Sstevel@tonic-gate native->n_curr += size; 25347c478bd9Sstevel@tonic-gate return (0); 25357c478bd9Sstevel@tonic-gate } 25367c478bd9Sstevel@tonic-gate 25377c478bd9Sstevel@tonic-gate /* 25387c478bd9Sstevel@tonic-gate * operate on nvlist_t header 25397c478bd9Sstevel@tonic-gate */ 25407c478bd9Sstevel@tonic-gate static int 25417c478bd9Sstevel@tonic-gate nvs_native_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size) 25427c478bd9Sstevel@tonic-gate { 25437c478bd9Sstevel@tonic-gate nvs_native_t *native = nvs->nvs_private; 25447c478bd9Sstevel@tonic-gate 25457c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) { 25467c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: 25477c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: 25487c478bd9Sstevel@tonic-gate if (native->n_flag) 25497c478bd9Sstevel@tonic-gate return (0); /* packed embedded list */ 25507c478bd9Sstevel@tonic-gate 25517c478bd9Sstevel@tonic-gate native->n_flag = 1; 25527c478bd9Sstevel@tonic-gate 25537c478bd9Sstevel@tonic-gate /* copy version and nvflag of the nvlist_t */ 25547c478bd9Sstevel@tonic-gate if (native_cp(nvs, &nvl->nvl_version, sizeof (int32_t)) != 0 || 25557c478bd9Sstevel@tonic-gate native_cp(nvs, &nvl->nvl_nvflag, sizeof (int32_t)) != 0) 25567c478bd9Sstevel@tonic-gate return (EFAULT); 25577c478bd9Sstevel@tonic-gate 25587c478bd9Sstevel@tonic-gate return (0); 25597c478bd9Sstevel@tonic-gate 25607c478bd9Sstevel@tonic-gate case NVS_OP_GETSIZE: 25617c478bd9Sstevel@tonic-gate /* 25627c478bd9Sstevel@tonic-gate * if calculate for packed embedded list 25637c478bd9Sstevel@tonic-gate * 4 for end of the embedded list 25647c478bd9Sstevel@tonic-gate * else 25657c478bd9Sstevel@tonic-gate * 2 * sizeof (int32_t) for nvl_version and nvl_nvflag 25667c478bd9Sstevel@tonic-gate * and 4 for end of the entire list 25677c478bd9Sstevel@tonic-gate */ 25687c478bd9Sstevel@tonic-gate if (native->n_flag) { 25697c478bd9Sstevel@tonic-gate *size += 4; 25707c478bd9Sstevel@tonic-gate } else { 25717c478bd9Sstevel@tonic-gate native->n_flag = 1; 25727c478bd9Sstevel@tonic-gate *size += 2 * sizeof (int32_t) + 4; 25737c478bd9Sstevel@tonic-gate } 25747c478bd9Sstevel@tonic-gate 25757c478bd9Sstevel@tonic-gate return (0); 25767c478bd9Sstevel@tonic-gate 25777c478bd9Sstevel@tonic-gate default: 25787c478bd9Sstevel@tonic-gate return (EINVAL); 25797c478bd9Sstevel@tonic-gate } 25807c478bd9Sstevel@tonic-gate } 25817c478bd9Sstevel@tonic-gate 25827c478bd9Sstevel@tonic-gate static int 25837c478bd9Sstevel@tonic-gate nvs_native_nvl_fini(nvstream_t *nvs) 25847c478bd9Sstevel@tonic-gate { 25857c478bd9Sstevel@tonic-gate if (nvs->nvs_op == NVS_OP_ENCODE) { 25867c478bd9Sstevel@tonic-gate nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 25877c478bd9Sstevel@tonic-gate /* 25887c478bd9Sstevel@tonic-gate * Add 4 zero bytes at end of nvlist. They are used 25897c478bd9Sstevel@tonic-gate * for end detection by the decode routine. 25907c478bd9Sstevel@tonic-gate */ 25917c478bd9Sstevel@tonic-gate if (native->n_curr + sizeof (int) > native->n_end) 25927c478bd9Sstevel@tonic-gate return (EFAULT); 25937c478bd9Sstevel@tonic-gate 25947c478bd9Sstevel@tonic-gate bzero(native->n_curr, sizeof (int)); 25957c478bd9Sstevel@tonic-gate native->n_curr += sizeof (int); 25967c478bd9Sstevel@tonic-gate } 25977c478bd9Sstevel@tonic-gate 25987c478bd9Sstevel@tonic-gate return (0); 25997c478bd9Sstevel@tonic-gate } 26007c478bd9Sstevel@tonic-gate 26017c478bd9Sstevel@tonic-gate static int 26027c478bd9Sstevel@tonic-gate nvpair_native_embedded(nvstream_t *nvs, nvpair_t *nvp) 26037c478bd9Sstevel@tonic-gate { 26047c478bd9Sstevel@tonic-gate if (nvs->nvs_op == NVS_OP_ENCODE) { 26057c478bd9Sstevel@tonic-gate nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 26067c478bd9Sstevel@tonic-gate nvlist_t *packed = (void *) 26077c478bd9Sstevel@tonic-gate (native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp)); 26087c478bd9Sstevel@tonic-gate /* 26097c478bd9Sstevel@tonic-gate * Null out the pointer that is meaningless in the packed 26107c478bd9Sstevel@tonic-gate * structure. The address may not be aligned, so we have 26117c478bd9Sstevel@tonic-gate * to use bzero. 26127c478bd9Sstevel@tonic-gate */ 26137c478bd9Sstevel@tonic-gate bzero(&packed->nvl_priv, sizeof (packed->nvl_priv)); 26147c478bd9Sstevel@tonic-gate } 26157c478bd9Sstevel@tonic-gate 26167c478bd9Sstevel@tonic-gate return (nvs_embedded(nvs, EMBEDDED_NVL(nvp))); 26177c478bd9Sstevel@tonic-gate } 26187c478bd9Sstevel@tonic-gate 26197c478bd9Sstevel@tonic-gate static int 26207c478bd9Sstevel@tonic-gate nvpair_native_embedded_array(nvstream_t *nvs, nvpair_t *nvp) 26217c478bd9Sstevel@tonic-gate { 26227c478bd9Sstevel@tonic-gate if (nvs->nvs_op == NVS_OP_ENCODE) { 26237c478bd9Sstevel@tonic-gate nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 26247c478bd9Sstevel@tonic-gate char *value = native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp); 26257c478bd9Sstevel@tonic-gate size_t len = NVP_NELEM(nvp) * sizeof (uint64_t); 26267c478bd9Sstevel@tonic-gate nvlist_t *packed = (nvlist_t *)((uintptr_t)value + len); 26277c478bd9Sstevel@tonic-gate int i; 26287c478bd9Sstevel@tonic-gate /* 26297c478bd9Sstevel@tonic-gate * Null out pointers that are meaningless in the packed 26307c478bd9Sstevel@tonic-gate * structure. The addresses may not be aligned, so we have 26317c478bd9Sstevel@tonic-gate * to use bzero. 26327c478bd9Sstevel@tonic-gate */ 26337c478bd9Sstevel@tonic-gate bzero(value, len); 26347c478bd9Sstevel@tonic-gate 26357c478bd9Sstevel@tonic-gate for (i = 0; i < NVP_NELEM(nvp); i++, packed++) 26367c478bd9Sstevel@tonic-gate /* 26377c478bd9Sstevel@tonic-gate * Null out the pointer that is meaningless in the 26387c478bd9Sstevel@tonic-gate * packed structure. The address may not be aligned, 26397c478bd9Sstevel@tonic-gate * so we have to use bzero. 26407c478bd9Sstevel@tonic-gate */ 26417c478bd9Sstevel@tonic-gate bzero(&packed->nvl_priv, sizeof (packed->nvl_priv)); 26427c478bd9Sstevel@tonic-gate } 26437c478bd9Sstevel@tonic-gate 26447c478bd9Sstevel@tonic-gate return (nvs_embedded_nvl_array(nvs, nvp, NULL)); 26457c478bd9Sstevel@tonic-gate } 26467c478bd9Sstevel@tonic-gate 26477c478bd9Sstevel@tonic-gate static void 26487c478bd9Sstevel@tonic-gate nvpair_native_string_array(nvstream_t *nvs, nvpair_t *nvp) 26497c478bd9Sstevel@tonic-gate { 26507c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) { 26517c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: { 26527c478bd9Sstevel@tonic-gate nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 26537c478bd9Sstevel@tonic-gate uint64_t *strp = (void *) 26547c478bd9Sstevel@tonic-gate (native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp)); 26557c478bd9Sstevel@tonic-gate /* 26567c478bd9Sstevel@tonic-gate * Null out pointers that are meaningless in the packed 26577c478bd9Sstevel@tonic-gate * structure. The addresses may not be aligned, so we have 26587c478bd9Sstevel@tonic-gate * to use bzero. 26597c478bd9Sstevel@tonic-gate */ 26607c478bd9Sstevel@tonic-gate bzero(strp, NVP_NELEM(nvp) * sizeof (uint64_t)); 26617c478bd9Sstevel@tonic-gate break; 26627c478bd9Sstevel@tonic-gate } 26637c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: { 26647c478bd9Sstevel@tonic-gate char **strp = (void *)NVP_VALUE(nvp); 26657c478bd9Sstevel@tonic-gate char *buf = ((char *)strp + NVP_NELEM(nvp) * sizeof (uint64_t)); 26667c478bd9Sstevel@tonic-gate int i; 26677c478bd9Sstevel@tonic-gate 26687c478bd9Sstevel@tonic-gate for (i = 0; i < NVP_NELEM(nvp); i++) { 26697c478bd9Sstevel@tonic-gate strp[i] = buf; 26707c478bd9Sstevel@tonic-gate buf += strlen(buf) + 1; 26717c478bd9Sstevel@tonic-gate } 26727c478bd9Sstevel@tonic-gate break; 26737c478bd9Sstevel@tonic-gate } 26747c478bd9Sstevel@tonic-gate } 26757c478bd9Sstevel@tonic-gate } 26767c478bd9Sstevel@tonic-gate 26777c478bd9Sstevel@tonic-gate static int 26787c478bd9Sstevel@tonic-gate nvs_native_nvp_op(nvstream_t *nvs, nvpair_t *nvp) 26797c478bd9Sstevel@tonic-gate { 26807c478bd9Sstevel@tonic-gate data_type_t type; 26817c478bd9Sstevel@tonic-gate int value_sz; 26827c478bd9Sstevel@tonic-gate int ret = 0; 26837c478bd9Sstevel@tonic-gate 26847c478bd9Sstevel@tonic-gate /* 26857c478bd9Sstevel@tonic-gate * We do the initial bcopy of the data before we look at 26867c478bd9Sstevel@tonic-gate * the nvpair type, because when we're decoding, we won't 26877c478bd9Sstevel@tonic-gate * have the correct values for the pair until we do the bcopy. 26887c478bd9Sstevel@tonic-gate */ 26897c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) { 26907c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: 26917c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: 26927c478bd9Sstevel@tonic-gate if (native_cp(nvs, nvp, nvp->nvp_size) != 0) 26937c478bd9Sstevel@tonic-gate return (EFAULT); 26947c478bd9Sstevel@tonic-gate break; 26957c478bd9Sstevel@tonic-gate default: 26967c478bd9Sstevel@tonic-gate return (EINVAL); 26977c478bd9Sstevel@tonic-gate } 26987c478bd9Sstevel@tonic-gate 26997c478bd9Sstevel@tonic-gate /* verify nvp_name_sz, check the name string length */ 27007c478bd9Sstevel@tonic-gate if (i_validate_nvpair_name(nvp) != 0) 27017c478bd9Sstevel@tonic-gate return (EFAULT); 27027c478bd9Sstevel@tonic-gate 27037c478bd9Sstevel@tonic-gate type = NVP_TYPE(nvp); 27047c478bd9Sstevel@tonic-gate 27057c478bd9Sstevel@tonic-gate /* 27067c478bd9Sstevel@tonic-gate * Verify type and nelem and get the value size. 27077c478bd9Sstevel@tonic-gate * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY 27087c478bd9Sstevel@tonic-gate * is the size of the string(s) excluded. 27097c478bd9Sstevel@tonic-gate */ 27107c478bd9Sstevel@tonic-gate if ((value_sz = i_get_value_size(type, NULL, NVP_NELEM(nvp))) < 0) 27117c478bd9Sstevel@tonic-gate return (EFAULT); 27127c478bd9Sstevel@tonic-gate 27137c478bd9Sstevel@tonic-gate if (NVP_SIZE_CALC(nvp->nvp_name_sz, value_sz) > nvp->nvp_size) 27147c478bd9Sstevel@tonic-gate return (EFAULT); 27157c478bd9Sstevel@tonic-gate 27167c478bd9Sstevel@tonic-gate switch (type) { 27177c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST: 27187c478bd9Sstevel@tonic-gate ret = nvpair_native_embedded(nvs, nvp); 27197c478bd9Sstevel@tonic-gate break; 27207c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: 27217c478bd9Sstevel@tonic-gate ret = nvpair_native_embedded_array(nvs, nvp); 27227c478bd9Sstevel@tonic-gate break; 27237c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY: 27247c478bd9Sstevel@tonic-gate nvpair_native_string_array(nvs, nvp); 27257c478bd9Sstevel@tonic-gate break; 27267c478bd9Sstevel@tonic-gate default: 27277c478bd9Sstevel@tonic-gate break; 27287c478bd9Sstevel@tonic-gate } 27297c478bd9Sstevel@tonic-gate 27307c478bd9Sstevel@tonic-gate return (ret); 27317c478bd9Sstevel@tonic-gate } 27327c478bd9Sstevel@tonic-gate 27337c478bd9Sstevel@tonic-gate static int 27347c478bd9Sstevel@tonic-gate nvs_native_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size) 27357c478bd9Sstevel@tonic-gate { 27367c478bd9Sstevel@tonic-gate uint64_t nvp_sz = nvp->nvp_size; 27377c478bd9Sstevel@tonic-gate 27387c478bd9Sstevel@tonic-gate switch (NVP_TYPE(nvp)) { 27397c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST: { 27407c478bd9Sstevel@tonic-gate size_t nvsize = 0; 27417c478bd9Sstevel@tonic-gate 27427c478bd9Sstevel@tonic-gate if (nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize) != 0) 27437c478bd9Sstevel@tonic-gate return (EINVAL); 27447c478bd9Sstevel@tonic-gate 27457c478bd9Sstevel@tonic-gate nvp_sz += nvsize; 27467c478bd9Sstevel@tonic-gate break; 27477c478bd9Sstevel@tonic-gate } 27487c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: { 27497c478bd9Sstevel@tonic-gate size_t nvsize; 27507c478bd9Sstevel@tonic-gate 27517c478bd9Sstevel@tonic-gate if (nvs_embedded_nvl_array(nvs, nvp, &nvsize) != 0) 27527c478bd9Sstevel@tonic-gate return (EINVAL); 27537c478bd9Sstevel@tonic-gate 27547c478bd9Sstevel@tonic-gate nvp_sz += nvsize; 27557c478bd9Sstevel@tonic-gate break; 27567c478bd9Sstevel@tonic-gate } 27577c478bd9Sstevel@tonic-gate default: 27587c478bd9Sstevel@tonic-gate break; 27597c478bd9Sstevel@tonic-gate } 27607c478bd9Sstevel@tonic-gate 27617c478bd9Sstevel@tonic-gate if (nvp_sz > INT32_MAX) 27627c478bd9Sstevel@tonic-gate return (EINVAL); 27637c478bd9Sstevel@tonic-gate 27647c478bd9Sstevel@tonic-gate *size = nvp_sz; 27657c478bd9Sstevel@tonic-gate 27667c478bd9Sstevel@tonic-gate return (0); 27677c478bd9Sstevel@tonic-gate } 27687c478bd9Sstevel@tonic-gate 27697c478bd9Sstevel@tonic-gate static int 27707c478bd9Sstevel@tonic-gate nvs_native_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size) 27717c478bd9Sstevel@tonic-gate { 27727c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) { 27737c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: 27747c478bd9Sstevel@tonic-gate return (nvs_native_nvp_op(nvs, nvp)); 27757c478bd9Sstevel@tonic-gate 27767c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: { 27777c478bd9Sstevel@tonic-gate nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 27787c478bd9Sstevel@tonic-gate int32_t decode_len; 27797c478bd9Sstevel@tonic-gate 27807c478bd9Sstevel@tonic-gate /* try to read the size value from the stream */ 27817c478bd9Sstevel@tonic-gate if (native->n_curr + sizeof (int32_t) > native->n_end) 27827c478bd9Sstevel@tonic-gate return (EFAULT); 27837c478bd9Sstevel@tonic-gate bcopy(native->n_curr, &decode_len, sizeof (int32_t)); 27847c478bd9Sstevel@tonic-gate 27857c478bd9Sstevel@tonic-gate /* sanity check the size value */ 27867c478bd9Sstevel@tonic-gate if (decode_len < 0 || 27877c478bd9Sstevel@tonic-gate decode_len > native->n_end - native->n_curr) 27887c478bd9Sstevel@tonic-gate return (EFAULT); 27897c478bd9Sstevel@tonic-gate 27907c478bd9Sstevel@tonic-gate *size = decode_len; 27917c478bd9Sstevel@tonic-gate 27927c478bd9Sstevel@tonic-gate /* 27937c478bd9Sstevel@tonic-gate * If at the end of the stream then move the cursor 27947c478bd9Sstevel@tonic-gate * forward, otherwise nvpair_native_op() will read 27957c478bd9Sstevel@tonic-gate * the entire nvpair at the same cursor position. 27967c478bd9Sstevel@tonic-gate */ 27977c478bd9Sstevel@tonic-gate if (*size == 0) 27987c478bd9Sstevel@tonic-gate native->n_curr += sizeof (int32_t); 27997c478bd9Sstevel@tonic-gate break; 28007c478bd9Sstevel@tonic-gate } 28017c478bd9Sstevel@tonic-gate 28027c478bd9Sstevel@tonic-gate default: 28037c478bd9Sstevel@tonic-gate return (EINVAL); 28047c478bd9Sstevel@tonic-gate } 28057c478bd9Sstevel@tonic-gate 28067c478bd9Sstevel@tonic-gate return (0); 28077c478bd9Sstevel@tonic-gate } 28087c478bd9Sstevel@tonic-gate 28097c478bd9Sstevel@tonic-gate static const nvs_ops_t nvs_native_ops = { 28107c478bd9Sstevel@tonic-gate nvs_native_nvlist, 28117c478bd9Sstevel@tonic-gate nvs_native_nvpair, 28127c478bd9Sstevel@tonic-gate nvs_native_nvp_op, 28137c478bd9Sstevel@tonic-gate nvs_native_nvp_size, 28147c478bd9Sstevel@tonic-gate nvs_native_nvl_fini 28157c478bd9Sstevel@tonic-gate }; 28167c478bd9Sstevel@tonic-gate 28177c478bd9Sstevel@tonic-gate static int 28187c478bd9Sstevel@tonic-gate nvs_native(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen) 28197c478bd9Sstevel@tonic-gate { 28207c478bd9Sstevel@tonic-gate nvs_native_t native; 28217c478bd9Sstevel@tonic-gate int err; 28227c478bd9Sstevel@tonic-gate 28237c478bd9Sstevel@tonic-gate nvs->nvs_ops = &nvs_native_ops; 28247c478bd9Sstevel@tonic-gate 28257c478bd9Sstevel@tonic-gate if ((err = nvs_native_create(nvs, &native, buf + sizeof (nvs_header_t), 28267c478bd9Sstevel@tonic-gate *buflen - sizeof (nvs_header_t))) != 0) 28277c478bd9Sstevel@tonic-gate return (err); 28287c478bd9Sstevel@tonic-gate 28297c478bd9Sstevel@tonic-gate err = nvs_operation(nvs, nvl, buflen); 28307c478bd9Sstevel@tonic-gate 28317c478bd9Sstevel@tonic-gate nvs_native_destroy(nvs); 28327c478bd9Sstevel@tonic-gate 28337c478bd9Sstevel@tonic-gate return (err); 28347c478bd9Sstevel@tonic-gate } 28357c478bd9Sstevel@tonic-gate 28367c478bd9Sstevel@tonic-gate /* 28377c478bd9Sstevel@tonic-gate * XDR encoding functions 28387c478bd9Sstevel@tonic-gate * 28397c478bd9Sstevel@tonic-gate * An xdr packed nvlist is encoded as: 28407c478bd9Sstevel@tonic-gate * 28417c478bd9Sstevel@tonic-gate * - encoding methode and host endian (4 bytes) 28427c478bd9Sstevel@tonic-gate * - nvl_version (4 bytes) 28437c478bd9Sstevel@tonic-gate * - nvl_nvflag (4 bytes) 28447c478bd9Sstevel@tonic-gate * 28457c478bd9Sstevel@tonic-gate * - encoded nvpairs, the format of one xdr encoded nvpair is: 28467c478bd9Sstevel@tonic-gate * - encoded size of the nvpair (4 bytes) 28477c478bd9Sstevel@tonic-gate * - decoded size of the nvpair (4 bytes) 28487c478bd9Sstevel@tonic-gate * - name string, (4 + sizeof(NV_ALIGN4(string)) 28497c478bd9Sstevel@tonic-gate * a string is coded as size (4 bytes) and data 28507c478bd9Sstevel@tonic-gate * - data type (4 bytes) 28517c478bd9Sstevel@tonic-gate * - number of elements in the nvpair (4 bytes) 28527c478bd9Sstevel@tonic-gate * - data 28537c478bd9Sstevel@tonic-gate * 28547c478bd9Sstevel@tonic-gate * - 2 zero's for end of the entire list (8 bytes) 28557c478bd9Sstevel@tonic-gate */ 28567c478bd9Sstevel@tonic-gate static int 28577c478bd9Sstevel@tonic-gate nvs_xdr_create(nvstream_t *nvs, XDR *xdr, char *buf, size_t buflen) 28587c478bd9Sstevel@tonic-gate { 28597c478bd9Sstevel@tonic-gate /* xdr data must be 4 byte aligned */ 28607c478bd9Sstevel@tonic-gate if ((ulong_t)buf % 4 != 0) 28617c478bd9Sstevel@tonic-gate return (EFAULT); 28627c478bd9Sstevel@tonic-gate 28637c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) { 28647c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: 28657c478bd9Sstevel@tonic-gate xdrmem_create(xdr, buf, (uint_t)buflen, XDR_ENCODE); 28667c478bd9Sstevel@tonic-gate nvs->nvs_private = xdr; 28677c478bd9Sstevel@tonic-gate return (0); 28687c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: 28697c478bd9Sstevel@tonic-gate xdrmem_create(xdr, buf, (uint_t)buflen, XDR_DECODE); 28707c478bd9Sstevel@tonic-gate nvs->nvs_private = xdr; 28717c478bd9Sstevel@tonic-gate return (0); 28727c478bd9Sstevel@tonic-gate case NVS_OP_GETSIZE: 28737c478bd9Sstevel@tonic-gate nvs->nvs_private = NULL; 28747c478bd9Sstevel@tonic-gate return (0); 28757c478bd9Sstevel@tonic-gate default: 28767c478bd9Sstevel@tonic-gate return (EINVAL); 28777c478bd9Sstevel@tonic-gate } 28787c478bd9Sstevel@tonic-gate } 28797c478bd9Sstevel@tonic-gate 28807c478bd9Sstevel@tonic-gate static void 28817c478bd9Sstevel@tonic-gate nvs_xdr_destroy(nvstream_t *nvs) 28827c478bd9Sstevel@tonic-gate { 28837c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) { 28847c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: 28857c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: 28867c478bd9Sstevel@tonic-gate xdr_destroy((XDR *)nvs->nvs_private); 28877c478bd9Sstevel@tonic-gate break; 28887c478bd9Sstevel@tonic-gate default: 28897c478bd9Sstevel@tonic-gate break; 28907c478bd9Sstevel@tonic-gate } 28917c478bd9Sstevel@tonic-gate } 28927c478bd9Sstevel@tonic-gate 28937c478bd9Sstevel@tonic-gate static int 28947c478bd9Sstevel@tonic-gate nvs_xdr_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size) 28957c478bd9Sstevel@tonic-gate { 28967c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) { 28977c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: 28987c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: { 28997c478bd9Sstevel@tonic-gate XDR *xdr = nvs->nvs_private; 29007c478bd9Sstevel@tonic-gate 29017c478bd9Sstevel@tonic-gate if (!xdr_int(xdr, &nvl->nvl_version) || 29027c478bd9Sstevel@tonic-gate !xdr_u_int(xdr, &nvl->nvl_nvflag)) 29037c478bd9Sstevel@tonic-gate return (EFAULT); 29047c478bd9Sstevel@tonic-gate break; 29057c478bd9Sstevel@tonic-gate } 29067c478bd9Sstevel@tonic-gate case NVS_OP_GETSIZE: { 29077c478bd9Sstevel@tonic-gate /* 29087c478bd9Sstevel@tonic-gate * 2 * 4 for nvl_version + nvl_nvflag 29097c478bd9Sstevel@tonic-gate * and 8 for end of the entire list 29107c478bd9Sstevel@tonic-gate */ 29117c478bd9Sstevel@tonic-gate *size += 2 * 4 + 8; 29127c478bd9Sstevel@tonic-gate break; 29137c478bd9Sstevel@tonic-gate } 29147c478bd9Sstevel@tonic-gate default: 29157c478bd9Sstevel@tonic-gate return (EINVAL); 29167c478bd9Sstevel@tonic-gate } 29177c478bd9Sstevel@tonic-gate return (0); 29187c478bd9Sstevel@tonic-gate } 29197c478bd9Sstevel@tonic-gate 29207c478bd9Sstevel@tonic-gate static int 29217c478bd9Sstevel@tonic-gate nvs_xdr_nvl_fini(nvstream_t *nvs) 29227c478bd9Sstevel@tonic-gate { 29237c478bd9Sstevel@tonic-gate if (nvs->nvs_op == NVS_OP_ENCODE) { 29247c478bd9Sstevel@tonic-gate XDR *xdr = nvs->nvs_private; 29257c478bd9Sstevel@tonic-gate int zero = 0; 29267c478bd9Sstevel@tonic-gate 29277c478bd9Sstevel@tonic-gate if (!xdr_int(xdr, &zero) || !xdr_int(xdr, &zero)) 29287c478bd9Sstevel@tonic-gate return (EFAULT); 29297c478bd9Sstevel@tonic-gate } 29307c478bd9Sstevel@tonic-gate 29317c478bd9Sstevel@tonic-gate return (0); 29327c478bd9Sstevel@tonic-gate } 29337c478bd9Sstevel@tonic-gate 29347c478bd9Sstevel@tonic-gate /* 29357c478bd9Sstevel@tonic-gate * The format of xdr encoded nvpair is: 29367c478bd9Sstevel@tonic-gate * encode_size, decode_size, name string, data type, nelem, data 29377c478bd9Sstevel@tonic-gate */ 29387c478bd9Sstevel@tonic-gate static int 29397c478bd9Sstevel@tonic-gate nvs_xdr_nvp_op(nvstream_t *nvs, nvpair_t *nvp) 29407c478bd9Sstevel@tonic-gate { 29417c478bd9Sstevel@tonic-gate data_type_t type; 29427c478bd9Sstevel@tonic-gate char *buf; 29437c478bd9Sstevel@tonic-gate char *buf_end = (char *)nvp + nvp->nvp_size; 29447c478bd9Sstevel@tonic-gate int value_sz; 29457c478bd9Sstevel@tonic-gate uint_t nelem, buflen; 29467c478bd9Sstevel@tonic-gate bool_t ret = FALSE; 29477c478bd9Sstevel@tonic-gate XDR *xdr = nvs->nvs_private; 29487c478bd9Sstevel@tonic-gate 29497c478bd9Sstevel@tonic-gate ASSERT(xdr != NULL && nvp != NULL); 29507c478bd9Sstevel@tonic-gate 29517c478bd9Sstevel@tonic-gate /* name string */ 29527c478bd9Sstevel@tonic-gate if ((buf = NVP_NAME(nvp)) >= buf_end) 29537c478bd9Sstevel@tonic-gate return (EFAULT); 29547c478bd9Sstevel@tonic-gate buflen = buf_end - buf; 29557c478bd9Sstevel@tonic-gate 29567c478bd9Sstevel@tonic-gate if (!xdr_string(xdr, &buf, buflen - 1)) 29577c478bd9Sstevel@tonic-gate return (EFAULT); 29587c478bd9Sstevel@tonic-gate nvp->nvp_name_sz = strlen(buf) + 1; 29597c478bd9Sstevel@tonic-gate 29607c478bd9Sstevel@tonic-gate /* type and nelem */ 29617c478bd9Sstevel@tonic-gate if (!xdr_int(xdr, (int *)&nvp->nvp_type) || 29627c478bd9Sstevel@tonic-gate !xdr_int(xdr, &nvp->nvp_value_elem)) 29637c478bd9Sstevel@tonic-gate return (EFAULT); 29647c478bd9Sstevel@tonic-gate 29657c478bd9Sstevel@tonic-gate type = NVP_TYPE(nvp); 29667c478bd9Sstevel@tonic-gate nelem = nvp->nvp_value_elem; 29677c478bd9Sstevel@tonic-gate 29687c478bd9Sstevel@tonic-gate /* 29697c478bd9Sstevel@tonic-gate * Verify type and nelem and get the value size. 29707c478bd9Sstevel@tonic-gate * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY 29717c478bd9Sstevel@tonic-gate * is the size of the string(s) excluded. 29727c478bd9Sstevel@tonic-gate */ 29737c478bd9Sstevel@tonic-gate if ((value_sz = i_get_value_size(type, NULL, nelem)) < 0) 29747c478bd9Sstevel@tonic-gate return (EFAULT); 29757c478bd9Sstevel@tonic-gate 29767c478bd9Sstevel@tonic-gate /* if there is no data to extract then return */ 29777c478bd9Sstevel@tonic-gate if (nelem == 0) 29787c478bd9Sstevel@tonic-gate return (0); 29797c478bd9Sstevel@tonic-gate 29807c478bd9Sstevel@tonic-gate /* value */ 29817c478bd9Sstevel@tonic-gate if ((buf = NVP_VALUE(nvp)) >= buf_end) 29827c478bd9Sstevel@tonic-gate return (EFAULT); 29837c478bd9Sstevel@tonic-gate buflen = buf_end - buf; 29847c478bd9Sstevel@tonic-gate 29857c478bd9Sstevel@tonic-gate if (buflen < value_sz) 29867c478bd9Sstevel@tonic-gate return (EFAULT); 29877c478bd9Sstevel@tonic-gate 29887c478bd9Sstevel@tonic-gate switch (type) { 29897c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST: 29907c478bd9Sstevel@tonic-gate if (nvs_embedded(nvs, (void *)buf) == 0) 29917c478bd9Sstevel@tonic-gate return (0); 29927c478bd9Sstevel@tonic-gate break; 29937c478bd9Sstevel@tonic-gate 29947c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: 29957c478bd9Sstevel@tonic-gate if (nvs_embedded_nvl_array(nvs, nvp, NULL) == 0) 29967c478bd9Sstevel@tonic-gate return (0); 29977c478bd9Sstevel@tonic-gate break; 29987c478bd9Sstevel@tonic-gate 29997c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN: 30007c478bd9Sstevel@tonic-gate ret = TRUE; 30017c478bd9Sstevel@tonic-gate break; 30027c478bd9Sstevel@tonic-gate 30037c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE: 30047c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8: 30057c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8: 30067c478bd9Sstevel@tonic-gate ret = xdr_char(xdr, buf); 30077c478bd9Sstevel@tonic-gate break; 30087c478bd9Sstevel@tonic-gate 30097c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16: 30107c478bd9Sstevel@tonic-gate ret = xdr_short(xdr, (void *)buf); 30117c478bd9Sstevel@tonic-gate break; 30127c478bd9Sstevel@tonic-gate 30137c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16: 30147c478bd9Sstevel@tonic-gate ret = xdr_u_short(xdr, (void *)buf); 30157c478bd9Sstevel@tonic-gate break; 30167c478bd9Sstevel@tonic-gate 30177c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_VALUE: 30187c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32: 30197c478bd9Sstevel@tonic-gate ret = xdr_int(xdr, (void *)buf); 30207c478bd9Sstevel@tonic-gate break; 30217c478bd9Sstevel@tonic-gate 30227c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32: 30237c478bd9Sstevel@tonic-gate ret = xdr_u_int(xdr, (void *)buf); 30247c478bd9Sstevel@tonic-gate break; 30257c478bd9Sstevel@tonic-gate 30267c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64: 30277c478bd9Sstevel@tonic-gate ret = xdr_longlong_t(xdr, (void *)buf); 30287c478bd9Sstevel@tonic-gate break; 30297c478bd9Sstevel@tonic-gate 30307c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64: 30317c478bd9Sstevel@tonic-gate ret = xdr_u_longlong_t(xdr, (void *)buf); 30327c478bd9Sstevel@tonic-gate break; 30337c478bd9Sstevel@tonic-gate 30347c478bd9Sstevel@tonic-gate case DATA_TYPE_HRTIME: 30357c478bd9Sstevel@tonic-gate /* 30367c478bd9Sstevel@tonic-gate * NOTE: must expose the definition of hrtime_t here 30377c478bd9Sstevel@tonic-gate */ 30387c478bd9Sstevel@tonic-gate ret = xdr_longlong_t(xdr, (void *)buf); 30397c478bd9Sstevel@tonic-gate break; 3040825ba0f2Srobj #if !defined(_KERNEL) 3041825ba0f2Srobj case DATA_TYPE_DOUBLE: 3042825ba0f2Srobj ret = xdr_double(xdr, (void *)buf); 3043825ba0f2Srobj break; 3044825ba0f2Srobj #endif 30457c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING: 30467c478bd9Sstevel@tonic-gate ret = xdr_string(xdr, &buf, buflen - 1); 30477c478bd9Sstevel@tonic-gate break; 30487c478bd9Sstevel@tonic-gate 30497c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE_ARRAY: 30507c478bd9Sstevel@tonic-gate ret = xdr_opaque(xdr, buf, nelem); 30517c478bd9Sstevel@tonic-gate break; 30527c478bd9Sstevel@tonic-gate 30537c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8_ARRAY: 30547c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8_ARRAY: 30557c478bd9Sstevel@tonic-gate ret = xdr_array(xdr, &buf, &nelem, buflen, sizeof (int8_t), 30567c478bd9Sstevel@tonic-gate (xdrproc_t)xdr_char); 30577c478bd9Sstevel@tonic-gate break; 30587c478bd9Sstevel@tonic-gate 30597c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16_ARRAY: 30607c478bd9Sstevel@tonic-gate ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int16_t), 30617c478bd9Sstevel@tonic-gate sizeof (int16_t), (xdrproc_t)xdr_short); 30627c478bd9Sstevel@tonic-gate break; 30637c478bd9Sstevel@tonic-gate 30647c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16_ARRAY: 30657c478bd9Sstevel@tonic-gate ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint16_t), 30667c478bd9Sstevel@tonic-gate sizeof (uint16_t), (xdrproc_t)xdr_u_short); 30677c478bd9Sstevel@tonic-gate break; 30687c478bd9Sstevel@tonic-gate 30697c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_ARRAY: 30707c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32_ARRAY: 30717c478bd9Sstevel@tonic-gate ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int32_t), 30727c478bd9Sstevel@tonic-gate sizeof (int32_t), (xdrproc_t)xdr_int); 30737c478bd9Sstevel@tonic-gate break; 30747c478bd9Sstevel@tonic-gate 30757c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32_ARRAY: 30767c478bd9Sstevel@tonic-gate ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint32_t), 30777c478bd9Sstevel@tonic-gate sizeof (uint32_t), (xdrproc_t)xdr_u_int); 30787c478bd9Sstevel@tonic-gate break; 30797c478bd9Sstevel@tonic-gate 30807c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64_ARRAY: 30817c478bd9Sstevel@tonic-gate ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int64_t), 30827c478bd9Sstevel@tonic-gate sizeof (int64_t), (xdrproc_t)xdr_longlong_t); 30837c478bd9Sstevel@tonic-gate break; 30847c478bd9Sstevel@tonic-gate 30857c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64_ARRAY: 30867c478bd9Sstevel@tonic-gate ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint64_t), 30877c478bd9Sstevel@tonic-gate sizeof (uint64_t), (xdrproc_t)xdr_u_longlong_t); 30887c478bd9Sstevel@tonic-gate break; 30897c478bd9Sstevel@tonic-gate 30907c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY: { 30917c478bd9Sstevel@tonic-gate size_t len = nelem * sizeof (uint64_t); 30927c478bd9Sstevel@tonic-gate char **strp = (void *)buf; 30937c478bd9Sstevel@tonic-gate int i; 30947c478bd9Sstevel@tonic-gate 30957c478bd9Sstevel@tonic-gate if (nvs->nvs_op == NVS_OP_DECODE) 30967c478bd9Sstevel@tonic-gate bzero(buf, len); /* don't trust packed data */ 30977c478bd9Sstevel@tonic-gate 30987c478bd9Sstevel@tonic-gate for (i = 0; i < nelem; i++) { 30997c478bd9Sstevel@tonic-gate if (buflen <= len) 31007c478bd9Sstevel@tonic-gate return (EFAULT); 31017c478bd9Sstevel@tonic-gate 31027c478bd9Sstevel@tonic-gate buf += len; 31037c478bd9Sstevel@tonic-gate buflen -= len; 31047c478bd9Sstevel@tonic-gate 31057c478bd9Sstevel@tonic-gate if (xdr_string(xdr, &buf, buflen - 1) != TRUE) 31067c478bd9Sstevel@tonic-gate return (EFAULT); 31077c478bd9Sstevel@tonic-gate 31087c478bd9Sstevel@tonic-gate if (nvs->nvs_op == NVS_OP_DECODE) 31097c478bd9Sstevel@tonic-gate strp[i] = buf; 31107c478bd9Sstevel@tonic-gate len = strlen(buf) + 1; 31117c478bd9Sstevel@tonic-gate } 31127c478bd9Sstevel@tonic-gate ret = TRUE; 31137c478bd9Sstevel@tonic-gate break; 31147c478bd9Sstevel@tonic-gate } 31157c478bd9Sstevel@tonic-gate default: 31167c478bd9Sstevel@tonic-gate break; 31177c478bd9Sstevel@tonic-gate } 31187c478bd9Sstevel@tonic-gate 31197c478bd9Sstevel@tonic-gate return (ret == TRUE ? 0 : EFAULT); 31207c478bd9Sstevel@tonic-gate } 31217c478bd9Sstevel@tonic-gate 31227c478bd9Sstevel@tonic-gate static int 31237c478bd9Sstevel@tonic-gate nvs_xdr_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size) 31247c478bd9Sstevel@tonic-gate { 31257c478bd9Sstevel@tonic-gate data_type_t type = NVP_TYPE(nvp); 31267c478bd9Sstevel@tonic-gate /* 31277c478bd9Sstevel@tonic-gate * encode_size + decode_size + name string size + data type + nelem 31287c478bd9Sstevel@tonic-gate * where name string size = 4 + NV_ALIGN4(strlen(NVP_NAME(nvp))) 31297c478bd9Sstevel@tonic-gate */ 31307c478bd9Sstevel@tonic-gate uint64_t nvp_sz = 4 + 4 + 4 + NV_ALIGN4(strlen(NVP_NAME(nvp))) + 4 + 4; 31317c478bd9Sstevel@tonic-gate 31327c478bd9Sstevel@tonic-gate switch (type) { 31337c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN: 31347c478bd9Sstevel@tonic-gate break; 31357c478bd9Sstevel@tonic-gate 31367c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_VALUE: 31377c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE: 31387c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8: 31397c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8: 31407c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16: 31417c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16: 31427c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32: 31437c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32: 31447c478bd9Sstevel@tonic-gate nvp_sz += 4; /* 4 is the minimum xdr unit */ 31457c478bd9Sstevel@tonic-gate break; 31467c478bd9Sstevel@tonic-gate 31477c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64: 31487c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64: 31497c478bd9Sstevel@tonic-gate case DATA_TYPE_HRTIME: 3150825ba0f2Srobj #if !defined(_KERNEL) 3151825ba0f2Srobj case DATA_TYPE_DOUBLE: 3152825ba0f2Srobj #endif 31537c478bd9Sstevel@tonic-gate nvp_sz += 8; 31547c478bd9Sstevel@tonic-gate break; 31557c478bd9Sstevel@tonic-gate 31567c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING: 31577c478bd9Sstevel@tonic-gate nvp_sz += 4 + NV_ALIGN4(strlen((char *)NVP_VALUE(nvp))); 31587c478bd9Sstevel@tonic-gate break; 31597c478bd9Sstevel@tonic-gate 31607c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE_ARRAY: 31617c478bd9Sstevel@tonic-gate nvp_sz += NV_ALIGN4(NVP_NELEM(nvp)); 31627c478bd9Sstevel@tonic-gate break; 31637c478bd9Sstevel@tonic-gate 31647c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_ARRAY: 31657c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8_ARRAY: 31667c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8_ARRAY: 31677c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16_ARRAY: 31687c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16_ARRAY: 31697c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32_ARRAY: 31707c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32_ARRAY: 31717c478bd9Sstevel@tonic-gate nvp_sz += 4 + 4 * (uint64_t)NVP_NELEM(nvp); 31727c478bd9Sstevel@tonic-gate break; 31737c478bd9Sstevel@tonic-gate 31747c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64_ARRAY: 31757c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64_ARRAY: 31767c478bd9Sstevel@tonic-gate nvp_sz += 4 + 8 * (uint64_t)NVP_NELEM(nvp); 31777c478bd9Sstevel@tonic-gate break; 31787c478bd9Sstevel@tonic-gate 31797c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY: { 31807c478bd9Sstevel@tonic-gate int i; 31817c478bd9Sstevel@tonic-gate char **strs = (void *)NVP_VALUE(nvp); 31827c478bd9Sstevel@tonic-gate 31837c478bd9Sstevel@tonic-gate for (i = 0; i < NVP_NELEM(nvp); i++) 31847c478bd9Sstevel@tonic-gate nvp_sz += 4 + NV_ALIGN4(strlen(strs[i])); 31857c478bd9Sstevel@tonic-gate 31867c478bd9Sstevel@tonic-gate break; 31877c478bd9Sstevel@tonic-gate } 31887c478bd9Sstevel@tonic-gate 31897c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST: 31907c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: { 31917c478bd9Sstevel@tonic-gate size_t nvsize = 0; 31927c478bd9Sstevel@tonic-gate int old_nvs_op = nvs->nvs_op; 31937c478bd9Sstevel@tonic-gate int err; 31947c478bd9Sstevel@tonic-gate 31957c478bd9Sstevel@tonic-gate nvs->nvs_op = NVS_OP_GETSIZE; 31967c478bd9Sstevel@tonic-gate if (type == DATA_TYPE_NVLIST) 31977c478bd9Sstevel@tonic-gate err = nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize); 31987c478bd9Sstevel@tonic-gate else 31997c478bd9Sstevel@tonic-gate err = nvs_embedded_nvl_array(nvs, nvp, &nvsize); 32007c478bd9Sstevel@tonic-gate nvs->nvs_op = old_nvs_op; 32017c478bd9Sstevel@tonic-gate 32027c478bd9Sstevel@tonic-gate if (err != 0) 32037c478bd9Sstevel@tonic-gate return (EINVAL); 32047c478bd9Sstevel@tonic-gate 32057c478bd9Sstevel@tonic-gate nvp_sz += nvsize; 32067c478bd9Sstevel@tonic-gate break; 32077c478bd9Sstevel@tonic-gate } 32087c478bd9Sstevel@tonic-gate 32097c478bd9Sstevel@tonic-gate default: 32107c478bd9Sstevel@tonic-gate return (EINVAL); 32117c478bd9Sstevel@tonic-gate } 32127c478bd9Sstevel@tonic-gate 32137c478bd9Sstevel@tonic-gate if (nvp_sz > INT32_MAX) 32147c478bd9Sstevel@tonic-gate return (EINVAL); 32157c478bd9Sstevel@tonic-gate 32167c478bd9Sstevel@tonic-gate *size = nvp_sz; 32177c478bd9Sstevel@tonic-gate 32187c478bd9Sstevel@tonic-gate return (0); 32197c478bd9Sstevel@tonic-gate } 32207c478bd9Sstevel@tonic-gate 32217c478bd9Sstevel@tonic-gate 32227c478bd9Sstevel@tonic-gate /* 32237c478bd9Sstevel@tonic-gate * The NVS_XDR_MAX_LEN macro takes a packed xdr buffer of size x and estimates 32247c478bd9Sstevel@tonic-gate * the largest nvpair that could be encoded in the buffer. 32257c478bd9Sstevel@tonic-gate * 32267c478bd9Sstevel@tonic-gate * See comments above nvpair_xdr_op() for the format of xdr encoding. 32277c478bd9Sstevel@tonic-gate * The size of a xdr packed nvpair without any data is 5 words. 32287c478bd9Sstevel@tonic-gate * 32297c478bd9Sstevel@tonic-gate * Using the size of the data directly as an estimate would be ok 32307c478bd9Sstevel@tonic-gate * in all cases except one. If the data type is of DATA_TYPE_STRING_ARRAY 32317c478bd9Sstevel@tonic-gate * then the actual nvpair has space for an array of pointers to index 32327c478bd9Sstevel@tonic-gate * the strings. These pointers are not encoded into the packed xdr buffer. 32337c478bd9Sstevel@tonic-gate * 32347c478bd9Sstevel@tonic-gate * If the data is of type DATA_TYPE_STRING_ARRAY and all the strings are 32357c478bd9Sstevel@tonic-gate * of length 0, then each string is endcoded in xdr format as a single word. 32367c478bd9Sstevel@tonic-gate * Therefore when expanded to an nvpair there will be 2.25 word used for 32377c478bd9Sstevel@tonic-gate * each string. (a int64_t allocated for pointer usage, and a single char 32387c478bd9Sstevel@tonic-gate * for the null termination.) 32397c478bd9Sstevel@tonic-gate * 32407c478bd9Sstevel@tonic-gate * This is the calculation performed by the NVS_XDR_MAX_LEN macro. 32417c478bd9Sstevel@tonic-gate */ 32427c478bd9Sstevel@tonic-gate #define NVS_XDR_HDR_LEN ((size_t)(5 * 4)) 32437c478bd9Sstevel@tonic-gate #define NVS_XDR_DATA_LEN(y) (((size_t)(y) <= NVS_XDR_HDR_LEN) ? \ 32447c478bd9Sstevel@tonic-gate 0 : ((size_t)(y) - NVS_XDR_HDR_LEN)) 32457c478bd9Sstevel@tonic-gate #define NVS_XDR_MAX_LEN(x) (NVP_SIZE_CALC(1, 0) + \ 32467c478bd9Sstevel@tonic-gate (NVS_XDR_DATA_LEN(x) * 2) + \ 32477c478bd9Sstevel@tonic-gate NV_ALIGN4((NVS_XDR_DATA_LEN(x) / 4))) 32487c478bd9Sstevel@tonic-gate 32497c478bd9Sstevel@tonic-gate static int 32507c478bd9Sstevel@tonic-gate nvs_xdr_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size) 32517c478bd9Sstevel@tonic-gate { 32527c478bd9Sstevel@tonic-gate XDR *xdr = nvs->nvs_private; 32537c478bd9Sstevel@tonic-gate int32_t encode_len, decode_len; 32547c478bd9Sstevel@tonic-gate 32557c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) { 32567c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: { 32577c478bd9Sstevel@tonic-gate size_t nvsize; 32587c478bd9Sstevel@tonic-gate 32597c478bd9Sstevel@tonic-gate if (nvs_xdr_nvp_size(nvs, nvp, &nvsize) != 0) 32607c478bd9Sstevel@tonic-gate return (EFAULT); 32617c478bd9Sstevel@tonic-gate 32627c478bd9Sstevel@tonic-gate decode_len = nvp->nvp_size; 32637c478bd9Sstevel@tonic-gate encode_len = nvsize; 32647c478bd9Sstevel@tonic-gate if (!xdr_int(xdr, &encode_len) || !xdr_int(xdr, &decode_len)) 32657c478bd9Sstevel@tonic-gate return (EFAULT); 32667c478bd9Sstevel@tonic-gate 32677c478bd9Sstevel@tonic-gate return (nvs_xdr_nvp_op(nvs, nvp)); 32687c478bd9Sstevel@tonic-gate } 32697c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: { 32707c478bd9Sstevel@tonic-gate struct xdr_bytesrec bytesrec; 32717c478bd9Sstevel@tonic-gate 32727c478bd9Sstevel@tonic-gate /* get the encode and decode size */ 32737c478bd9Sstevel@tonic-gate if (!xdr_int(xdr, &encode_len) || !xdr_int(xdr, &decode_len)) 32747c478bd9Sstevel@tonic-gate return (EFAULT); 32757c478bd9Sstevel@tonic-gate *size = decode_len; 32767c478bd9Sstevel@tonic-gate 32777c478bd9Sstevel@tonic-gate /* are we at the end of the stream? */ 32787c478bd9Sstevel@tonic-gate if (*size == 0) 32797c478bd9Sstevel@tonic-gate return (0); 32807c478bd9Sstevel@tonic-gate 32817c478bd9Sstevel@tonic-gate /* sanity check the size parameter */ 32827c478bd9Sstevel@tonic-gate if (!xdr_control(xdr, XDR_GET_BYTES_AVAIL, &bytesrec)) 32837c478bd9Sstevel@tonic-gate return (EFAULT); 32847c478bd9Sstevel@tonic-gate 32857c478bd9Sstevel@tonic-gate if (*size > NVS_XDR_MAX_LEN(bytesrec.xc_num_avail)) 32867c478bd9Sstevel@tonic-gate return (EFAULT); 32877c478bd9Sstevel@tonic-gate break; 32887c478bd9Sstevel@tonic-gate } 32897c478bd9Sstevel@tonic-gate 32907c478bd9Sstevel@tonic-gate default: 32917c478bd9Sstevel@tonic-gate return (EINVAL); 32927c478bd9Sstevel@tonic-gate } 32937c478bd9Sstevel@tonic-gate return (0); 32947c478bd9Sstevel@tonic-gate } 32957c478bd9Sstevel@tonic-gate 32967c478bd9Sstevel@tonic-gate static const struct nvs_ops nvs_xdr_ops = { 32977c478bd9Sstevel@tonic-gate nvs_xdr_nvlist, 32987c478bd9Sstevel@tonic-gate nvs_xdr_nvpair, 32997c478bd9Sstevel@tonic-gate nvs_xdr_nvp_op, 33007c478bd9Sstevel@tonic-gate nvs_xdr_nvp_size, 33017c478bd9Sstevel@tonic-gate nvs_xdr_nvl_fini 33027c478bd9Sstevel@tonic-gate }; 33037c478bd9Sstevel@tonic-gate 33047c478bd9Sstevel@tonic-gate static int 33057c478bd9Sstevel@tonic-gate nvs_xdr(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen) 33067c478bd9Sstevel@tonic-gate { 33077c478bd9Sstevel@tonic-gate XDR xdr; 33087c478bd9Sstevel@tonic-gate int err; 33097c478bd9Sstevel@tonic-gate 33107c478bd9Sstevel@tonic-gate nvs->nvs_ops = &nvs_xdr_ops; 33117c478bd9Sstevel@tonic-gate 33127c478bd9Sstevel@tonic-gate if ((err = nvs_xdr_create(nvs, &xdr, buf + sizeof (nvs_header_t), 33137c478bd9Sstevel@tonic-gate *buflen - sizeof (nvs_header_t))) != 0) 33147c478bd9Sstevel@tonic-gate return (err); 33157c478bd9Sstevel@tonic-gate 33167c478bd9Sstevel@tonic-gate err = nvs_operation(nvs, nvl, buflen); 33177c478bd9Sstevel@tonic-gate 33187c478bd9Sstevel@tonic-gate nvs_xdr_destroy(nvs); 33197c478bd9Sstevel@tonic-gate 33207c478bd9Sstevel@tonic-gate return (err); 33217c478bd9Sstevel@tonic-gate } 3322