diff options
author | Jo-Philipp Wich <jo@mein.io> | 2024-07-11 13:47:23 +0200 |
---|---|---|
committer | Jo-Philipp Wich <jo@mein.io> | 2024-07-11 14:08:01 +0200 |
commit | f6ea6fc8f0269d48e01429158153126fc213b0e4 (patch) | |
tree | 8e146c102770093a55759b00bf146d71e2f75e17 | |
parent | 115a84fa3c13eb9524089b48d4fa794222de4bfc (diff) |
nl80211: support conversion from/to struct array attributes
Some netlink attributes, e.g. `HWSIM_ATTR_TX_INFO` contain arrays of
structures. In order to cover this use-case, extend the ucode <-> nla
conversion routines to support `DT_NESTED` declaration in conjunction
with `DF_ARRAY`.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r-- | lib/nl80211.c | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/lib/nl80211.c b/lib/nl80211.c index 1cd7534..1b3c81e 100644 --- a/lib/nl80211.c +++ b/lib/nl80211.c @@ -1685,6 +1685,30 @@ uc_nl_parse_attr(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, break; case DT_NESTED: + if (spec->flags & DF_ARRAY) { + const uc_nl_nested_spec_t *nested = spec->auxdata; + + assert(nested != NULL); + assert(nested->headsize > 0); + + if (ucv_type(val) != UC_ARRAY) + return nla_parse_error(spec, vm, val, "not an array"); + + nla = nla_reserve(msg, spec->attr, ucv_array_length(val) * nested->headsize); + s = nla_data(nla); + + for (i = 0; i < ucv_array_length(val); i++) { + item = ucv_array_get(val, i); + + if (!uc_nl_parse_attrs(msg, s, nested->attrs, nested->nattrs, vm, item)) + return false; + + s += nested->headsize; + } + + return true; + } + if (!uc_nl_parse_rta_nested(spec, msg, base, vm, val)) return false; @@ -1824,6 +1848,34 @@ uc_nl_convert_attr(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base return ucv_string_new(buf); case DT_NESTED: + if (spec->flags & DF_ARRAY) { + const uc_nl_nested_spec_t *nested = spec->auxdata; + + assert(nested != NULL); + assert(nested->headsize > 0); + assert((nla_len(attr) % nested->headsize) == 0); + + v = ucv_array_new_length(vm, nla_len(attr) / nested->headsize); + + for (i = 0; i < nla_len(attr); i += nested->headsize) { + uc_value_t *item = ucv_object_new(vm); + + ucv_array_push(v, item); + + bool rv = uc_nl_convert_attrs(msg, + nla_data(attr) + i, nla_len(attr) - i, nested->headsize, + nested->attrs, nested->nattrs, vm, item); + + if (!rv) { + ucv_put(v); + + return NULL; + } + } + + return v; + } + return uc_nl_convert_rta_nested(spec, msg, attr, vm); case DT_HT_MCS: |