diff options
author | Felix Fietkau <nbd@nbd.name> | 2022-01-28 14:13:58 +0100 |
---|---|---|
committer | Felix Fietkau <nbd@nbd.name> | 2022-02-03 15:16:47 +0100 |
commit | 03ea0405a6db0e5144d486a682e97a0be47a47c1 (patch) | |
tree | 892588d04993da9fa9c5d40859ff9ac3644f0c39 /package/kernel | |
parent | 543ada64edb88ff68328bcde5418eac7afcc3634 (diff) | |
download | upstream-03ea0405a6db0e5144d486a682e97a0be47a47c1.tar.gz upstream-03ea0405a6db0e5144d486a682e97a0be47a47c1.tar.bz2 upstream-03ea0405a6db0e5144d486a682e97a0be47a47c1.zip |
mac80211: backport MBSSID/EMA support patches
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Diffstat (limited to 'package/kernel')
3 files changed, 771 insertions, 16 deletions
diff --git a/package/kernel/mac80211/patches/subsys/312-mac80211-split-beacon-retrieval-functions.patch b/package/kernel/mac80211/patches/subsys/312-mac80211-split-beacon-retrieval-functions.patch new file mode 100644 index 0000000000..18b1951f6e --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/312-mac80211-split-beacon-retrieval-functions.patch @@ -0,0 +1,262 @@ +From: Aloka Dixit <alokad@codeaurora.org> +Date: Tue, 5 Oct 2021 21:09:36 -0700 +Subject: [PATCH] mac80211: split beacon retrieval functions + +Split __ieee80211_beacon_get() into a separate function for AP mode +ieee80211_beacon_get_ap(). +Also, move the code common to all modes (AP, adhoc and mesh) to +a separate function ieee80211_beacon_get_finish(). + +Signed-off-by: Aloka Dixit <alokad@codeaurora.org> +Link: https://lore.kernel.org/r/20211006040938.9531-2-alokad@codeaurora.org +Signed-off-by: Johannes Berg <johannes.berg@intel.com> +--- + +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -4987,6 +4987,115 @@ static int ieee80211_beacon_protect(stru + return 0; + } + ++static void ++ieee80211_beacon_get_finish(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ struct ieee80211_mutable_offsets *offs, ++ struct beacon_data *beacon, ++ struct sk_buff *skb, ++ struct ieee80211_chanctx_conf *chanctx_conf, ++ u16 csa_off_base) ++{ ++ struct ieee80211_local *local = hw_to_local(hw); ++ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); ++ struct ieee80211_tx_info *info; ++ enum nl80211_band band; ++ struct ieee80211_tx_rate_control txrc; ++ ++ /* CSA offsets */ ++ if (offs && beacon) { ++ u16 i; ++ ++ for (i = 0; i < IEEE80211_MAX_CNTDWN_COUNTERS_NUM; i++) { ++ u16 csa_off = beacon->cntdwn_counter_offsets[i]; ++ ++ if (!csa_off) ++ continue; ++ ++ offs->cntdwn_counter_offs[i] = csa_off_base + csa_off; ++ } ++ } ++ ++ band = chanctx_conf->def.chan->band; ++ info = IEEE80211_SKB_CB(skb); ++ info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; ++ info->flags |= IEEE80211_TX_CTL_NO_ACK; ++ info->band = band; ++ ++ memset(&txrc, 0, sizeof(txrc)); ++ txrc.hw = hw; ++ txrc.sband = local->hw.wiphy->bands[band]; ++ txrc.bss_conf = &sdata->vif.bss_conf; ++ txrc.skb = skb; ++ txrc.reported_rate.idx = -1; ++ if (sdata->beacon_rate_set && sdata->beacon_rateidx_mask[band]) ++ txrc.rate_idx_mask = sdata->beacon_rateidx_mask[band]; ++ else ++ txrc.rate_idx_mask = sdata->rc_rateidx_mask[band]; ++ txrc.bss = true; ++ rate_control_get_rate(sdata, NULL, &txrc); ++ ++ info->control.vif = vif; ++ info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT | ++ IEEE80211_TX_CTL_ASSIGN_SEQ | ++ IEEE80211_TX_CTL_FIRST_FRAGMENT; ++} ++ ++static struct sk_buff * ++ieee80211_beacon_get_ap(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ struct ieee80211_mutable_offsets *offs, ++ bool is_template, ++ struct beacon_data *beacon, ++ struct ieee80211_chanctx_conf *chanctx_conf) ++{ ++ struct ieee80211_local *local = hw_to_local(hw); ++ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); ++ struct ieee80211_if_ap *ap = &sdata->u.ap; ++ struct sk_buff *skb = NULL; ++ u16 csa_off_base = 0; ++ ++ if (beacon->cntdwn_counter_offsets[0]) { ++ if (!is_template) ++ ieee80211_beacon_update_cntdwn(vif); ++ ++ ieee80211_set_beacon_cntdwn(sdata, beacon); ++ } ++ ++ /* headroom, head length, ++ * tail length and maximum TIM length ++ */ ++ skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + ++ beacon->tail_len + 256 + ++ local->hw.extra_beacon_tailroom); ++ if (!skb) ++ return NULL; ++ ++ skb_reserve(skb, local->tx_headroom); ++ skb_put_data(skb, beacon->head, beacon->head_len); ++ ++ ieee80211_beacon_add_tim(sdata, &ap->ps, skb, is_template); ++ ++ if (offs) { ++ offs->tim_offset = beacon->head_len; ++ offs->tim_length = skb->len - beacon->head_len; ++ offs->cntdwn_counter_offs[0] = beacon->cntdwn_counter_offsets[0]; ++ ++ /* for AP the csa offsets are from tail */ ++ csa_off_base = skb->len; ++ } ++ ++ if (beacon->tail) ++ skb_put_data(skb, beacon->tail, beacon->tail_len); ++ ++ if (ieee80211_beacon_protect(skb, local, sdata) < 0) ++ return NULL; ++ ++ ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb, chanctx_conf, ++ csa_off_base); ++ return skb; ++} ++ + static struct sk_buff * + __ieee80211_beacon_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +@@ -4996,12 +5105,8 @@ __ieee80211_beacon_get(struct ieee80211_ + struct ieee80211_local *local = hw_to_local(hw); + struct beacon_data *beacon = NULL; + struct sk_buff *skb = NULL; +- struct ieee80211_tx_info *info; + struct ieee80211_sub_if_data *sdata = NULL; +- enum nl80211_band band; +- struct ieee80211_tx_rate_control txrc; + struct ieee80211_chanctx_conf *chanctx_conf; +- int csa_off_base = 0; + + rcu_read_lock(); + +@@ -5018,48 +5123,11 @@ __ieee80211_beacon_get(struct ieee80211_ + struct ieee80211_if_ap *ap = &sdata->u.ap; + + beacon = rcu_dereference(ap->beacon); +- if (beacon) { +- if (beacon->cntdwn_counter_offsets[0]) { +- if (!is_template) +- ieee80211_beacon_update_cntdwn(vif); +- +- ieee80211_set_beacon_cntdwn(sdata, beacon); +- } +- +- /* +- * headroom, head length, +- * tail length and maximum TIM length +- */ +- skb = dev_alloc_skb(local->tx_headroom + +- beacon->head_len + +- beacon->tail_len + 256 + +- local->hw.extra_beacon_tailroom); +- if (!skb) +- goto out; +- +- skb_reserve(skb, local->tx_headroom); +- skb_put_data(skb, beacon->head, beacon->head_len); +- +- ieee80211_beacon_add_tim(sdata, &ap->ps, skb, +- is_template); +- +- if (offs) { +- offs->tim_offset = beacon->head_len; +- offs->tim_length = skb->len - beacon->head_len; +- offs->cntdwn_counter_offs[0] = beacon->cntdwn_counter_offsets[0]; +- +- /* for AP the csa offsets are from tail */ +- csa_off_base = skb->len; +- } +- +- if (beacon->tail) +- skb_put_data(skb, beacon->tail, +- beacon->tail_len); +- +- if (ieee80211_beacon_protect(skb, local, sdata) < 0) +- goto out; +- } else ++ if (!beacon) + goto out; ++ ++ skb = ieee80211_beacon_get_ap(hw, vif, offs, is_template, ++ beacon, chanctx_conf); + } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { + struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; + struct ieee80211_hdr *hdr; +@@ -5085,6 +5153,9 @@ __ieee80211_beacon_get(struct ieee80211_ + hdr = (struct ieee80211_hdr *) skb->data; + hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_BEACON); ++ ++ ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb, ++ chanctx_conf, 0); + } else if (ieee80211_vif_is_mesh(&sdata->vif)) { + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; + +@@ -5124,51 +5195,13 @@ __ieee80211_beacon_get(struct ieee80211_ + } + + skb_put_data(skb, beacon->tail, beacon->tail_len); ++ ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb, ++ chanctx_conf, 0); + } else { + WARN_ON(1); + goto out; + } + +- /* CSA offsets */ +- if (offs && beacon) { +- int i; +- +- for (i = 0; i < IEEE80211_MAX_CNTDWN_COUNTERS_NUM; i++) { +- u16 csa_off = beacon->cntdwn_counter_offsets[i]; +- +- if (!csa_off) +- continue; +- +- offs->cntdwn_counter_offs[i] = csa_off_base + csa_off; +- } +- } +- +- band = chanctx_conf->def.chan->band; +- +- info = IEEE80211_SKB_CB(skb); +- +- info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; +- info->flags |= IEEE80211_TX_CTL_NO_ACK; +- info->band = band; +- +- memset(&txrc, 0, sizeof(txrc)); +- txrc.hw = hw; +- txrc.sband = local->hw.wiphy->bands[band]; +- txrc.bss_conf = &sdata->vif.bss_conf; +- txrc.skb = skb; +- txrc.reported_rate.idx = -1; +- if (sdata->beacon_rate_set && sdata->beacon_rateidx_mask[band]) +- txrc.rate_idx_mask = sdata->beacon_rateidx_mask[band]; +- else +- txrc.rate_idx_mask = sdata->rc_rateidx_mask[band]; +- txrc.bss = true; +- rate_control_get_rate(sdata, NULL, &txrc); +- +- info->control.vif = vif; +- +- info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT | +- IEEE80211_TX_CTL_ASSIGN_SEQ | +- IEEE80211_TX_CTL_FIRST_FRAGMENT; + out: + rcu_read_unlock(); + return skb; diff --git a/package/kernel/mac80211/patches/subsys/313-nl80211-MBSSID-and-EMA-support-in-AP-mode.patch b/package/kernel/mac80211/patches/subsys/313-nl80211-MBSSID-and-EMA-support-in-AP-mode.patch new file mode 100644 index 0000000000..8e6b301888 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/313-nl80211-MBSSID-and-EMA-support-in-AP-mode.patch @@ -0,0 +1,493 @@ +From: John Crispin <john@phrozen.org> +Date: Wed, 15 Sep 2021 19:54:34 -0700 +Subject: [PATCH] nl80211: MBSSID and EMA support in AP mode + +Add new attributes to configure support for multiple BSSID +and advanced multi-BSSID advertisements (EMA) in AP mode. + +- NL80211_ATTR_MBSSID_CONFIG used for per interface configuration. +- NL80211_ATTR_MBSSID_ELEMS used to MBSSID elements for beacons. + +Memory for the elements is allocated dynamically. This change frees +the memory in existing functions which call nl80211_parse_beacon(), +a comment is added to indicate the new references to do the same. + +Signed-off-by: John Crispin <john@phrozen.org> +Co-developed-by: Aloka Dixit <alokad@codeaurora.org> +Signed-off-by: Aloka Dixit <alokad@codeaurora.org> +Link: https://lore.kernel.org/r/20210916025437.29138-2-alokad@codeaurora.org +[don't leave ERR_PTR hanging around] +Signed-off-by: Johannes Berg <johannes.berg@intel.com> +--- + +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -1046,6 +1046,36 @@ struct cfg80211_crypto_settings { + }; + + /** ++ * struct cfg80211_mbssid_config - AP settings for multi bssid ++ * ++ * @tx_wdev: pointer to the transmitted interface in the MBSSID set ++ * @index: index of this AP in the multi bssid group. ++ * @ema: set to true if the beacons should be sent out in EMA mode. ++ */ ++struct cfg80211_mbssid_config { ++ struct wireless_dev *tx_wdev; ++ u8 index; ++ bool ema; ++}; ++ ++/** ++ * struct cfg80211_mbssid_elems - Multiple BSSID elements ++ * ++ * @cnt: Number of elements in array %elems. ++ * ++ * @elem: Array of multiple BSSID element(s) to be added into Beacon frames. ++ * @elem.data: Data for multiple BSSID elements. ++ * @elem.len: Length of data. ++ */ ++struct cfg80211_mbssid_elems { ++ u8 cnt; ++ struct { ++ const u8 *data; ++ size_t len; ++ } elem[]; ++}; ++ ++/** + * struct cfg80211_beacon_data - beacon data + * @head: head portion of beacon (before TIM IE) + * or %NULL if not changed +@@ -1063,6 +1093,7 @@ struct cfg80211_crypto_settings { + * @assocresp_ies_len: length of assocresp_ies in octets + * @probe_resp_len: length of probe response template (@probe_resp) + * @probe_resp: probe response template (AP mode only) ++ * @mbssid_ies: multiple BSSID elements + * @ftm_responder: enable FTM responder functionality; -1 for no change + * (which also implies no change in LCI/civic location data) + * @lci: Measurement Report element content, starting with Measurement Token +@@ -1080,6 +1111,7 @@ struct cfg80211_beacon_data { + const u8 *probe_resp; + const u8 *lci; + const u8 *civicloc; ++ struct cfg80211_mbssid_elems *mbssid_ies; + s8 ftm_responder; + + size_t head_len, tail_len; +@@ -1194,6 +1226,7 @@ enum cfg80211_ap_settings_flags { + * @he_oper: HE operation IE (or %NULL if HE isn't enabled) + * @fils_discovery: FILS discovery transmission parameters + * @unsol_bcast_probe_resp: Unsolicited broadcast probe response parameters ++ * @mbssid_config: AP settings for multiple bssid + */ + struct cfg80211_ap_settings { + struct cfg80211_chan_def chandef; +@@ -1226,6 +1259,7 @@ struct cfg80211_ap_settings { + struct cfg80211_he_bss_color he_bss_color; + struct cfg80211_fils_discovery fils_discovery; + struct cfg80211_unsol_bcast_probe_resp unsol_bcast_probe_resp; ++ struct cfg80211_mbssid_config mbssid_config; + }; + + /** +@@ -4986,6 +5020,13 @@ struct wiphy_iftype_akm_suites { + * %NL80211_TID_CONFIG_ATTR_RETRY_LONG attributes + * @sar_capa: SAR control capabilities + * @rfkill: a pointer to the rfkill structure ++ * ++ * @mbssid_max_interfaces: maximum number of interfaces supported by the driver ++ * in a multiple BSSID set. This field must be set to a non-zero value ++ * by the driver to advertise MBSSID support. ++ * @mbssid_max_ema_profile_periodicity: maximum profile periodicity supported by ++ * the driver. Setting this field to a non-zero value indicates that the ++ * driver supports enhanced multi-BSSID advertisements (EMA AP). + */ + struct wiphy { + struct mutex mtx; +@@ -5133,6 +5174,9 @@ struct wiphy { + + struct rfkill *rfkill; + ++ u8 mbssid_max_interfaces; ++ u8 ema_max_profile_periodicity; ++ + char priv[] __aligned(NETDEV_ALIGN); + }; + +--- a/include/uapi/linux/nl80211.h ++++ b/include/uapi/linux/nl80211.h +@@ -337,7 +337,10 @@ + * @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes + * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from + * userspace to request deletion of a virtual interface, then requires +- * attribute %NL80211_ATTR_IFINDEX. ++ * attribute %NL80211_ATTR_IFINDEX. If multiple BSSID advertisements are ++ * enabled using %NL80211_ATTR_MBSSID_CONFIG, %NL80211_ATTR_MBSSID_ELEMS, ++ * and if this command is used for the transmitting interface, then all ++ * the non-transmitting interfaces are deleted as well. + * + * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified + * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC. +@@ -2593,6 +2596,18 @@ enum nl80211_commands { + * @NL80211_ATTR_COLOR_CHANGE_ELEMS: Nested set of attributes containing the IE + * information for the time while performing a color switch. + * ++ * @NL80211_ATTR_MBSSID_CONFIG: Nested attribute for multiple BSSID ++ * advertisements (MBSSID) parameters in AP mode. ++ * Kernel uses this attribute to indicate the driver's support for MBSSID ++ * and enhanced multi-BSSID advertisements (EMA AP) to the userspace. ++ * Userspace should use this attribute to configure per interface MBSSID ++ * parameters. ++ * See &enum nl80211_mbssid_config_attributes for details. ++ * ++ * @NL80211_ATTR_MBSSID_ELEMS: Nested parameter to pass multiple BSSID elements. ++ * Mandatory parameter for the transmitting interface to enable MBSSID. ++ * Optional for the non-transmitting interfaces. ++ * + * @NUM_NL80211_ATTR: total number of nl80211_attrs available + * @NL80211_ATTR_MAX: highest attribute number currently defined + * @__NL80211_ATTR_AFTER_LAST: internal use +@@ -3096,6 +3111,9 @@ enum nl80211_attrs { + NL80211_ATTR_COLOR_CHANGE_COLOR, + NL80211_ATTR_COLOR_CHANGE_ELEMS, + ++ NL80211_ATTR_MBSSID_CONFIG, ++ NL80211_ATTR_MBSSID_ELEMS, ++ + /* add attributes here, update the policy in nl80211.c */ + + __NL80211_ATTR_AFTER_LAST, +@@ -7349,4 +7367,60 @@ enum nl80211_sar_specs_attrs { + NL80211_SAR_ATTR_SPECS_MAX = __NL80211_SAR_ATTR_SPECS_LAST - 1, + }; + ++/** ++ * enum nl80211_mbssid_config_attributes - multiple BSSID (MBSSID) and enhanced ++ * multi-BSSID advertisements (EMA) in AP mode. ++ * Kernel uses some of these attributes to advertise driver's support for ++ * MBSSID and EMA. ++ * Remaining attributes should be used by the userspace to configure the ++ * features. ++ * ++ * @__NL80211_MBSSID_CONFIG_ATTR_INVALID: Invalid ++ * ++ * @NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES: Used by the kernel to advertise ++ * the maximum number of MBSSID interfaces supported by the driver. ++ * Driver should indicate MBSSID support by setting ++ * wiphy->mbssid_max_interfaces to a value more than or equal to 2. ++ * ++ * @NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY: Used by the kernel ++ * to advertise the maximum profile periodicity supported by the driver ++ * if EMA is enabled. Driver should indicate EMA support to the userspace ++ * by setting wiphy->mbssid_max_ema_profile_periodicity to ++ * a non-zero value. ++ * ++ * @NL80211_MBSSID_CONFIG_ATTR_INDEX: Mandatory parameter to pass the index of ++ * this BSS (u8) in the multiple BSSID set. ++ * Value must be set to 0 for the transmitting interface and non-zero for ++ * all non-transmitting interfaces. The userspace will be responsible ++ * for using unique indices for the interfaces. ++ * Range: 0 to wiphy->mbssid_max_interfaces-1. ++ * ++ * @NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX: Mandatory parameter for ++ * a non-transmitted profile which provides the interface index (u32) of ++ * the transmitted profile. The value must match one of the interface ++ * indices advertised by the kernel. Optional if the interface being set up ++ * is the transmitting one, however, if provided then the value must match ++ * the interface index of the same. ++ * ++ * @NL80211_MBSSID_CONFIG_ATTR_EMA: Flag used to enable EMA AP feature. ++ * Setting this flag is permitted only if the driver advertises EMA support ++ * by setting wiphy->mbssid_max_ema_profile_periodicity to non-zero. ++ * ++ * @__NL80211_MBSSID_CONFIG_ATTR_LAST: Internal ++ * @NL80211_MBSSID_CONFIG_ATTR_MAX: highest attribute ++ */ ++enum nl80211_mbssid_config_attributes { ++ __NL80211_MBSSID_CONFIG_ATTR_INVALID, ++ ++ NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES, ++ NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY, ++ NL80211_MBSSID_CONFIG_ATTR_INDEX, ++ NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX, ++ NL80211_MBSSID_CONFIG_ATTR_EMA, ++ ++ /* keep last */ ++ __NL80211_MBSSID_CONFIG_ATTR_LAST, ++ NL80211_MBSSID_CONFIG_ATTR_MAX = __NL80211_MBSSID_CONFIG_ATTR_LAST - 1, ++}; ++ + #endif /* __LINUX_NL80211_H */ +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -439,6 +439,16 @@ sar_policy[NL80211_SAR_ATTR_MAX + 1] = { + [NL80211_SAR_ATTR_SPECS] = NLA_POLICY_NESTED_ARRAY(sar_specs_policy), + }; + ++static const struct nla_policy ++nl80211_mbssid_config_policy[NL80211_MBSSID_CONFIG_ATTR_MAX + 1] = { ++ [NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES] = NLA_POLICY_MIN(NLA_U8, 2), ++ [NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY] = ++ NLA_POLICY_MIN(NLA_U8, 1), ++ [NL80211_MBSSID_CONFIG_ATTR_INDEX] = { .type = NLA_U8 }, ++ [NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX] = { .type = NLA_U32 }, ++ [NL80211_MBSSID_CONFIG_ATTR_EMA] = { .type = NLA_FLAG }, ++}; ++ + static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { + [0] = { .strict_start_type = NL80211_ATTR_HE_OBSS_PD }, + [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, +@@ -780,6 +790,9 @@ static const struct nla_policy nl80211_p + [NL80211_ATTR_COLOR_CHANGE_COUNT] = { .type = NLA_U8 }, + [NL80211_ATTR_COLOR_CHANGE_COLOR] = { .type = NLA_U8 }, + [NL80211_ATTR_COLOR_CHANGE_ELEMS] = NLA_POLICY_NESTED(nl80211_policy), ++ [NL80211_ATTR_MBSSID_CONFIG] = ++ NLA_POLICY_NESTED(nl80211_mbssid_config_policy), ++ [NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED }, + }; + + /* policy for the key attributes */ +@@ -2228,6 +2241,35 @@ fail: + return -ENOBUFS; + } + ++static int nl80211_put_mbssid_support(struct wiphy *wiphy, struct sk_buff *msg) ++{ ++ struct nlattr *config; ++ ++ if (!wiphy->mbssid_max_interfaces) ++ return 0; ++ ++ config = nla_nest_start(msg, NL80211_ATTR_MBSSID_CONFIG); ++ if (!config) ++ return -ENOBUFS; ++ ++ if (nla_put_u8(msg, NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES, ++ wiphy->mbssid_max_interfaces)) ++ goto fail; ++ ++ if (wiphy->ema_max_profile_periodicity && ++ nla_put_u8(msg, ++ NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY, ++ wiphy->ema_max_profile_periodicity)) ++ goto fail; ++ ++ nla_nest_end(msg, config); ++ return 0; ++ ++fail: ++ nla_nest_cancel(msg, config); ++ return -ENOBUFS; ++} ++ + struct nl80211_dump_wiphy_state { + s64 filter_wiphy; + long start; +@@ -2813,6 +2855,9 @@ static int nl80211_send_wiphy(struct cfg + if (nl80211_put_sar_specs(rdev, msg)) + goto nla_put_failure; + ++ if (nl80211_put_mbssid_support(&rdev->wiphy, msg)) ++ goto nla_put_failure; ++ + /* done */ + state->split_start = 0; + break; +@@ -5002,6 +5047,96 @@ static int validate_beacon_tx_rate(struc + return 0; + } + ++static int nl80211_parse_mbssid_config(struct wiphy *wiphy, ++ struct net_device *dev, ++ struct nlattr *attrs, ++ struct cfg80211_mbssid_config *config, ++ u8 num_elems) ++{ ++ struct nlattr *tb[NL80211_MBSSID_CONFIG_ATTR_MAX + 1]; ++ ++ if (!wiphy->mbssid_max_interfaces) ++ return -EOPNOTSUPP; ++ ++ if (nla_parse_nested(tb, NL80211_MBSSID_CONFIG_ATTR_MAX, attrs, NULL, ++ NULL) || ++ !tb[NL80211_MBSSID_CONFIG_ATTR_INDEX]) ++ return -EINVAL; ++ ++ config->ema = nla_get_flag(tb[NL80211_MBSSID_CONFIG_ATTR_EMA]); ++ if (config->ema) { ++ if (!wiphy->ema_max_profile_periodicity) ++ return -EOPNOTSUPP; ++ ++ if (num_elems > wiphy->ema_max_profile_periodicity) ++ return -EINVAL; ++ } ++ ++ config->index = nla_get_u8(tb[NL80211_MBSSID_CONFIG_ATTR_INDEX]); ++ if (config->index >= wiphy->mbssid_max_interfaces || ++ (!config->index && !num_elems)) ++ return -EINVAL; ++ ++ if (tb[NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX]) { ++ u32 tx_ifindex = ++ nla_get_u32(tb[NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX]); ++ ++ if ((!config->index && tx_ifindex != dev->ifindex) || ++ (config->index && tx_ifindex == dev->ifindex)) ++ return -EINVAL; ++ ++ if (tx_ifindex != dev->ifindex) { ++ struct net_device *tx_netdev = ++ dev_get_by_index(wiphy_net(wiphy), tx_ifindex); ++ ++ if (!tx_netdev || !tx_netdev->ieee80211_ptr || ++ tx_netdev->ieee80211_ptr->wiphy != wiphy || ++ tx_netdev->ieee80211_ptr->iftype != ++ NL80211_IFTYPE_AP) { ++ dev_put(tx_netdev); ++ return -EINVAL; ++ } ++ ++ config->tx_wdev = tx_netdev->ieee80211_ptr; ++ } else { ++ config->tx_wdev = dev->ieee80211_ptr; ++ } ++ } else if (!config->index) { ++ config->tx_wdev = dev->ieee80211_ptr; ++ } else { ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static struct cfg80211_mbssid_elems * ++nl80211_parse_mbssid_elems(struct wiphy *wiphy, struct nlattr *attrs) ++{ ++ struct nlattr *nl_elems; ++ struct cfg80211_mbssid_elems *elems; ++ int rem_elems; ++ u8 i = 0, num_elems = 0; ++ ++ if (!wiphy->mbssid_max_interfaces) ++ return ERR_PTR(-EINVAL); ++ ++ nla_for_each_nested(nl_elems, attrs, rem_elems) ++ num_elems++; ++ ++ elems = kzalloc(struct_size(elems, elem, num_elems), GFP_KERNEL); ++ if (!elems) ++ return ERR_PTR(-ENOMEM); ++ ++ nla_for_each_nested(nl_elems, attrs, rem_elems) { ++ elems->elem[i].data = nla_data(nl_elems); ++ elems->elem[i].len = nla_len(nl_elems); ++ i++; ++ } ++ elems->cnt = num_elems; ++ return elems; ++} ++ + static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev, + struct nlattr *attrs[], + struct cfg80211_beacon_data *bcn) +@@ -5082,6 +5217,17 @@ static int nl80211_parse_beacon(struct c + bcn->ftm_responder = -1; + } + ++ if (attrs[NL80211_ATTR_MBSSID_ELEMS]) { ++ struct cfg80211_mbssid_elems *mbssid = ++ nl80211_parse_mbssid_elems(&rdev->wiphy, ++ attrs[NL80211_ATTR_MBSSID_ELEMS]); ++ ++ if (IS_ERR(mbssid)) ++ return PTR_ERR(mbssid); ++ ++ bcn->mbssid_ies = mbssid; ++ } ++ + return 0; + } + +@@ -5538,6 +5684,17 @@ static int nl80211_start_ap(struct sk_bu + goto out; + } + ++ if (info->attrs[NL80211_ATTR_MBSSID_CONFIG]) { ++ err = nl80211_parse_mbssid_config(&rdev->wiphy, dev, ++ info->attrs[NL80211_ATTR_MBSSID_CONFIG], ++ ¶ms.mbssid_config, ++ params.beacon.mbssid_ies ? ++ params.beacon.mbssid_ies->cnt : ++ 0); ++ if (err) ++ goto out; ++ } ++ + nl80211_calculate_ap_params(¶ms); + + if (info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT]) +@@ -5559,6 +5716,11 @@ static int nl80211_start_ap(struct sk_bu + + out: + kfree(params.acl); ++ kfree(params.beacon.mbssid_ies); ++ if (params.mbssid_config.tx_wdev && ++ params.mbssid_config.tx_wdev->netdev && ++ params.mbssid_config.tx_wdev->netdev != dev) ++ dev_put(params.mbssid_config.tx_wdev->netdev); + + return err; + } +@@ -5583,12 +5745,14 @@ static int nl80211_set_beacon(struct sk_ + + err = nl80211_parse_beacon(rdev, info->attrs, ¶ms); + if (err) +- return err; ++ goto out; + + wdev_lock(wdev); + err = rdev_change_beacon(rdev, dev, ¶ms); + wdev_unlock(wdev); + ++out: ++ kfree(params.mbssid_ies); + return err; + } + +@@ -9265,12 +9429,14 @@ static int nl80211_channel_switch(struct + + err = nl80211_parse_beacon(rdev, info->attrs, ¶ms.beacon_after); + if (err) +- return err; ++ goto free; + + csa_attrs = kcalloc(NL80211_ATTR_MAX + 1, sizeof(*csa_attrs), + GFP_KERNEL); +- if (!csa_attrs) +- return -ENOMEM; ++ if (!csa_attrs) { ++ err = -ENOMEM; ++ goto free; ++ } + + err = nla_parse_nested_deprecated(csa_attrs, NL80211_ATTR_MAX, + info->attrs[NL80211_ATTR_CSA_IES], +@@ -9389,6 +9555,8 @@ skip_beacons: + wdev_unlock(wdev); + + free: ++ kfree(params.beacon_after.mbssid_ies); ++ kfree(params.beacon_csa.mbssid_ies); + kfree(csa_attrs); + return err; + } +@@ -14924,6 +15092,8 @@ static int nl80211_color_change(struct s + wdev_unlock(wdev); + + out: ++ kfree(params.beacon_next.mbssid_ies); ++ kfree(params.beacon_color_change.mbssid_ies); + kfree(tb); + return err; + } diff --git a/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch b/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch index e0a259cde5..3140eee5d0 100644 --- a/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch +++ b/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch @@ -1,6 +1,6 @@ --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h -@@ -3835,6 +3835,7 @@ struct mgmt_frame_regs { +@@ -3869,6 +3869,7 @@ struct mgmt_frame_regs { * (as advertised by the nl80211 feature flag.) * @get_tx_power: store the current TX power into the dbm variable; * return 0 if successful @@ -8,7 +8,7 @@ * * @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting * functions to adjust rfkill hw state -@@ -4159,6 +4160,7 @@ struct cfg80211_ops { +@@ -4193,6 +4194,7 @@ struct cfg80211_ops { enum nl80211_tx_power_setting type, int mbm); int (*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev, int *dbm); @@ -36,9 +36,9 @@ u8 ps_dtim_period; --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h -@@ -2593,6 +2593,9 @@ enum nl80211_commands { - * @NL80211_ATTR_COLOR_CHANGE_ELEMS: Nested set of attributes containing the IE - * information for the time while performing a color switch. +@@ -2608,6 +2608,9 @@ enum nl80211_commands { + * Mandatory parameter for the transmitting interface to enable MBSSID. + * Optional for the non-transmitting interfaces. * + * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce + * transmit power to stay within regulatory limits. u32, dBi. @@ -46,9 +46,9 @@ * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use -@@ -3096,6 +3099,8 @@ enum nl80211_attrs { - NL80211_ATTR_COLOR_CHANGE_COLOR, - NL80211_ATTR_COLOR_CHANGE_ELEMS, +@@ -3114,6 +3117,8 @@ enum nl80211_attrs { + NL80211_ATTR_MBSSID_CONFIG, + NL80211_ATTR_MBSSID_ELEMS, + NL80211_ATTR_WIPHY_ANTENNA_GAIN, + @@ -129,19 +129,18 @@ local->hw.max_mtu = IEEE80211_MAX_DATA_LEN; --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c -@@ -780,6 +780,7 @@ static const struct nla_policy nl80211_p - [NL80211_ATTR_COLOR_CHANGE_COUNT] = { .type = NLA_U8 }, - [NL80211_ATTR_COLOR_CHANGE_COLOR] = { .type = NLA_U8 }, - [NL80211_ATTR_COLOR_CHANGE_ELEMS] = NLA_POLICY_NESTED(nl80211_policy), +@@ -793,6 +793,7 @@ static const struct nla_policy nl80211_p + [NL80211_ATTR_MBSSID_CONFIG] = + NLA_POLICY_NESTED(nl80211_mbssid_config_policy), + [NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED }, + [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 }, }; /* policy for the key attributes */ -@@ -3328,6 +3329,22 @@ static int nl80211_set_wiphy(struct sk_b - if (result) +@@ -3374,6 +3375,22 @@ static int nl80211_set_wiphy(struct sk_b goto out; } -+ + + if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_GAIN]) { + int idx, dbi = 0; + @@ -157,6 +156,7 @@ + if (result) + goto out; + } - ++ if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) { struct wireless_dev *txp_wdev = wdev; + enum nl80211_tx_power_setting type; |