From 47728424bea22cb0dc646be2cec95fec51710e01 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Fri, 22 Nov 2024 06:37:44 +0100 Subject: [PATCH] ucode: multi radio support Signed-off-by: John Crispin --- package/utils/ucode/patches/0001-fixes.patch | 21 +- ...ess-to-tb-array-out-of-uc_nl_convert.patch | 341 ++++++++++++++++++ ...d-support-for-multi-attribute-arrays.patch | 94 +++++ ...l80211-add-wiphy-multi-radio-support.patch | 50 +++ ...w-attributes-for-multi-radio-support.patch | 30 ++ 5 files changed, 528 insertions(+), 8 deletions(-) create mode 100644 package/utils/ucode/patches/110-nl80211-move-access-to-tb-array-out-of-uc_nl_convert.patch create mode 100644 package/utils/ucode/patches/111-nl80211-add-support-for-multi-attribute-arrays.patch create mode 100644 package/utils/ucode/patches/112-nl80211-add-wiphy-multi-radio-support.patch create mode 100644 package/utils/ucode/patches/113-nl80211-add-new-attributes-for-multi-radio-support.patch diff --git a/package/utils/ucode/patches/0001-fixes.patch b/package/utils/ucode/patches/0001-fixes.patch index a8f96fc71d..1f60bdd656 100644 --- a/package/utils/ucode/patches/0001-fixes.patch +++ b/package/utils/ucode/patches/0001-fixes.patch @@ -8,11 +8,9 @@ Subject: [PATCH] fixes lib/rtnl.c | 1 + 2 files changed, 87 insertions(+), 6 deletions(-) -Index: ucode-2023-06-06-c7d84aae/lib/nl80211.c -=================================================================== ---- ucode-2023-06-06-c7d84aae.orig/lib/nl80211.c -+++ ucode-2023-06-06-c7d84aae/lib/nl80211.c -@@ -56,6 +56,26 @@ limitations under the License. +--- a/lib/nl80211.c ++++ b/lib/nl80211.c +@@ -57,6 +57,33 @@ limitations under the License. #define NL80211_CMDS_BITMAP_SIZE DIV_ROUND_UP(NL80211_CMD_MAX + 1, 32) @@ -33,13 +31,20 @@ Index: ucode-2023-06-06-c7d84aae/lib/nl80211.c +#ifndef QCA_WIFI_7 +#define NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC NL80211_ATTR_NOT_IMPLEMENTED +#define NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY NL80211_ATTR_NOT_IMPLEMENTED ++#define NL80211_WIPHY_RADIO_FREQ_ATTR_START NL80211_ATTR_NOT_IMPLEMENTED ++#define NL80211_WIPHY_RADIO_FREQ_ATTR_END NL80211_ATTR_NOT_IMPLEMENTED ++#define NL80211_WIPHY_RADIO_ATTR_INDEX NL80211_ATTR_NOT_IMPLEMENTED ++#define NL80211_WIPHY_RADIO_ATTR_FREQ_RANGE NL80211_ATTR_NOT_IMPLEMENTED ++#define NL80211_WIPHY_RADIO_ATTR_INTERFACE_COMBINATION NL80211_ATTR_NOT_IMPLEMENTED ++#define NL80211_ATTR_WIPHY_RADIOS NL80211_ATTR_NOT_IMPLEMENTED ++#define NL80211_ATTR_VIF_RADIO_MASK NL80211_ATTR_NOT_IMPLEMENTED +#endif + + static struct { int code; char *msg; -@@ -560,7 +580,7 @@ static const uc_nl_nested_spec_t nl80211 +@@ -561,7 +588,7 @@ static const uc_nl_nested_spec_t nl80211 static const uc_nl_nested_spec_t nl80211_wiphy_bands_iftype_data_nla = { .headsize = 0, @@ -47,8 +52,8 @@ Index: ucode-2023-06-06-c7d84aae/lib/nl80211.c + .nattrs = 9, .attrs = { { NL80211_BAND_IFTYPE_ATTR_IFTYPES, "iftypes", DT_NESTED, 0, &nl80211_ifcomb_limit_types_nla }, - { NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC, "he_cap_mac", DT_U16, DF_ARRAY, NULL }, -@@ -569,6 +589,8 @@ static const uc_nl_nested_spec_t nl80211 + { NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC, "he_cap_mac", DT_U8, DF_ARRAY, NULL }, +@@ -570,6 +597,8 @@ static const uc_nl_nested_spec_t nl80211 { NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE, "he_cap_ppe", DT_U8, DF_ARRAY, NULL }, { NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA, "he_6ghz_capa", DT_U16, 0, NULL }, { NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS, "vendor_elems", DT_STRING, DF_BINARY, NULL }, diff --git a/package/utils/ucode/patches/110-nl80211-move-access-to-tb-array-out-of-uc_nl_convert.patch b/package/utils/ucode/patches/110-nl80211-move-access-to-tb-array-out-of-uc_nl_convert.patch new file mode 100644 index 0000000000..7e9d07e01e --- /dev/null +++ b/package/utils/ucode/patches/110-nl80211-move-access-to-tb-array-out-of-uc_nl_convert.patch @@ -0,0 +1,341 @@ +From: Felix Fietkau +Date: Sat, 29 Jun 2024 12:03:21 +0200 +Subject: [PATCH] nl80211: move access to tb array out of uc_nl_convert_attr + and below + +Only one place needs access to another attribute from the tb array +(HE MCS rates). In order to make that access possible, add a flag to indicate +a second attribute dependency via auxdata. + +Signed-off-by: Felix Fietkau +--- + +--- a/lib/nl80211.c ++++ b/lib/nl80211.c +@@ -197,6 +197,7 @@ enum { + DF_OFFSET1 = (1 << 4), + DF_ARRAY = (1 << 5), + DF_BINARY = (1 << 6), ++ DF_RELATED = (1 << 7), + }; + + typedef struct uc_nl_attr_spec { +@@ -215,6 +216,7 @@ typedef struct uc_nl_nested_spec { + + #define SIZE(type) (void *)(uintptr_t)sizeof(struct type) + #define MEMBER(type, field) (void *)(uintptr_t)offsetof(struct type, field) ++#define ATTRID(id) (void *)(uintptr_t)(id) + + static const uc_nl_nested_spec_t nl80211_cqm_nla = { + .headsize = 0, +@@ -593,7 +595,7 @@ static const uc_nl_nested_spec_t nl80211 + { NL80211_BAND_IFTYPE_ATTR_IFTYPES, "iftypes", DT_NESTED, 0, &nl80211_ifcomb_limit_types_nla }, + { NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC, "he_cap_mac", DT_U8, DF_ARRAY, NULL }, + { NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY, "he_cap_phy", DT_U8, DF_ARRAY, NULL }, +- { NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET, "he_cap_mcs_set", DT_HE_MCS, 0, NULL }, ++ { NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET, "he_cap_mcs_set", DT_HE_MCS, DF_RELATED, ATTRID(NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY) }, + { NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE, "he_cap_ppe", DT_U8, DF_ARRAY, NULL }, + { NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA, "he_6ghz_capa", DT_U16, 0, NULL }, + { NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS, "vendor_elems", DT_STRING, DF_BINARY, NULL }, +@@ -1065,12 +1067,12 @@ 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); + + static uc_value_t * +-uc_nl_convert_attr(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, struct nlattr **tb, uc_vm_t *vm); ++uc_nl_convert_attr(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, struct nlattr *attr, struct nlattr *attr2, uc_vm_t *vm); + + static bool + uc_nl_convert_attrs(struct nl_msg *msg, void *buf, size_t buflen, size_t headsize, const uc_nl_attr_spec_t *attrs, size_t nattrs, uc_vm_t *vm, uc_value_t *obj) + { +- struct nlattr **tb, *nla, *nla_nest; ++ struct nlattr **tb, *nla, *nla2, *nla_nest; + size_t i, type, maxattr = 0; + uc_value_t *v, *arr; + int rem; +@@ -1106,9 +1108,7 @@ uc_nl_convert_attrs(struct nl_msg *msg, + attrs[i].auxdata && nla_type(nla) != (intptr_t)attrs[i].auxdata) + continue; + +- tb[attrs[i].attr] = nla; +- +- v = uc_nl_convert_attr(&attrs[i], msg, (char *)buf, tb, vm); ++ v = uc_nl_convert_attr(&attrs[i], msg, (char *)buf, nla, NULL, vm); + + if (!v) + continue; +@@ -1128,7 +1128,12 @@ uc_nl_convert_attrs(struct nl_msg *msg, + v = arr; + } + else { +- v = uc_nl_convert_attr(&attrs[i], msg, (char *)buf, tb, vm); ++ if (attrs[i].flags & DF_RELATED) ++ nla2 = tb[(uintptr_t)attrs[i].auxdata]; ++ else ++ nla2 = NULL; ++ ++ v = uc_nl_convert_attr(&attrs[i], msg, (char *)buf, tb[attrs[i].attr], nla2, vm); + + if (!v) + continue; +@@ -1218,7 +1223,7 @@ uc_nl_parse_rta_nested(const uc_nl_attr_ + } + + static uc_value_t * +-uc_nl_convert_rta_nested(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm) ++uc_nl_convert_rta_nested(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr *attr, uc_vm_t *vm) + { + const uc_nl_nested_spec_t *nest = spec->auxdata; + uc_value_t *nested_obj; +@@ -1227,13 +1232,13 @@ uc_nl_convert_rta_nested(const uc_nl_att + if (!nest) + return NULL; + +- if (!nla_check_len(tb[spec->attr], nest->headsize)) ++ if (!nla_check_len(attr, nest->headsize)) + return NULL; + + nested_obj = ucv_object_new(vm); + + rv = uc_nl_convert_attrs(msg, +- nla_data(tb[spec->attr]), nla_len(tb[spec->attr]), nest->headsize, ++ nla_data(attr), nla_len(attr), nest->headsize, + nest->attrs, nest->nattrs, + vm, nested_obj); + +@@ -1247,17 +1252,17 @@ uc_nl_convert_rta_nested(const uc_nl_att + } + + static uc_value_t * +-uc_nl_convert_rta_ht_mcs(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm) ++uc_nl_convert_rta_ht_mcs(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr *attr, uc_vm_t *vm) + { + uc_value_t *mcs_obj, *mcs_idx; + uint16_t max_rate = 0; + uint8_t *mcs; + size_t i; + +- if (!nla_check_len(tb[spec->attr], 16)) ++ if (!nla_check_len(attr, 16)) + return NULL; + +- mcs = nla_data(tb[spec->attr]); ++ mcs = nla_data(attr); + mcs_obj = ucv_object_new(vm); + + max_rate = (mcs[10] | ((mcs[11] & 0x3) << 8)); +@@ -1282,16 +1287,16 @@ uc_nl_convert_rta_ht_mcs(const uc_nl_att + } + + static uc_value_t * +-uc_nl_convert_rta_ht_cap(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm) ++uc_nl_convert_rta_ht_cap(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr *attr, uc_vm_t *vm) + { + uc_value_t *cap_obj, *mcs_obj, *rx_mask; + struct ieee80211_ht_cap *cap; + size_t i; + +- if (!nla_check_len(tb[spec->attr], sizeof(*cap))) ++ if (!nla_check_len(attr, sizeof(*cap))) + return NULL; + +- cap = nla_data(tb[spec->attr]); ++ cap = nla_data(attr); + cap_obj = ucv_object_new(vm); + + ucv_object_add(cap_obj, "cap_info", ucv_uint64_new(le16toh(cap->cap_info))); +@@ -1316,17 +1321,17 @@ uc_nl_convert_rta_ht_cap(const uc_nl_att + } + + static uc_value_t * +-uc_nl_convert_rta_vht_mcs(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm) ++uc_nl_convert_rta_vht_mcs(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr *attr, uc_vm_t *vm) + { + uc_value_t *mcs_obj, *mcs_set, *mcs_entry, *mcs_idx; + size_t i, j, max_idx; + uint16_t u16; + uint8_t *mcs; + +- if (!nla_check_len(tb[spec->attr], 8)) ++ if (!nla_check_len(attr, 8)) + return NULL; + +- mcs = nla_data(tb[spec->attr]); ++ mcs = nla_data(attr); + mcs_obj = ucv_object_new(vm); + + u16 = mcs[0] | (mcs[1] << 8); +@@ -1387,7 +1392,7 @@ uc_nl_convert_rta_vht_mcs(const uc_nl_at + } + + static uc_value_t * +-uc_nl_convert_rta_he_mcs(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm) ++uc_nl_convert_rta_he_mcs(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr *attr, struct nlattr *phy_attr, uc_vm_t *vm) + { + uint8_t bw_support_mask[] = { (1 << 1) | (1 << 2), (1 << 3), (1 << 4) }; + uc_value_t *mcs_set, *mcs_bw, *mcs_dir, *mcs_entry, *mcs_idx; +@@ -1395,13 +1400,13 @@ uc_nl_convert_rta_he_mcs(const uc_nl_att + uint16_t u16, phy_cap_0 = 0; + size_t i, j, k, l, max_idx; + +- if (!nla_check_len(tb[spec->attr], sizeof(mcs))) ++ if (!nla_check_len(attr, sizeof(mcs))) + return NULL; + +- if (nla_check_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY], sizeof(phy_cap_0))) +- phy_cap_0 = nla_get_u16(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]); ++ if (nla_check_len(phy_attr, sizeof(phy_cap_0))) ++ phy_cap_0 = nla_get_u16(phy_attr); + +- memcpy(mcs, nla_data(tb[spec->attr]), sizeof(mcs)); ++ memcpy(mcs, nla_data(attr), sizeof(mcs)); + + mcs_set = ucv_array_new_length(vm, 3); + +@@ -1458,14 +1463,14 @@ uc_nl_convert_rta_he_mcs(const uc_nl_att + } + + static uc_value_t * +-uc_nl_convert_rta_ie(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm) ++uc_nl_convert_rta_ie(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr *attr, uc_vm_t *vm) + { + uc_value_t *ie_arr, *ie_obj; + uint8_t *ie; + size_t len; + +- len = nla_len(tb[spec->attr]); +- ie = nla_data(tb[spec->attr]); ++ len = nla_len(attr); ++ ie = nla_data(attr); + + if (len < 2) + return NULL; +@@ -1734,7 +1739,7 @@ uc_nl_convert_numval(const uc_nl_attr_sp + } + + static uc_value_t * +-uc_nl_convert_attr(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, struct nlattr **tb, uc_vm_t *vm) ++uc_nl_convert_attr(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, struct nlattr *attr, struct nlattr *attr2, uc_vm_t *vm) + { + union { uint8_t u8; uint16_t u16; uint32_t u32; uint64_t u64; size_t sz; } t = { 0 }; + char buf[sizeof("FF:FF:FF:FF:FF:FF")]; +@@ -1751,17 +1756,17 @@ uc_nl_convert_attr(const uc_nl_attr_spec + case DT_U64: + if (spec->flags & DF_ARRAY) { + assert(spec->attr != 0); +- assert((nla_len(tb[spec->attr]) % dt_sizes[spec->type]) == 0); ++ assert((nla_len(attr) % dt_sizes[spec->type]) == 0); + +- v = ucv_array_new_length(vm, nla_len(tb[spec->attr]) / dt_sizes[spec->type]); ++ v = ucv_array_new_length(vm, nla_len(attr) / dt_sizes[spec->type]); + +- for (i = 0; i < nla_len(tb[spec->attr]); i += dt_sizes[spec->type]) +- ucv_array_push(v, uc_nl_convert_numval(spec, nla_data(tb[spec->attr]) + i)); ++ for (i = 0; i < nla_len(attr); i += dt_sizes[spec->type]) ++ ucv_array_push(v, uc_nl_convert_numval(spec, nla_data(attr) + i)); + + return v; + } +- else if (nla_check_len(tb[spec->attr], dt_sizes[spec->type])) { +- return uc_nl_convert_numval(spec, nla_data(tb[spec->attr])); ++ else if (nla_check_len(attr, dt_sizes[spec->type])) { ++ return uc_nl_convert_numval(spec, nla_data(attr)); + } + + return NULL; +@@ -1769,15 +1774,15 @@ uc_nl_convert_attr(const uc_nl_attr_spec + case DT_BOOL: + if (spec->attr == 0) + t.u8 = uc_nl_get_struct_member_u8(base, spec->auxdata); +- else if (nla_check_len(tb[spec->attr], sizeof(t.u8))) +- t.u8 = nla_get_u8(tb[spec->attr]); ++ else if (nla_check_len(attr, sizeof(t.u8))) ++ t.u8 = nla_get_u8(attr); + + return ucv_boolean_new(t.u8 != 0); + + case DT_FLAG: + if (spec->attr == 0) + t.u8 = uc_nl_get_struct_member_u8(base, spec->auxdata); +- else if (tb[spec->attr] != NULL) ++ else if (attr != NULL) + t.u8 = 1; + + return ucv_boolean_new(t.u8 != 0); +@@ -1785,21 +1790,21 @@ uc_nl_convert_attr(const uc_nl_attr_spec + case DT_STRING: + assert(spec->attr != 0); + +- if (!nla_check_len(tb[spec->attr], 1)) ++ if (!nla_check_len(attr, 1)) + return NULL; + +- t.sz = nla_len(tb[spec->attr]); ++ t.sz = nla_len(attr); + + if (!(spec->flags & DF_BINARY)) + t.sz -= 1; + +- return ucv_string_new_length(nla_data(tb[spec->attr]), t.sz); ++ return ucv_string_new_length(nla_data(attr), t.sz); + + case DT_NETDEV: + if (spec->attr == 0) + t.u32 = uc_nl_get_struct_member_u32(base, spec->auxdata); +- else if (nla_check_len(tb[spec->attr], sizeof(t.u32))) +- t.u32 = nla_get_u32(tb[spec->attr]); ++ else if (nla_check_len(attr, sizeof(t.u32))) ++ t.u32 = nla_get_u32(attr); + + if (if_indextoname(t.u32, buf)) + return ucv_string_new(buf); +@@ -1809,10 +1814,10 @@ uc_nl_convert_attr(const uc_nl_attr_spec + case DT_LLADDR: + assert(spec->attr != 0); + +- if (!nla_check_len(tb[spec->attr], sizeof(*ea))) ++ if (!nla_check_len(attr, sizeof(*ea))) + return NULL; + +- ea = nla_data(tb[spec->attr]); ++ ea = nla_data(attr); + + snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x", + ea->ether_addr_octet[0], ea->ether_addr_octet[1], +@@ -1824,29 +1829,29 @@ uc_nl_convert_attr(const uc_nl_attr_spec + case DT_INADDR: + assert(spec->attr != 0); + +- if (!nla_check_len(tb[spec->attr], sizeof(struct in_addr)) || +- !inet_ntop(AF_INET, nla_data(tb[spec->attr]), buf, sizeof(buf))) ++ if (!nla_check_len(attr, sizeof(struct in_addr)) || ++ !inet_ntop(AF_INET, nla_data(attr), buf, sizeof(buf))) + return NULL; + + return ucv_string_new(buf); + + case DT_NESTED: +- return uc_nl_convert_rta_nested(spec, msg, tb, vm); ++ return uc_nl_convert_rta_nested(spec, msg, attr, vm); + + case DT_HT_MCS: +- return uc_nl_convert_rta_ht_mcs(spec, msg, tb, vm); ++ return uc_nl_convert_rta_ht_mcs(spec, msg, attr, vm); + + case DT_HT_CAP: +- return uc_nl_convert_rta_ht_cap(spec, msg, tb, vm); ++ return uc_nl_convert_rta_ht_cap(spec, msg, attr, vm); + + case DT_VHT_MCS: +- return uc_nl_convert_rta_vht_mcs(spec, msg, tb, vm); ++ return uc_nl_convert_rta_vht_mcs(spec, msg, attr, vm); + + case DT_HE_MCS: +- return uc_nl_convert_rta_he_mcs(spec, msg, tb, vm); ++ return uc_nl_convert_rta_he_mcs(spec, msg, attr, attr2, vm); + + case DT_IE: +- return uc_nl_convert_rta_ie(spec, msg, tb, vm); ++ return uc_nl_convert_rta_ie(spec, msg, attr, vm); + + default: + assert(0); diff --git a/package/utils/ucode/patches/111-nl80211-add-support-for-multi-attribute-arrays.patch b/package/utils/ucode/patches/111-nl80211-add-support-for-multi-attribute-arrays.patch new file mode 100644 index 0000000000..517d882850 --- /dev/null +++ b/package/utils/ucode/patches/111-nl80211-add-support-for-multi-attribute-arrays.patch @@ -0,0 +1,94 @@ +From: Felix Fietkau +Date: Sat, 29 Jun 2024 12:05:29 +0200 +Subject: [PATCH] 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 +--- + +--- a/lib/nl80211.c ++++ b/lib/nl80211.c +@@ -198,6 +198,7 @@ enum { + DF_ARRAY = (1 << 5), + DF_BINARY = (1 << 6), + DF_RELATED = (1 << 7), ++ DF_REPEATED = (1 << 8), + }; + + typedef struct uc_nl_attr_spec { +@@ -1043,26 +1044,6 @@ uc_nl_get_struct_member_u32(char *base, + 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); + +@@ -1086,12 +1067,10 @@ uc_nl_convert_attrs(struct nl_msg *msg, + 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; + } + +@@ -1099,7 +1078,28 @@ uc_nl_convert_attrs(struct nl_msg *msg, + 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]; + diff --git a/package/utils/ucode/patches/112-nl80211-add-wiphy-multi-radio-support.patch b/package/utils/ucode/patches/112-nl80211-add-wiphy-multi-radio-support.patch new file mode 100644 index 0000000000..588e9a5e72 --- /dev/null +++ b/package/utils/ucode/patches/112-nl80211-add-wiphy-multi-radio-support.patch @@ -0,0 +1,50 @@ +From: Felix Fietkau +Date: Tue, 9 Jul 2024 17:53:30 +0200 +Subject: [PATCH] nl80211: add wiphy multi-radio support + +Support new attributes that describe multiple radios belonging to a single +wiphy. + +Signed-off-by: Felix Fietkau +--- + +--- a/lib/nl80211.c ++++ b/lib/nl80211.c +@@ -842,9 +842,28 @@ static const uc_nl_nested_spec_t nl80211 + } + }; + ++static const uc_nl_nested_spec_t nl80211_radio_freq_range_nla = { ++ .headsize = 0, ++ .nattrs = 2, ++ .attrs = { ++ { NL80211_WIPHY_RADIO_FREQ_ATTR_START, "start", DT_U32, 0, NULL }, ++ { NL80211_WIPHY_RADIO_FREQ_ATTR_END, "end", DT_U32, 0, NULL }, ++ } ++}; ++ ++static const uc_nl_nested_spec_t nl80211_wiphy_radio_nla = { ++ .headsize = 0, ++ .nattrs = 3, ++ .attrs = { ++ { NL80211_WIPHY_RADIO_ATTR_INDEX, "index", DT_U32, 0, NULL }, ++ { NL80211_WIPHY_RADIO_ATTR_FREQ_RANGE, "freq_ranges", DT_NESTED, DF_REPEATED, &nl80211_radio_freq_range_nla }, ++ { NL80211_WIPHY_RADIO_ATTR_INTERFACE_COMBINATION, "interface_combinations", DT_NESTED, DF_REPEATED, &nl80211_ifcomb_nla }, ++ } ++}; ++ + static const uc_nl_nested_spec_t nl80211_msg = { + .headsize = 0, +- .nattrs = 128, ++ .nattrs = 129, + .attrs = { + { NL80211_ATTR_4ADDR, "4addr", DT_U8, 0, NULL }, + { NL80211_ATTR_AIRTIME_WEIGHT, "airtime_weight", DT_U16, 0, NULL }, +@@ -974,6 +993,7 @@ static const uc_nl_nested_spec_t nl80211 + { NL80211_ATTR_SOFTWARE_IFTYPES, "software_iftypes", DT_NESTED, 0, &nl80211_ifcomb_limit_types_nla }, + { NL80211_ATTR_MAX_AP_ASSOC_STA, "max_ap_assoc", DT_U16, 0, NULL }, + { NL80211_ATTR_SURVEY_INFO, "survey_info", DT_NESTED, 0, &nl80211_survey_info_nla }, ++ { NL80211_ATTR_WIPHY_RADIOS, "radios", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX, &nl80211_wiphy_radio_nla }, + } + }; + diff --git a/package/utils/ucode/patches/113-nl80211-add-new-attributes-for-multi-radio-support.patch b/package/utils/ucode/patches/113-nl80211-add-new-attributes-for-multi-radio-support.patch new file mode 100644 index 0000000000..15e5047510 --- /dev/null +++ b/package/utils/ucode/patches/113-nl80211-add-new-attributes-for-multi-radio-support.patch @@ -0,0 +1,30 @@ +From: Felix Fietkau +Date: Wed, 23 Oct 2024 18:50:10 +0200 +Subject: [PATCH] nl80211: add new attributes for multi-radio support + +- vif radio mask: used to assign vifs to specific radios +- monitor skip_tx flag: do not pass locally transmitted packets on the monitor interface +- radio antenna mask: radio specific part of the phy antenna mask + +Signed-off-by: Felix Fietkau +--- + +--- a/lib/nl80211.c ++++ b/lib/nl80211.c +@@ -863,7 +863,7 @@ static const uc_nl_nested_spec_t nl80211 + + static const uc_nl_nested_spec_t nl80211_msg = { + .headsize = 0, +- .nattrs = 129, ++ .nattrs = 130, + .attrs = { + { NL80211_ATTR_4ADDR, "4addr", DT_U8, 0, NULL }, + { NL80211_ATTR_AIRTIME_WEIGHT, "airtime_weight", DT_U16, 0, NULL }, +@@ -994,6 +994,7 @@ static const uc_nl_nested_spec_t nl80211 + { NL80211_ATTR_MAX_AP_ASSOC_STA, "max_ap_assoc", DT_U16, 0, NULL }, + { NL80211_ATTR_SURVEY_INFO, "survey_info", DT_NESTED, 0, &nl80211_survey_info_nla }, + { NL80211_ATTR_WIPHY_RADIOS, "radios", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX, &nl80211_wiphy_radio_nla }, ++ { NL80211_ATTR_VIF_RADIO_MASK, "vif_radio_mask", DT_U32, 0, NULL }, + } + }; + -- 2.34.1