diff options
author | Felix Fietkau <nbd@nbd.name> | 2024-06-29 12:05:29 +0200 |
---|---|---|
committer | Felix Fietkau <nbd@nbd.name> | 2024-07-07 14:40:14 +0200 |
commit | 6e3cf83a77a7363d05c2b4c604187004d6eb17ef (patch) | |
tree | 1af1d6eb4527f7eaa7fbba61ec9bcfdd245fa721 | |
parent | 73644a036f5a67dc850ad73f4c713763db7c579c (diff) |
nl80211: add support for multi-attribute arrays
For newly added attributes, the kernel prefers to no longer add a nesting
container attribute. Instead, an attribute with the element type is simply
added multiple times within the outer container.
Add support for this array style, which will be used in the pending wiphy
multi radio support.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
-rw-r--r-- | lib/nl80211.c | 48 |
1 files changed, 24 insertions, 24 deletions
diff --git a/lib/nl80211.c b/lib/nl80211.c index f43a33d..3d2f6e2 100644 --- a/lib/nl80211.c +++ b/lib/nl80211.c @@ -170,6 +170,7 @@ enum { DF_ARRAY = (1 << 5), DF_BINARY = (1 << 6), DF_RELATED = (1 << 7), + DF_REPEATED = (1 << 8), }; typedef struct uc_nl_attr_spec { @@ -1008,26 +1009,6 @@ uc_nl_get_struct_member_u32(char *base, const void *offset) return u32; } -static void -uc_nl_nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len) -{ - struct nlattr *nla; - int rem; - - memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1)); - - nla_for_each_attr(nla, head, len, rem) { - int type = nla_type(nla); - - if (type <= maxtype) - tb[type] = nla; - } - - if (rem > 0) - fprintf(stderr, "netlink: %d bytes leftover after parsing attributes.\n", rem); -} - - static bool uc_nl_parse_attr(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, uc_vm_t *vm, uc_value_t *val, size_t idx); @@ -1051,12 +1032,10 @@ uc_nl_convert_attrs(struct nl_msg *msg, void *buf, size_t buflen, size_t headsiz if (!tb) return false; - uc_nl_nla_parse(tb, maxattr, buf + headsize, buflen - headsize); - nla_for_each_attr(nla, buf + headsize, buflen - headsize, rem) { type = nla_type(nla); - if (type <= maxattr) + if (type <= maxattr && !tb[type]) tb[type] = nla; } @@ -1064,7 +1043,28 @@ uc_nl_convert_attrs(struct nl_msg *msg, void *buf, size_t buflen, size_t headsiz if (attrs[i].attr != 0 && !tb[attrs[i].attr]) continue; - if (attrs[i].flags & DF_MULTIPLE) { + if (attrs[i].flags & DF_REPEATED) { + arr = ucv_array_new(vm); + + nla = tb[attrs[i].attr]; + rem = buflen - ((void *)nla - buf); + for (; nla_ok(nla, rem); nla = nla_next(nla, &rem)) { + if (nla_type(nla) != (int)attrs[i].attr) + break; + v = uc_nl_convert_attr(&attrs[i], msg, (char *)buf, nla, NULL, vm); + if (!v) + continue; + + ucv_array_push(arr, v); + } + if (!ucv_array_length(arr)) { + ucv_put(arr); + continue; + } + + v = arr; + } + else if (attrs[i].flags & DF_MULTIPLE) { arr = ucv_array_new(vm); nla_nest = tb[attrs[i].attr]; |