Path: blob/main/sys/dev/bhnd/nvram/bhnd_nvram_plist.c
39536 views
/*-1* Copyright (c) 2015-2016 Landon Fuller <[email protected]>2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer,9* without modification.10* 2. Redistributions in binary form must reproduce at minimum a disclaimer11* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any12* redistribution must be conditioned upon including a substantially13* similar Disclaimer requirement for further binary redistribution.14*15* NO WARRANTY16* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS17* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT18* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY19* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL20* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,21* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF22* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS23* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER24* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)25* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF26* THE POSSIBILITY OF SUCH DAMAGES.27*/2829#include <sys/param.h>30#include <sys/hash.h>3132#ifdef _KERNEL3334#include <sys/systm.h>3536#else /* !_KERNEL */3738#include <errno.h>39#include <stdint.h>40#include <stdlib.h>41#include <string.h>4243#endif /* _KERNEL */4445#include "bhnd_nvram_plistvar.h"46#include "bhnd_nvram_private.h"4748static bhnd_nvram_plist_entry *bhnd_nvram_plist_get_entry(49bhnd_nvram_plist *plist, const char *name);5051/**52* Allocate and initialize a new, empty property list.53*54* The caller is responsible for releasing the returned property value55* via bhnd_nvram_plist_release().56*57* @retval non-NULL success58* @retval NULL if allocation fails.59*/60bhnd_nvram_plist *61bhnd_nvram_plist_new(void)62{63bhnd_nvram_plist *plist;6465plist = bhnd_nv_calloc(1, sizeof(*plist));66if (plist == NULL)67return NULL;6869/* Implicit caller-owned reference */70plist->refs = 1;7172/* Initialize entry list */73plist->num_entries = 0;74TAILQ_INIT(&plist->entries);7576/* Initialize entry hash table */77for (size_t i = 0; i < nitems(plist->names); i++)78LIST_INIT(&plist->names[i]);7980return (plist);81}8283/**84* Retain a reference and return @p plist to the caller.85*86* The caller is responsible for releasing their reference ownership via87* bhnd_nvram_plist_release().88*89* @param plist The property list to be retained.90*/91bhnd_nvram_plist *92bhnd_nvram_plist_retain(bhnd_nvram_plist *plist)93{94BHND_NV_ASSERT(plist->refs >= 1, ("plist over-released"));9596refcount_acquire(&plist->refs);97return (plist);98}99100/**101* Release a reference to @p plist.102*103* If this is the last reference, all associated resources will be freed.104*105* @param plist The property list to be released.106*/107void108bhnd_nvram_plist_release(bhnd_nvram_plist *plist)109{110bhnd_nvram_plist_entry *ple, *ple_next;111112BHND_NV_ASSERT(plist->refs >= 1, ("plist over-released"));113114/* Drop reference */115if (!refcount_release(&plist->refs))116return;117118/* Free all property entries */119TAILQ_FOREACH_SAFE(ple, &plist->entries, pl_link, ple_next) {120bhnd_nvram_prop_release(ple->prop);121bhnd_nv_free(ple);122}123124/* Free plist instance */125bhnd_nv_free(plist);126}127128/**129* Return a shallow copy of @p plist.130*131* The caller is responsible for releasing the returned property value132* via bhnd_nvram_plist_release().133*134* @retval non-NULL success135* @retval NULL if allocation fails.136*/137bhnd_nvram_plist *138bhnd_nvram_plist_copy(bhnd_nvram_plist *plist)139{140bhnd_nvram_plist *copy;141bhnd_nvram_prop *prop;142int error;143144/* Allocate new, empty plist */145if ((copy = bhnd_nvram_plist_new()) == NULL)146return (NULL);147148/* Append all properties */149prop = NULL;150while ((prop = bhnd_nvram_plist_next(plist, prop)) != NULL) {151error = bhnd_nvram_plist_append(copy, prop);152if (error) {153if (error != ENOMEM) {154BHND_NV_LOG("error copying property: %d\n",155error);156}157158bhnd_nvram_plist_release(copy);159return (NULL);160}161}162163/* Return ownership of the copy to our caller */164return (copy);165}166167/**168* Return the number of properties in @p plist.169*/170size_t171bhnd_nvram_plist_count(bhnd_nvram_plist *plist)172{173return (plist->num_entries);174}175176/**177* Return true if @p plist contains a property name @p name, false otherwise.178*179* @param plist The property list to be queried.180* @param name The property name to be queried.181*/182bool183bhnd_nvram_plist_contains(bhnd_nvram_plist *plist, const char *name)184{185if (bhnd_nvram_plist_get_entry(plist, name) != NULL)186return (true);187188return (false);189}190191/**192* Replace the current property value for a property matching the name193* of @p prop, maintaining the property's current order in @p plist.194*195* If a matching property is not found in @p plist, @p prop will instead be196* appended.197*198* @param plist The property list to be modified.199* @param prop The replacement property.200*201* @retval 0 success202* @retval ENOMEM if allocation fails.203* @retval non-zero if modifying @p plist otherwise fails, a regular unix204* error code will be returned.205*/206int207bhnd_nvram_plist_replace(bhnd_nvram_plist *plist, bhnd_nvram_prop *prop)208{209bhnd_nvram_plist_entry *entry;210211/* Fetch current entry */212entry = bhnd_nvram_plist_get_entry(plist, prop->name);213if (entry == NULL) {214/* Not found -- append property instead */215return (bhnd_nvram_plist_append(plist, prop));216}217218/* Replace the current entry's property reference */219bhnd_nvram_prop_release(entry->prop);220entry->prop = bhnd_nvram_prop_retain(prop);221222return (0);223}224225/**226* Replace the current property value for a property matching @p name,227* maintaining the property's order in @p plist.228*229* If @p name is not found in @p plist, a new property will be appended.230*231* @param plist The property list to be modified.232* @param name The name of the property to be replaced.233* @param val The replacement value for @p name.234*235* @retval 0 success236* @retval ENOMEM if allocation fails.237* @retval non-zero if modifying @p plist otherwise fails, a regular unix238* error code will be returned.239*/240int241bhnd_nvram_plist_replace_val(bhnd_nvram_plist *plist, const char *name,242bhnd_nvram_val *val)243{244bhnd_nvram_prop *prop;245int error;246247/* Construct a new property instance for the name and value */248if ((prop = bhnd_nvram_prop_new(name, val)) == NULL)249return (ENOMEM);250251/* Attempt replace */252error = bhnd_nvram_plist_replace(plist, prop);253bhnd_nvram_prop_release(prop);254255return (error);256}257258/**259* Replace the current property value for a property matching @p name, copying260* the new property value from the given @p inp buffer of @p itype and @p ilen.261*262* The current property order of @p name in @p plist will be maintained.263*264* If @p name is not found in @p plist, a new property will be appended.265*266* @param plist The property list to be modified.267* @param name The name of the property to be replaced.268* @param inp Input buffer.269* @param ilen Input buffer length.270* @param itype Input buffer type.271*272* @retval 0 success273* @retval ENOMEM if allocation fails.274* @retval non-zero if modifying @p plist otherwise fails, a regular unix275* error code will be returned.276*/277int278bhnd_nvram_plist_replace_bytes(bhnd_nvram_plist *plist, const char *name,279const void *inp, size_t ilen, bhnd_nvram_type itype)280{281bhnd_nvram_prop *prop;282int error;283284if ((prop = bhnd_nvram_prop_bytes_new(name, inp, ilen, itype)) == NULL)285return (ENOMEM);286287error = bhnd_nvram_plist_replace(plist, prop);288bhnd_nvram_prop_release(prop);289290return (error);291}292293/**294* Replace the current property value for a property matching @p name, copying295* the new property value from @p val.296*297* The current property order of @p name in @p plist will be maintained.298*299* If @p name is not found in @p plist, a new property will be appended.300*301* @param plist The property list to be modified.302* @param name The name of the property to be replaced.303* @param val The property's replacement string value.304*305* @retval 0 success306* @retval ENOMEM if allocation fails.307* @retval non-zero if modifying @p plist otherwise fails, a regular unix308* error code will be returned.309*/310int311bhnd_nvram_plist_replace_string(bhnd_nvram_plist *plist, const char *name,312const char *val)313{314return (bhnd_nvram_plist_replace_bytes(plist, name, val, strlen(val)+1,315BHND_NVRAM_TYPE_STRING));316}317318/**319* Remove the property entry for the property @p name, if any.320*321* @param plist The property list to be modified.322* @param name The name of the property to be removed.323*/324void325bhnd_nvram_plist_remove(bhnd_nvram_plist *plist, const char *name)326{327bhnd_nvram_plist_entry *entry;328329/* Fetch entry */330entry = bhnd_nvram_plist_get_entry(plist, name);331if (entry == NULL)332return;333334/* Remove from entry list and hash table */335TAILQ_REMOVE(&plist->entries, entry, pl_link);336LIST_REMOVE(entry, pl_hash_link);337338/* Free plist entry */339bhnd_nvram_prop_release(entry->prop);340bhnd_nv_free(entry);341342/* Decrement entry count */343BHND_NV_ASSERT(plist->num_entries > 0, ("entry count over-release"));344plist->num_entries--;345}346347/**348* Fetch the property list entry for @p name, if any.349*350* @param plist The property list to be queried.351* @param name The property name to be queried.352*353* @retval non-NULL if @p name is found.354* @retval NULL if @p name is not found.355*/356static bhnd_nvram_plist_entry *357bhnd_nvram_plist_get_entry(bhnd_nvram_plist *plist, const char *name)358{359bhnd_nvram_plist_entry_list *hash_list;360bhnd_nvram_plist_entry *entry;361uint32_t h;362363h = hash32_str(name, HASHINIT);364hash_list = &plist->names[h % nitems(plist->names)];365366LIST_FOREACH(entry, hash_list, pl_hash_link) {367if (strcmp(entry->prop->name, name) == 0)368return (entry);369};370371/* Not found */372return (NULL);373}374375/**376* Append all properties from @p tail to @p plist.377*378* @param plist The property list to be modified.379* @param tail The property list to append.380*381* @retval 0 success382* @retval ENOMEM if allocation fails.383* @retval EEXIST an existing property from @p tail was found in @p plist.384*/385int386bhnd_nvram_plist_append_list(bhnd_nvram_plist *plist, bhnd_nvram_plist *tail)387{388bhnd_nvram_prop *p;389int error;390391p = NULL;392while ((p = bhnd_nvram_plist_next(tail, p)) != NULL) {393if ((error = bhnd_nvram_plist_append(plist, p)))394return (error);395}396397return (0);398}399400/**401* Append @p prop to @p plist.402*403* @param plist The property list to be modified.404* @param prop The property to append.405*406* @retval 0 success407* @retval ENOMEM if allocation fails.408* @retval EEXIST an existing property with @p name was found in @p plist.409*/410int411bhnd_nvram_plist_append(bhnd_nvram_plist *plist, bhnd_nvram_prop *prop)412{413bhnd_nvram_plist_entry_list *hash_list;414bhnd_nvram_plist_entry *entry;415uint32_t h;416417if (bhnd_nvram_plist_contains(plist, prop->name))418return (EEXIST);419420/* Have we hit the maximum representable entry count? */421if (plist->num_entries == SIZE_MAX)422return (ENOMEM);423424/* Allocate new entry */425entry = bhnd_nv_malloc(sizeof(*entry));426if (entry == NULL)427return (ENOMEM);428429entry->prop = bhnd_nvram_prop_retain(prop);430431/* Append to entry list */432TAILQ_INSERT_TAIL(&plist->entries, entry, pl_link);433434/* Add to name-based hash table */435h = hash32_str(prop->name, HASHINIT);436hash_list = &plist->names[h % nitems(plist->names)];437LIST_INSERT_HEAD(hash_list, entry, pl_hash_link);438439/* Increment entry count */440plist->num_entries++;441442return (0);443}444445/**446* Append a new property to @p plist with @p name and @p val.447*448* @param plist The property list to be modified.449* @param name The name of the property to be appended.450* @param val The value of the property to be appended.451*452* @retval 0 success453* @retval ENOMEM if allocation fails.454* @retval EEXIST an existing property with @p name was found in @p plist.455*/456int457bhnd_nvram_plist_append_val(bhnd_nvram_plist *plist, const char *name,458bhnd_nvram_val *val)459{460bhnd_nvram_prop *prop;461int error;462463if ((prop = bhnd_nvram_prop_new(name, val)) == NULL)464return (ENOMEM);465466error = bhnd_nvram_plist_append(plist, prop);467bhnd_nvram_prop_release(prop);468469return (error);470}471472/**473* Append a new property to @p plist, copying the property value from the474* given @p inp buffer of @p itype and @p ilen.475*476* @param plist The property list to be modified.477* @param name The name of the property to be appended.478* @param inp Input buffer.479* @param ilen Input buffer length.480* @param itype Input buffer type.481*482* @retval 0 success483* @retval ENOMEM if allocation fails.484* @retval EEXIST an existing property with @p name was found in @p plist.485*/486int487bhnd_nvram_plist_append_bytes(bhnd_nvram_plist *plist, const char *name,488const void *inp, size_t ilen, bhnd_nvram_type itype)489{490bhnd_nvram_prop *prop;491int error;492493if ((prop = bhnd_nvram_prop_bytes_new(name, inp, ilen, itype)) == NULL)494return (ENOMEM);495496error = bhnd_nvram_plist_append(plist, prop);497bhnd_nvram_prop_release(prop);498499return (error);500}501502/**503* Append a new string property to @p plist, copying the property value from504* @p val.505*506* @param plist The property list to be modified.507* @param name The name of the property to be appended.508* @param val The new property's string value.509*510* @retval 0 success511* @retval ENOMEM if allocation fails.512* @retval EEXIST an existing property with @p name was found in @p plist.513*/514int515bhnd_nvram_plist_append_string(bhnd_nvram_plist *plist, const char *name,516const char *val)517{518return (bhnd_nvram_plist_append_bytes(plist, name, val, strlen(val)+1,519BHND_NVRAM_TYPE_STRING));520}521522/**523* Iterate over all properties in @p plist.524*525* @param plist The property list to be iterated.526* @param prop A property in @p plist, or NULL to return the first527* property in @p plist.528*529* @retval non-NULL A borrowed reference to the next property in @p plist.530* @retval NULL If the end of the property list is reached or @p prop531* is not found in @p plist.532*/533bhnd_nvram_prop *534bhnd_nvram_plist_next(bhnd_nvram_plist *plist, bhnd_nvram_prop *prop)535{536bhnd_nvram_plist_entry *entry;537538if (prop == NULL) {539if ((entry = TAILQ_FIRST(&plist->entries)) == NULL)540return (NULL);541542return (entry->prop);543}544545/* Look up previous property entry by name */546if ((entry = bhnd_nvram_plist_get_entry(plist, prop->name)) == NULL)547return (NULL);548549/* The property instance must be identical */550if (entry->prop != prop)551return (NULL);552553/* Fetch next entry */554if ((entry = TAILQ_NEXT(entry, pl_link)) == NULL)555return (NULL);556557return (entry->prop);558}559560/**561* Return a borrowed reference to a named property, or NULL if @p name is562* not found in @p plist.563*564* @param plist The property list to be queried.565* @param name The name of the property to be returned.566*567* @retval non-NULL if @p name is found.568* @retval NULL if @p name is not found.569*/570bhnd_nvram_prop *571bhnd_nvram_plist_get_prop(bhnd_nvram_plist *plist, const char *name)572{573bhnd_nvram_plist_entry *entry;574575if ((entry = bhnd_nvram_plist_get_entry(plist, name)) == NULL)576return (NULL);577578return (entry->prop);579}580581/**582* Return a borrowed reference to the named property's value, or NULL if583* @p name is not found in @p plist.584*585* @param plist The property list to be queried.586* @param name The name of the property to be returned.587*588* @retval non-NULL if @p name is found.589* @retval NULL if @p name is not found.590*/591bhnd_nvram_val *592bhnd_nvram_plist_get_val(bhnd_nvram_plist *plist, const char *name)593{594bhnd_nvram_prop *prop;595596if ((prop = bhnd_nvram_plist_get_prop(plist, name)) == NULL)597return (NULL);598599return (bhnd_nvram_prop_val(prop));600}601602/**603* Attempt to encode a named property's value as @p otype, writing the result604* to @p outp.605*606* @param plist The property list to be queried.607* @param name The name of the property value to be returned.608* @param[out] outp On success, the value will be written to this609* buffer. This argment may be NULL if the value is610* not desired.611* @param[in,out] olen The capacity of @p outp. On success, will be set612* to the actual size of the requested value.613* @param otype The data type to be written to @p outp.614*615* @retval 0 success616* @retval ENOENT If @p name is not found in @p plist.617* @retval ENOMEM If the @p outp is non-NULL, and the provided @p olen618* is too small to hold the encoded value.619* @retval EFTYPE If value coercion from @p prop to @p otype is620* impossible.621* @retval ERANGE If value coercion would overflow (or underflow) the622* a @p otype representation.623*/624int625bhnd_nvram_plist_get_encoded(bhnd_nvram_plist *plist, const char *name,626void *outp, size_t olen, bhnd_nvram_type otype)627{628bhnd_nvram_prop *prop;629630if ((prop = bhnd_nvram_plist_get_prop(plist, name)) == NULL)631return (ENOENT);632633return (bhnd_nvram_prop_encode(prop, outp, &olen, otype));634}635636/**637* Return the character representation of a named property's value.638*639* @param plist The property list to be queried.640* @param name The name of the property value to be returned.641* @param[out] val On success, the character value of @p name.642*643* @retval 0 success644* @retval ENOENT If @p name is not found in @p plist.645* @retval EFTYPE If coercion of the property's value to @p val.646* @retval ERANGE If coercion of the property's value would overflow647* (or underflow) @p val.648*/649int650bhnd_nvram_plist_get_char(bhnd_nvram_plist *plist, const char *name,651u_char *val)652{653return (bhnd_nvram_plist_get_encoded(plist, name, val, sizeof(*val),654BHND_NVRAM_TYPE_CHAR));655}656657/**658* Return the uint8 representation of a named property's value.659*660* @param plist The property list to be queried.661* @param name The name of the property value to be returned.662* @param[out] val On success, the uint8 value of @p name.663*664* @retval 0 success665* @retval ENOENT If @p name is not found in @p plist.666* @retval EFTYPE If coercion of the property's value to @p val.667* @retval ERANGE If coercion of the property's value would overflow668* (or underflow) @p val.669*/670int671bhnd_nvram_plist_get_uint8(bhnd_nvram_plist *plist, const char *name,672uint8_t *val)673{674return (bhnd_nvram_plist_get_encoded(plist, name, val, sizeof(*val),675BHND_NVRAM_TYPE_UINT8));676}677678/**679* Return the uint16 representation of a named property's value.680*681* @param plist The property list to be queried.682* @param name The name of the property value to be returned.683* @param[out] val On success, the uint16 value of @p name.684*685* @retval 0 success686* @retval ENOENT If @p name is not found in @p plist.687* @retval EFTYPE If coercion of the property's value to @p val.688* @retval ERANGE If coercion of the property's value would overflow689* (or underflow) @p val.690*/691int692bhnd_nvram_plist_get_uint16(bhnd_nvram_plist *plist, const char *name,693uint16_t *val)694{695return (bhnd_nvram_plist_get_encoded(plist, name, val, sizeof(*val),696BHND_NVRAM_TYPE_UINT16));697}698699/**700* Return the uint32 representation of a named property's value.701*702* @param plist The property list to be queried.703* @param name The name of the property value to be returned.704* @param[out] val On success, the uint32 value of @p name.705*706* @retval 0 success707* @retval ENOENT If @p name is not found in @p plist.708* @retval EFTYPE If coercion of the property's value to @p val.709* @retval ERANGE If coercion of the property's value would overflow710* (or underflow) @p val.711*/712int713bhnd_nvram_plist_get_uint32(bhnd_nvram_plist *plist, const char *name,714uint32_t *val)715{716return (bhnd_nvram_plist_get_encoded(plist, name, val, sizeof(*val),717BHND_NVRAM_TYPE_UINT32));718}719720/**721* Return the uint64 representation of a named property's value.722*723* @param plist The property list to be queried.724* @param name The name of the property value to be returned.725* @param[out] val On success, the uint64 value of @p name.726*727* @retval 0 success728* @retval ENOENT If @p name is not found in @p plist.729* @retval EFTYPE If coercion of the property's value to @p val.730* @retval ERANGE If coercion of the property's value would overflow731* (or underflow) @p val.732*/733int734bhnd_nvram_plist_get_uint64(bhnd_nvram_plist *plist, const char *name,735uint64_t *val)736{737return (bhnd_nvram_plist_get_encoded(plist, name, val, sizeof(*val),738BHND_NVRAM_TYPE_UINT64));739}740741/**742* Return the boolean representation of a named property's value.743*744* @param plist The property list to be queried.745* @param name The name of the property value to be returned.746* @param[out] val On success, the boolean value of @p name.747*748* @retval 0 success749* @retval ENOENT If @p name is not found in @p plist.750* @retval EFTYPE If coercion of the property's value to @p val.751* @retval ERANGE If coercion of the property's value would overflow752* (or underflow) @p val.753*/754int755bhnd_nvram_plist_get_bool(bhnd_nvram_plist *plist, const char *name,756bool *val)757{758return (bhnd_nvram_plist_get_encoded(plist, name, val, sizeof(*val),759BHND_NVRAM_TYPE_BOOL));760}761762/**763* Allocate and initialize a new property value.764*765* The caller is responsible for releasing the returned property value766* via bhnd_nvram_prop_release().767*768* @param name Property name.769* @param val Property value.770*771* @retval non-NULL success772* @retval NULL if allocation fails.773*/774struct bhnd_nvram_prop *775bhnd_nvram_prop_new(const char *name, bhnd_nvram_val *val)776{777struct bhnd_nvram_prop *prop;778779prop = bhnd_nv_calloc(1, sizeof(*prop));780if (prop == NULL)781return NULL;782783/* Implicit caller-owned reference */784prop->refs = 1;785786if ((prop->name = bhnd_nv_strdup(name)) == NULL)787goto failed;788789if ((prop->val = bhnd_nvram_val_copy(val)) == NULL)790goto failed;791792return (prop);793794failed:795if (prop->name != NULL)796bhnd_nv_free(prop->name);797798if (prop->val != NULL)799bhnd_nvram_val_release(prop->val);800801bhnd_nv_free(prop);802return (NULL);803}804805/**806* Allocate a new property value and attempt to initialize its value from807* the given @p inp buffer of @p itype and @p ilen.808*809* The caller is responsible for releasing the returned property value810* via bhnd_nvram_prop_release().811*812* @param name Property name.813* @param inp Input buffer.814* @param ilen Input buffer length.815* @param itype Input buffer type.816*817* @retval non-NULL success818* @retval NULL if allocation or initialization fails.819*/820bhnd_nvram_prop *821bhnd_nvram_prop_bytes_new(const char *name, const void *inp, size_t ilen,822bhnd_nvram_type itype)823{824bhnd_nvram_prop *prop;825bhnd_nvram_val *val;826int error;827828/* Construct new value instance */829error = bhnd_nvram_val_new(&val, NULL, inp, ilen, itype,830BHND_NVRAM_VAL_DYNAMIC);831if (error) {832if (error != ENOMEM) {833BHND_NV_LOG("invalid input data; initialization "834"failed: %d\n", error);835}836837return (NULL);838}839840/* Delegate to default implementation */841prop = bhnd_nvram_prop_new(name, val);842843/* Clean up */844bhnd_nvram_val_release(val);845return (prop);846}847848/**849* Retain a reference and return @p prop to the caller.850*851* The caller is responsible for releasing their reference ownership via852* bhnd_nvram_prop_release().853*854* @param prop The property to be retained.855*/856bhnd_nvram_prop *857bhnd_nvram_prop_retain(bhnd_nvram_prop *prop)858{859BHND_NV_ASSERT(prop->refs >= 1, ("prop over-released"));860861refcount_acquire(&prop->refs);862return (prop);863}864865/**866* Release a reference to @p prop.867*868* If this is the last reference, all associated resources will be freed.869*870* @param prop The property to be released.871*/872void873bhnd_nvram_prop_release(bhnd_nvram_prop *prop)874{875BHND_NV_ASSERT(prop->refs >= 1, ("prop over-released"));876877/* Drop reference */878if (!refcount_release(&prop->refs))879return;880881/* Free property data */882bhnd_nvram_val_release(prop->val);883bhnd_nv_free(prop->name);884bhnd_nv_free(prop);885}886887/**888* Return a borrowed reference to the property's name.889*890* @param prop The property to query.891*/892const char *893bhnd_nvram_prop_name(bhnd_nvram_prop *prop)894{895return (prop->name);896}897898/**899* Return a borrowed reference to the property's value.900*901* @param prop The property to query.902*/903bhnd_nvram_val *904bhnd_nvram_prop_val(bhnd_nvram_prop *prop)905{906return (prop->val);907}908909/**910* Return the property's value type.911*912* @param prop The property to query.913*/914bhnd_nvram_type915bhnd_nvram_prop_type(bhnd_nvram_prop *prop)916{917return (bhnd_nvram_val_type(prop->val));918}919920/**921* Return true if @p prop has a NULL value type (BHND_NVRAM_TYPE_NULL), false922* otherwise.923*924* @param prop The property to query.925*/926bool927bhnd_nvram_prop_is_null(bhnd_nvram_prop *prop)928{929return (bhnd_nvram_prop_type(prop) == BHND_NVRAM_TYPE_NULL);930}931932/**933* Return a borrowed reference to the property's internal value representation.934*935* @param prop The property to query.936* @param[out] olen The returned data's size, in bytes.937* @param[out] otype The returned data's type.938*/939const void *940bhnd_nvram_prop_bytes(bhnd_nvram_prop *prop, size_t *olen,941bhnd_nvram_type *otype)942{943const void *bytes;944945bytes = bhnd_nvram_val_bytes(prop->val, olen, otype);946BHND_NV_ASSERT(*otype == bhnd_nvram_prop_type(prop), ("type mismatch"));947948return (bytes);949}950951/**952* Attempt to encode the property's value as @p otype, writing the result953* to @p outp.954*955* @param prop The property to be encoded.956* @param[out] outp On success, the value will be written to this957* buffer. This argment may be NULL if the value is958* not desired.959* @param[in,out] olen The capacity of @p outp. On success, will be set960* to the actual size of the requested value.961* @param otype The data type to be written to @p outp.962*963* @retval 0 success964* @retval ENOMEM If the @p outp is non-NULL, and the provided @p olen965* is too small to hold the encoded value.966* @retval EFTYPE If value coercion from @p prop to @p otype is967* impossible.968* @retval ERANGE If value coercion would overflow (or underflow) the969* a @p otype representation.970*/971int972bhnd_nvram_prop_encode(bhnd_nvram_prop *prop, void *outp, size_t *olen,973bhnd_nvram_type otype)974{975return (bhnd_nvram_val_encode(prop->val, outp, olen, otype));976}977978979