diff --git a/patches/0081-ucode-multi-radio.patch b/patches/0081-ucode-multi-radio.patch new file mode 100644 index 000000000..0714e1647 --- /dev/null +++ b/patches/0081-ucode-multi-radio.patch @@ -0,0 +1,612 @@ +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 +