mac80211: add multiple bssid support
authorJohn Crispin <john@phrozen.org>
Wed, 7 Oct 2020 12:02:19 +0000 (14:02 +0200)
committerJohn Crispin <john@phrozen.org>
Wed, 7 Oct 2020 12:06:43 +0000 (14:06 +0200)
Signed-off-by: John Crispin <john@phrozen.org>
package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
package/kernel/mac80211/patches/subsys/600-nl80211-add-basic-multiple-bssid-support.patch [new file with mode: 0644]
package/kernel/mac80211/patches/subsys/601-mac80211-add-multiple-bssid-support-to-interface-han.patch [new file with mode: 0644]
package/kernel/mac80211/patches/subsys/602-mac80211-add-multiple-bssid-EMA-support-to-beacon-ha.patch [new file with mode: 0644]
package/kernel/mac80211/patches/subsys/603-mac80211-dont-allow-CS-on-non-transmitting-interface.patch [new file with mode: 0644]
package/kernel/mac80211/patches/subsys/604-mbssid-ie.patch [new file with mode: 0644]

index 42144375b477e4477ee04aea7f745d79d3cd0ce6..fabf0a934697af164c77dd9c2f6c552be2f2e800 100644 (file)
@@ -401,6 +401,7 @@ mac80211_get_addr() {
 
 mac80211_generate_mac() {
        local phy="$1"
+       local multiple_bssid="$2"
        local id="${macidx:-0}"
 
        local ref="$(cat /sys/class/ieee80211/${phy}/macaddress)"
@@ -425,6 +426,11 @@ mac80211_generate_mac() {
 
        local oIFS="$IFS"; IFS=":"; set -- $ref; IFS="$oIFS"
 
+       [ "$multiple_bssid" -eq 1 ] && {
+               printf "02:%s:%s:%s:%s:%02x" $b1 $2 $3 $4 $5 $macidx
+               return
+       }
+
        macidx=$(($id + 1))
        [ "$((0x$mask1))" -gt 0 ] && {
                b1="0x$1"
@@ -533,6 +539,8 @@ mac80211_iw_interface_add() {
 }
 
 mac80211_prepare_vif() {
+       local multiple_bssid=$1
+
        json_select config
 
        json_get_vars ifname mode ssid wds powersave macaddr enable wpa_psk_file vlan_file
@@ -546,7 +554,7 @@ mac80211_prepare_vif() {
        json_select ..
 
        [ -n "$macaddr" ] || {
-               macaddr="$(mac80211_generate_mac $phy)"
+               macaddr="$(mac80211_generate_mac $phy $multiple_bssid)"
                macidx="$(($macidx + 1))"
        }
 
@@ -896,7 +904,8 @@ drv_mac80211_setup() {
                country chanbw distance \
                txpower antenna_gain \
                rxantenna txantenna \
-               frag rts beacon_int:100 htmode
+               frag rts beacon_int:100 htmode \
+               multiple_bssid:0
        json_get_values basic_rate_list basic_rate
        json_get_values scan_list scan_list
        json_select ..
@@ -991,7 +1000,7 @@ drv_mac80211_setup() {
        mac80211_prepare_iw_htmode
        for_each_interface "sta adhoc mesh monitor" mac80211_prepare_vif
        NEWAPLIST=
-       for_each_interface "ap" mac80211_prepare_vif
+       for_each_interface "ap" mac80211_prepare_vif $multiple_bssid
        NEW_MD5=$(test -e "${hostapd_conf_file}" && md5sum ${hostapd_conf_file})
        OLD_MD5=$(uci -q -P /var/state get wireless._${phy}.md5)
        if [ "${NEWAPLIST}" != "${OLDAPLIST}" ]; then
diff --git a/package/kernel/mac80211/patches/subsys/600-nl80211-add-basic-multiple-bssid-support.patch b/package/kernel/mac80211/patches/subsys/600-nl80211-add-basic-multiple-bssid-support.patch
new file mode 100644 (file)
index 0000000..6934e38
--- /dev/null
@@ -0,0 +1,202 @@
+From f548ce607d01d9575ec1a64702f75f96b923d259 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 6 Oct 2020 15:43:48 +0200
+Subject: [PATCH 1/4] nl80211: add basic multiple bssid support
+
+This patch adds support for passing the multiple bssid config to the
+kernel when adding an interface. If the BSS is non-transmitting it needs
+to be indicated. A non-transmitting BSSID will have a parent interface,
+which needs to be transmitting. The multiple bssid elements are passed
+as an array.
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ include/net/cfg80211.h       | 33 +++++++++++++++++++++++++++++++++
+ include/uapi/linux/nl80211.h | 21 +++++++++++++++++++++
+ net/wireless/nl80211.c       | 34 ++++++++++++++++++++++++++++++++++
+ 3 files changed, 88 insertions(+)
+
+Index: backports-5.8-1/include/net/cfg80211.h
+===================================================================
+--- backports-5.8-1.orig/include/net/cfg80211.h
++++ backports-5.8-1/include/net/cfg80211.h
+@@ -455,6 +455,21 @@ struct ieee80211_supported_band {
+ };
+ /**
++ * struct ieee80211_multiple_bssid - AP settings for multi bssid
++ *
++ * @index: the index of this AP in the multi bssid group.
++ * @count: the total number of multi bssid peer APs.
++ * @parent: non-transmitted BSSs transmitted parents index
++ * @ema: Shall the beacons be sent out in EMA mode.
++ */
++struct ieee80211_multiple_bssid {
++      u8 index;
++      u8 count;
++      u32 parent;
++      bool ema;
++};
++
++/**
+  * ieee80211_get_sband_iftype_data - return sband data for a given iftype
+  * @sband: the sband to search for the STA on
+  * @iftype: enum nl80211_iftype
+@@ -983,6 +998,19 @@ struct cfg80211_crypto_settings {
+ };
+ /**
++ * struct cfg80211_multiple_bssid_data - multiple_bssid data
++ * @ies: array of extra information element(s) to add into Beacon frames for multiple
++ *    bssid or %NULL
++ * @len: array of lengths of multiple_bssid.ies in octets
++ * @cnt: number of entries in multiple_bssid.ies
++ */
++struct cfg80211_multiple_bssid_data {
++      u8 *ies[NL80211_MULTIPLE_BSSID_IES_MAX];
++      size_t len[NL80211_MULTIPLE_BSSID_IES_MAX];
++      int cnt;
++};
++
++/**
+  * struct cfg80211_beacon_data - beacon data
+  * @head: head portion of beacon (before TIM IE)
+  *    or %NULL if not changed
+@@ -1008,6 +1036,7 @@ struct cfg80211_crypto_settings {
+  *    Token (measurement type 11)
+  * @lci_len: LCI data length
+  * @civicloc_len: Civic location data length
++ * @multiple_bssid: multiple_bssid data
+  */
+ struct cfg80211_beacon_data {
+       const u8 *head, *tail;
+@@ -1026,6 +1055,8 @@ struct cfg80211_beacon_data {
+       size_t probe_resp_len;
+       size_t lci_len;
+       size_t civicloc_len;
++
++      struct cfg80211_multiple_bssid_data multiple_bssid;
+ };
+ struct mac_address {
+@@ -1095,6 +1126,7 @@ enum cfg80211_ap_settings_flags {
+  * @he_obss_pd: OBSS Packet Detection settings
+  * @he_bss_color: BSS Color settings
+  * @he_oper: HE operation IE (or %NULL if HE isn't enabled)
++ * @multiple_bssid: AP settings for multiple bssid
+  */
+ struct cfg80211_ap_settings {
+       struct cfg80211_chan_def chandef;
+@@ -1125,6 +1157,7 @@ struct cfg80211_ap_settings {
+       u32 flags;
+       struct ieee80211_he_obss_pd he_obss_pd;
+       struct cfg80211_he_bss_color he_bss_color;
++      struct ieee80211_multiple_bssid multiple_bssid;
+ };
+ /**
+Index: backports-5.8-1/include/uapi/linux/nl80211.h
+===================================================================
+--- backports-5.8-1.orig/include/uapi/linux/nl80211.h
++++ backports-5.8-1/include/uapi/linux/nl80211.h
+@@ -2508,6 +2508,19 @@ enum nl80211_commands {
+  * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce
+  *    transmit power to stay within regulatory limits. u32, dBi.
+  *
++ * @NL80211_ATTR_MULTIPLE_BSSID_PARENT: If this is a Non-Transmitted BSSID, define
++ *    the parent (transmitting) interface.
++ *
++ * @NL80211_ATTR_MULTIPLE_BSSID_INDEX: The index of this BSS inside the multi bssid
++ *    element.
++ *
++ * @NL80211_ATTR_MULTIPLE_BSSID_COUNT: The number of BSSs inside the multi bssid element.
++ *
++ * @NL80211_ATTR_MULTIPLE_BSSID_IES: The Elements that describe our multiple BSS group.
++ *    these get passed separately as the kernel might need to split them up for EMA VAP.
++ *
++ * @NL80211_ATTR_MULTIPLE_BSSID_EMA: Shall the multiple BSS beacons be sent out in EMA mode. 
++ *
+  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
+  * @NL80211_ATTR_MAX: highest attribute number currently defined
+  * @__NL80211_ATTR_AFTER_LAST: internal use
+@@ -2992,6 +3005,12 @@ enum nl80211_attrs {
+       NL80211_ATTR_WIPHY_ANTENNA_GAIN,
++      NL80211_ATTR_MULTIPLE_BSSID_PARENT,
++      NL80211_ATTR_MULTIPLE_BSSID_INDEX,
++      NL80211_ATTR_MULTIPLE_BSSID_COUNT,
++      NL80211_ATTR_MULTIPLE_BSSID_IES,
++      NL80211_ATTR_MULTIPLE_BSSID_EMA,
++
+       /* add attributes here, update the policy in nl80211.c */
+       __NL80211_ATTR_AFTER_LAST,
+@@ -3053,6 +3072,8 @@ enum nl80211_attrs {
+ #define NL80211_CQM_TXE_MAX_INTVL             1800
++#define NL80211_MULTIPLE_BSSID_IES_MAX                8
++
+ /**
+  * enum nl80211_iftype - (virtual) interface types
+  *
+Index: backports-5.8-1/net/wireless/nl80211.c
+===================================================================
+--- backports-5.8-1.orig/net/wireless/nl80211.c
++++ backports-5.8-1/net/wireless/nl80211.c
+@@ -659,6 +659,11 @@ static const struct nla_policy nl80211_p
+               .len = sizeof(struct ieee80211_he_6ghz_capa),
+       },
+       [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 },
++      [NL80211_ATTR_MULTIPLE_BSSID_PARENT] = { .type = NLA_U32 },
++      [NL80211_ATTR_MULTIPLE_BSSID_INDEX] = { .type = NLA_U8 },
++      [NL80211_ATTR_MULTIPLE_BSSID_COUNT] = NLA_POLICY_RANGE(NLA_U8, 1, 16),
++      [NL80211_ATTR_MULTIPLE_BSSID_IES] = { .type = NLA_NESTED },
++      [NL80211_ATTR_MULTIPLE_BSSID_EMA] = { .type = NLA_FLAG },
+ };
+ /* policy for the key attributes */
+@@ -4684,6 +4689,21 @@ static int nl80211_parse_beacon(struct c
+               bcn->ftm_responder = -1;
+       }
++      if (attrs[NL80211_ATTR_MULTIPLE_BSSID_IES]) {
++              struct nlattr *nl_ie;
++              int rem_ie;
++
++              nla_for_each_nested(nl_ie, attrs[NL80211_ATTR_MULTIPLE_BSSID_IES], rem_ie) {
++                      if (bcn->multiple_bssid.cnt > NL80211_MULTIPLE_BSSID_IES_MAX)
++                              return -EINVAL;
++                      if (nla_type(nl_ie) != bcn->multiple_bssid.cnt + 1)
++                              return -EINVAL;
++                      bcn->multiple_bssid.ies[bcn->multiple_bssid.cnt] = nla_data(nl_ie);
++                      bcn->multiple_bssid.len[bcn->multiple_bssid.cnt] = nla_len(nl_ie);
++                      bcn->multiple_bssid.cnt++;
++              }
++      }
++
+       return 0;
+ }
+@@ -5046,6 +5066,20 @@ static int nl80211_start_ap(struct sk_bu
+                       goto out;
+       }
++      if (info->attrs[NL80211_ATTR_MULTIPLE_BSSID_PARENT])
++              params.multiple_bssid.parent =
++                      nla_get_u32(info->attrs[NL80211_ATTR_MULTIPLE_BSSID_PARENT]);
++
++      if (info->attrs[NL80211_ATTR_MULTIPLE_BSSID_INDEX])
++              params.multiple_bssid.index = nla_get_u8(
++                              info->attrs[NL80211_ATTR_MULTIPLE_BSSID_INDEX]);
++
++      if (info->attrs[NL80211_ATTR_MULTIPLE_BSSID_COUNT])
++              params.multiple_bssid.count = nla_get_u8(
++                              info->attrs[NL80211_ATTR_MULTIPLE_BSSID_COUNT]);
++      params.multiple_bssid.ema =
++              nla_get_flag(info->attrs[NL80211_ATTR_MULTIPLE_BSSID_EMA]);
++
+       nl80211_calculate_ap_params(&params);
+       if (info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT])
diff --git a/package/kernel/mac80211/patches/subsys/601-mac80211-add-multiple-bssid-support-to-interface-han.patch b/package/kernel/mac80211/patches/subsys/601-mac80211-add-multiple-bssid-support-to-interface-han.patch
new file mode 100644 (file)
index 0000000..1065526
--- /dev/null
@@ -0,0 +1,197 @@
+From 5ec6d96689c93093f51e233da5d28c6cd49f85ae Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 6 Oct 2020 15:45:37 +0200
+Subject: [PATCH 2/4] mac80211: add multiple bssid support to interface
+ handling
+
+When bringing up multi bssid APs we need to track the parent-child relation
+of non-transmitting and transmitting VAPs. This patch checks the above by
+using a linked list to track the relations. The patch also ensures that
+when a non-transmitting interface is closed the transmitting one is also
+closed.
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ include/net/mac80211.h | 28 +++++++++++++++++++++-
+ net/mac80211/cfg.c     | 53 ++++++++++++++++++++++++++++++++++++++++++
+ net/mac80211/debugfs.c |  1 +
+ net/mac80211/iface.c   |  6 +++++
+ 4 files changed, 87 insertions(+), 1 deletion(-)
+
+Index: backports-5.8-1/include/net/mac80211.h
+===================================================================
+--- backports-5.8-1.orig/include/net/mac80211.h
++++ backports-5.8-1/include/net/mac80211.h
+@@ -674,6 +674,7 @@ struct ieee80211_bss_conf {
+       } he_oper;
+       struct ieee80211_he_obss_pd he_obss_pd;
+       struct cfg80211_he_bss_color he_bss_color;
++      struct ieee80211_multiple_bssid multiple_bssid;
+ };
+ /**
+@@ -1623,6 +1624,20 @@ enum ieee80211_offload_flags {
+ };
+ /**
++ * enum ieee80211_vif_multiple_bssid_flags - virtual interface multiple bssid flags
++ *
++ * @IEEE80211_VIF_MBSS_TRANSMITTING: this BSS is transmitting beacons
++ * @IEEE80211_VIF_MBSS_NON_TRANSMITTING: this BSS is not transmitting beacons
++ * @IEEE80211_VIF_MBSS_EMA_BEACON: beacons should be send out in EMA mode
++*/
++
++enum ieee80211_vif_multiple_bssid_flags {
++      IEEE80211_VIF_MBSS_TRANSMITTING         = BIT(1),
++      IEEE80211_VIF_MBSS_NON_TRANSMITTING     = BIT(2),
++      IEEE80211_VIF_MBSS_EMA_BEACON           = BIT(3),
++};
++
++/**
+  * struct ieee80211_vif - per-interface data
+  *
+  * Data in this structure is continually present for driver
+@@ -1693,6 +1708,10 @@ struct ieee80211_vif {
+       bool rx_mcast_action_reg;
+       bool txqs_stopped[IEEE80211_NUM_ACS];
++      struct {
++              struct ieee80211_vif *parent;
++              u32 flags;
++      } multiple_bssid;
+       /* must be last */
+       u8 drv_priv[] __aligned(sizeof(void *));
+@@ -2341,7 +2360,7 @@ struct ieee80211_txq {
+  * @IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN: Driver does not report accurate A-MPDU
+  *    length in tx status information
+  *
+- * @IEEE80211_HW_SUPPORTS_MULTI_BSSID: Hardware supports multi BSSID
++ * @IEEE80211_HW_SUPPORTS_MULTI_BSSID: Hardware supports multi BSSID in STA mode
+  *
+  * @IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID: Hardware supports multi BSSID
+  *    only for HE APs. Applies if @IEEE80211_HW_SUPPORTS_MULTI_BSSID is set.
+@@ -2353,6 +2372,8 @@ struct ieee80211_txq {
+  * @IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD: Hardware supports tx encapsulation
+  *    offload
+  *
++ * @IEEE80211_HW_SUPPORTS_MULTI_BSSID_AP: Hardware supports multi BSSID in AP mode
++ *
+  * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
+  */
+ enum ieee80211_hw_flags {
+@@ -2406,6 +2427,7 @@ enum ieee80211_hw_flags {
+       IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID,
+       IEEE80211_HW_AMPDU_KEYBORDER_SUPPORT,
+       IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD,
++      IEEE80211_HW_SUPPORTS_MULTI_BSSID_AP,
+       /* keep last, obviously */
+       NUM_IEEE80211_HW_FLAGS
+Index: backports-5.8-1/net/mac80211/cfg.c
+===================================================================
+--- backports-5.8-1.orig/net/mac80211/cfg.c
++++ backports-5.8-1/net/mac80211/cfg.c
+@@ -111,6 +111,39 @@ static int ieee80211_set_mon_options(str
+       return 0;
+ }
++static void ieee80211_set_multiple_bssid_options(struct ieee80211_sub_if_data *sdata,
++                                               struct cfg80211_ap_settings *params)
++{
++      struct ieee80211_local *local = sdata->local;
++      struct wiphy *wiphy = local->hw.wiphy;
++      struct net_device *parent;
++      struct ieee80211_sub_if_data *psdata;
++
++      if (!ieee80211_hw_check(&local->hw, SUPPORTS_MULTI_BSSID_AP))
++              return;
++
++      if (!params->multiple_bssid.count)
++              return;
++
++      if (params->multiple_bssid.parent) {
++              parent = __dev_get_by_index(wiphy_net(wiphy),
++                                          params->multiple_bssid.parent);
++              if (!parent || !parent->ieee80211_ptr)
++                      return;
++              psdata = IEEE80211_WDEV_TO_SUB_IF(parent->ieee80211_ptr);
++              if (psdata->vif.multiple_bssid.parent)
++                      return;
++              sdata->vif.multiple_bssid.parent = &psdata->vif;
++              sdata->vif.multiple_bssid.flags |= IEEE80211_VIF_MBSS_NON_TRANSMITTING;
++      } else {
++              sdata->vif.multiple_bssid.flags |= IEEE80211_VIF_MBSS_TRANSMITTING;
++      }
++
++      if (params->multiple_bssid.ema)
++              sdata->vif.multiple_bssid.flags |= IEEE80211_VIF_MBSS_EMA_BEACON;
++      sdata->vif.bss_conf.multiple_bssid = params->multiple_bssid;
++}
++
+ static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy,
+                                               const char *name,
+                                               unsigned char name_assign_type,
+@@ -141,6 +174,23 @@ static struct wireless_dev *ieee80211_ad
+ static int ieee80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
+ {
++      struct ieee80211_sub_if_data *sdata;
++
++      sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
++      if (sdata->vif.type == NL80211_IFTYPE_AP) {
++              if (sdata->vif.multiple_bssid.flags & IEEE80211_VIF_MBSS_TRANSMITTING) {
++                      struct ieee80211_sub_if_data *child;
++
++                      rcu_read_lock();
++                      list_for_each_entry_rcu(child, &sdata->local->interfaces, list)
++                              if (child->vif.multiple_bssid.parent == &sdata->vif)
++                                      dev_close(child->wdev.netdev);
++                      rcu_read_unlock();
++              } else {
++                      sdata->vif.multiple_bssid.parent = NULL;
++              }
++      }
++
+       ieee80211_if_remove(IEEE80211_WDEV_TO_SUB_IF(wdev));
+       return 0;
+@@ -1021,6 +1071,9 @@ static int ieee80211_start_ap(struct wip
+                             IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK);
+       }
++      if (sdata->vif.type == NL80211_IFTYPE_AP)
++              ieee80211_set_multiple_bssid_options(sdata, params);
++
+       mutex_lock(&local->mtx);
+       err = ieee80211_vif_use_channel(sdata, &params->chandef,
+                                       IEEE80211_CHANCTX_SHARED);
+Index: backports-5.8-1/net/mac80211/debugfs.c
+===================================================================
+--- backports-5.8-1.orig/net/mac80211/debugfs.c
++++ backports-5.8-1/net/mac80211/debugfs.c
+@@ -409,6 +409,7 @@ static const char *hw_flag_names[] = {
+       FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID),
+       FLAG(AMPDU_KEYBORDER_SUPPORT),
+       FLAG(SUPPORTS_TX_ENCAP_OFFLOAD),
++      FLAG(SUPPORTS_MULTI_BSSID_AP),
+ #undef FLAG
+ };
+Index: backports-5.8-1/net/mac80211/iface.c
+===================================================================
+--- backports-5.8-1.orig/net/mac80211/iface.c
++++ backports-5.8-1/net/mac80211/iface.c
+@@ -377,6 +377,12 @@ static void ieee80211_do_stop(struct iee
+       bool cancel_scan;
+       struct cfg80211_nan_func *func;
++      /* make sure the parent is already down */
++      if (sdata->vif.type == NL80211_IFTYPE_AP &&
++          sdata->vif.multiple_bssid.parent &&
++          ieee80211_sdata_running(vif_to_sdata(sdata->vif.multiple_bssid.parent)))
++              dev_close(vif_to_sdata(sdata->vif.multiple_bssid.parent)->wdev.netdev);
++
+       clear_bit(SDATA_STATE_RUNNING, &sdata->state);
+       cancel_scan = rcu_access_pointer(local->scan_sdata) == sdata;
diff --git a/package/kernel/mac80211/patches/subsys/602-mac80211-add-multiple-bssid-EMA-support-to-beacon-ha.patch b/package/kernel/mac80211/patches/subsys/602-mac80211-add-multiple-bssid-EMA-support-to-beacon-ha.patch
new file mode 100644 (file)
index 0000000..64febfb
--- /dev/null
@@ -0,0 +1,514 @@
+From fb4fc65312a19630f7726e2bd992931349daebee Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 6 Oct 2020 15:51:59 +0200
+Subject: [PATCH 3/4] mac80211: add multiple bssid/EMA support to beacon
+ handling
+
+With beacon_data now holding the additional information about the multiple
+bssid elements, we need to honour these in the various beacon handling
+code paths.
+
+Extend ieee80211_beacon_get_template() to allow generation of EMA beacons.
+The API provides support for HW that can offload the EMA beaconing aswell
+as HW that will require periodic updates of the beacon template.
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ include/net/mac80211.h     |  92 +++++++++++++++++++++-
+ net/mac80211/cfg.c         |  59 +++++++++++++-
+ net/mac80211/ieee80211_i.h |   2 +
+ net/mac80211/tx.c          | 156 +++++++++++++++++++++++++++++++++----
+ 4 files changed, 288 insertions(+), 21 deletions(-)
+
+Index: backports-5.8-1/include/net/mac80211.h
+===================================================================
+--- backports-5.8-1.orig/include/net/mac80211.h
++++ backports-5.8-1/include/net/mac80211.h
+@@ -4834,6 +4834,8 @@ struct ieee80211_mutable_offsets {
+       u16 tim_length;
+       u16 csa_counter_offs[IEEE80211_MAX_CSA_COUNTERS_NUM];
++      u16 multiple_bssid_offset;
++      u16 multiple_bssid_length;
+ };
+ /**
+@@ -4861,6 +4863,91 @@ ieee80211_beacon_get_template(struct iee
+                             struct ieee80211_mutable_offsets *offs);
+ /**
++ * enum ieee80211_bcn_tmpl_ema - EMA beacon generation type
++ * @IEEE80211_BCN_EMA_NONE: don't generate an EMA beacon.
++ * @IEEE80211_BCN_EMA_NEXT: generate the next periodicity beacon.
++ * @IEEE80211_BCN_EMA_INDEX: generate beacon by periodicity index
++ *    if the value is >= this enum value.
++ */
++enum ieee80211_bcn_tmpl_ema {
++      IEEE80211_BCN_EMA_NONE  = -2,
++      IEEE80211_BCN_EMA_NEXT  = -1,
++      IEEE80211_BCN_EMA_INDEX = 0,
++};
++
++/**
++ * ieee80211_beacon_get_template_ema_next - EMA beacon template generation
++ *    function for drivers using the sw offload path.
++ * @hw: pointer obtained from ieee80211_alloc_hw().
++ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
++ * @offs: &struct ieee80211_mutable_offsets pointer to struct that will
++ *    receive the offsets that may be updated by the driver.
++ *
++ * This function differs from ieee80211_beacon_get_template in the sense that
++ * it generates EMA VAP templates. When we use multiple_bssid, the beacons can
++ * get very large costing a lot of airtime. To work around this, we iterate
++ * over the multiple bssid elements and only send one inside the beacon for
++ * 1..n. Calling this function will auto-increment the periodicity counter.
++ *
++ * This function needs to follow the same rules as ieee80211_beacon_get_template
++ *
++ * Return: The beacon template. %NULL on error.
++ */
++
++struct sk_buff *
++ieee80211_beacon_get_template_ema_next(struct ieee80211_hw *hw,
++                                     struct ieee80211_vif *vif,
++                                     struct ieee80211_mutable_offsets *offs);
++
++/** struct ieee80211_ema_bcn_list - list entry of an EMA beacon
++ * @list: the list pointer.
++ * @skb: the skb containing this specific beacon
++ * @offs: &struct ieee80211_mutable_offsets pointer to struct that will
++ *    receive the offsets that may be updated by the driver.
++ */
++struct ieee80211_ema_bcn_list {
++      struct list_head list;
++      struct sk_buff * skb;
++      struct ieee80211_mutable_offsets offs;
++};
++
++/**
++ * ieee80211_beacon_get_template_ema_list - EMA beacon template generation
++ *    function for drivers using the hw offload.
++ * @hw: pointer obtained from ieee80211_alloc_hw().
++ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
++ * @head: linked list head that will get populated with
++ *    &struct ieee80211_ema_bcn_list pointers.
++ *
++ * This function differs from ieee80211_beacon_get_template in the sense that
++ * it generates EMA VAP templates. When we use multiple_bssid, the beacons can
++ * get very large costing a lot of airtime. To work around this, we iterate
++ * over the multiple bssid elements and only send one inside the beacon for
++ * 1..n. This function will populate a linked list that the driver can pass
++ * to the HW.
++ *
++ * This function needs to follow the same rules as ieee80211_beacon_get_template
++ *
++ * Return: The nuber of entries in the list or 0 on error.
++ */
++
++int
++ieee80211_beacon_get_template_ema_list(struct ieee80211_hw *hw,
++                                     struct ieee80211_vif *vif,
++                                     struct list_head *head);
++
++/**
++ * ieee80211_beacon_free_ema_list - free an EMA beacon template list
++ * @head: linked list head containing &struct ieee80211_ema_bcn_list pointers.
++ *
++ * This function will free a list previously acquired by calling
++ * ieee80211_beacon_get_template_ema_list()
++ */
++
++void
++ieee80211_beacon_free_ema_list(struct list_head *head);
++
++/**
+  * ieee80211_beacon_get_tim - beacon generation function
+  * @hw: pointer obtained from ieee80211_alloc_hw().
+  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+Index: backports-5.8-1/net/mac80211/cfg.c
+===================================================================
+--- backports-5.8-1.orig/net/mac80211/cfg.c
++++ backports-5.8-1/net/mac80211/cfg.c
+@@ -929,12 +929,38 @@ static int ieee80211_set_ftm_responder_p
+       return 0;
+ }
++static int ieee80211_get_multiple_bssid_beacon_len(struct cfg80211_multiple_bssid_data *data)
++{
++      int i, len = 0;
++
++      for (i = 0; i < data->cnt; i++)
++              len += data->len[i];
++
++      return len;
++}
++
++static u8 *ieee80211_copy_multiple_bssid_beacon(u8 *offset,
++                                              struct cfg80211_multiple_bssid_data *new,
++                                              struct cfg80211_multiple_bssid_data *old)
++{
++      int i;
++
++      *new = *old;
++      for (i = 0; i < new->cnt; i++) {
++              new->ies[i] = offset;
++              memcpy(new->ies[i], old->ies[i], new->len[i]);
++              offset += new->len[i];
++      }
++      return offset;
++}
++
+ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
+                                  struct cfg80211_beacon_data *params,
+                                  const struct ieee80211_csa_settings *csa)
+ {
+       struct beacon_data *new, *old;
+-      int new_head_len, new_tail_len;
++      int new_head_len, new_tail_len, new_multiple_bssid_len;
++      u8 *new_multiple_bssid_offset;
+       int size, err;
+       u32 changed = BSS_CHANGED_BEACON;
+@@ -958,7 +984,15 @@ static int ieee80211_assign_beacon(struc
+       else
+               new_tail_len = old->tail_len;
+-      size = sizeof(*new) + new_head_len + new_tail_len;
++      /* new or old multiple_bssid? */
++      if (params->multiple_bssid.cnt || !old)
++              new_multiple_bssid_len =
++                      ieee80211_get_multiple_bssid_beacon_len(&params->multiple_bssid);
++      else
++              new_multiple_bssid_len =
++                      ieee80211_get_multiple_bssid_beacon_len(&old->multiple_bssid);
++
++      size = sizeof(*new) + new_head_len + new_tail_len + new_multiple_bssid_len;
+       new = kzalloc(size, GFP_KERNEL);
+       if (!new)
+@@ -975,6 +1009,18 @@ static int ieee80211_assign_beacon(struc
+       new->head_len = new_head_len;
+       new->tail_len = new_tail_len;
++      new_multiple_bssid_offset = new->tail + new_tail_len;
++
++      /* copy in optional multiple_bssid_ies */
++      if (params->multiple_bssid.cnt)
++              ieee80211_copy_multiple_bssid_beacon(new_multiple_bssid_offset,
++                                                   &new->multiple_bssid,
++                                                   &params->multiple_bssid);
++      else if (old && old->multiple_bssid.cnt)
++              ieee80211_copy_multiple_bssid_beacon(new_multiple_bssid_offset,
++                                                   &new->multiple_bssid,
++                                                   &old->multiple_bssid);
++
+       if (csa) {
+               new->csa_current_counter = csa->count;
+               memcpy(new->csa_counter_offsets, csa->counter_offsets_beacon,
+@@ -3011,7 +3057,8 @@ cfg80211_beacon_dup(struct cfg80211_beac
+       len = beacon->head_len + beacon->tail_len + beacon->beacon_ies_len +
+             beacon->proberesp_ies_len + beacon->assocresp_ies_len +
+-            beacon->probe_resp_len + beacon->lci_len + beacon->civicloc_len;
++            beacon->probe_resp_len + beacon->lci_len + beacon->civicloc_len +
++            ieee80211_get_multiple_bssid_beacon_len(&beacon->multiple_bssid);
+       new_beacon = kzalloc(sizeof(*new_beacon) + len, GFP_KERNEL);
+       if (!new_beacon)
+@@ -3054,6 +3101,10 @@ cfg80211_beacon_dup(struct cfg80211_beac
+               memcpy(pos, beacon->probe_resp, beacon->probe_resp_len);
+               pos += beacon->probe_resp_len;
+       }
++      if (beacon->multiple_bssid.cnt)
++              pos = ieee80211_copy_multiple_bssid_beacon(pos,
++                                                         &new_beacon->multiple_bssid,
++                                                         &beacon->multiple_bssid);
+       /* might copy -1, meaning no changes requested */
+       new_beacon->ftm_responder = beacon->ftm_responder;
+Index: backports-5.8-1/net/mac80211/ieee80211_i.h
+===================================================================
+--- backports-5.8-1.orig/net/mac80211/ieee80211_i.h
++++ backports-5.8-1/net/mac80211/ieee80211_i.h
+@@ -262,6 +262,8 @@ struct beacon_data {
+       struct ieee80211_meshconf_ie *meshconf;
+       u16 csa_counter_offsets[IEEE80211_MAX_CSA_COUNTERS_NUM];
+       u8 csa_current_counter;
++      struct cfg80211_multiple_bssid_data multiple_bssid;
++      u16 ema_index;
+       struct rcu_head rcu_head;
+ };
+Index: backports-5.8-1/net/mac80211/tx.c
+===================================================================
+--- backports-5.8-1.orig/net/mac80211/tx.c
++++ backports-5.8-1/net/mac80211/tx.c
+@@ -4719,11 +4719,26 @@ static int ieee80211_beacon_protect(stru
+       return 0;
+ }
++static void
++ieee80211_beacon_add_multiple_bssid_config(struct ieee80211_vif *vif, struct sk_buff *skb,
++                                         struct cfg80211_multiple_bssid_data *config)
++{
++      u8 *pos = skb_put(skb, 6);
++
++      *pos++ = WLAN_EID_EXTENSION;
++      *pos++ = 4;
++      *pos++ = WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION;
++      *pos++ = 2;
++      *pos++ = vif->bss_conf.multiple_bssid.count;
++      *pos++ = config->cnt;
++}
++
+ static struct sk_buff *
+ __ieee80211_beacon_get(struct ieee80211_hw *hw,
+                      struct ieee80211_vif *vif,
+                      struct ieee80211_mutable_offsets *offs,
+-                     bool is_template)
++                     bool is_template,
++                     int ema_index)
+ {
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct beacon_data *beacon = NULL;
+@@ -4735,13 +4750,11 @@ __ieee80211_beacon_get(struct ieee80211_
+       struct ieee80211_chanctx_conf *chanctx_conf;
+       int csa_off_base = 0;
+-      rcu_read_lock();
+-
+       sdata = vif_to_sdata(vif);
+       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+       if (!ieee80211_sdata_running(sdata) || !chanctx_conf)
+-              goto out;
++              return NULL;
+       if (offs)
+               memset(offs, 0, sizeof(*offs));
+@@ -4751,6 +4764,8 @@ __ieee80211_beacon_get(struct ieee80211_
+               beacon = rcu_dereference(ap->beacon);
+               if (beacon) {
++                      int multiple_bssid_len = 0;
++
+                       if (beacon->csa_counter_offsets[0]) {
+                               if (!is_template)
+                                       __ieee80211_csa_update_counter(beacon);
+@@ -4758,6 +4773,27 @@ __ieee80211_beacon_get(struct ieee80211_
+                               ieee80211_set_csa(sdata, beacon);
+                       }
++                      if (ema_index == IEEE80211_BCN_EMA_NEXT) {
++                              ema_index = beacon->ema_index;
++                              beacon->ema_index++;
++                              beacon->ema_index %= beacon->multiple_bssid.cnt;
++                      }
++
++                      if (ema_index != IEEE80211_BCN_EMA_NONE &&
++                          ema_index >= beacon->multiple_bssid.cnt)
++                              return NULL;
++
++                      if (beacon->multiple_bssid.cnt) {
++                              if (ema_index >= IEEE80211_BCN_EMA_INDEX) {
++                                      multiple_bssid_len = beacon->multiple_bssid.len[ema_index];
++                              } else {
++                                      int i;
++
++                                      for (i = 0; i < beacon->multiple_bssid.cnt; i++)
++                                              multiple_bssid_len = beacon->multiple_bssid.len[i];
++                              }
++                      }
++
+                       /*
+                        * headroom, head length,
+                        * tail length and maximum TIM length
+@@ -4765,9 +4801,10 @@ __ieee80211_beacon_get(struct ieee80211_
+                       skb = dev_alloc_skb(local->tx_headroom +
+                                           beacon->head_len +
+                                           beacon->tail_len + 256 +
+-                                          local->hw.extra_beacon_tailroom);
++                                          local->hw.extra_beacon_tailroom +
++                                          multiple_bssid_len);
+                       if (!skb)
+-                              goto out;
++                              return NULL;
+                       skb_reserve(skb, local->tx_headroom);
+                       skb_put_data(skb, beacon->head, beacon->head_len);
+@@ -4783,21 +4820,38 @@ __ieee80211_beacon_get(struct ieee80211_
+                               csa_off_base = skb->len;
+                       }
++                      if (multiple_bssid_len) {
++                              if (ema_index >= IEEE80211_BCN_EMA_INDEX) {
++                                      ieee80211_beacon_add_multiple_bssid_config(vif, skb,
++                                                                                 &beacon->multiple_bssid);
++                                      skb_put_data(skb, beacon->multiple_bssid.ies[beacon->ema_index],
++                                                   beacon->multiple_bssid.len[beacon->ema_index]);
++                              } else {
++                                      int i;
++
++                                      for (i = 0; i < beacon->multiple_bssid.cnt; i++)
++                                              skb_put_data(skb, beacon->multiple_bssid.ies[i],
++                                                           beacon->multiple_bssid.len[i]);
++                              }
++                              if (offs)
++                                      offs->multiple_bssid_offset = skb->len - multiple_bssid_len;
++                      }
++
+                       if (beacon->tail)
+                               skb_put_data(skb, beacon->tail,
+                                            beacon->tail_len);
+                       if (ieee80211_beacon_protect(skb, local, sdata) < 0)
+-                              goto out;
++                              return NULL;
+               } else
+-                      goto out;
++                      return NULL;
+       } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+               struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+               struct ieee80211_hdr *hdr;
+               beacon = rcu_dereference(ifibss->presp);
+               if (!beacon)
+-                      goto out;
++                      return NULL;
+               if (beacon->csa_counter_offsets[0]) {
+                       if (!is_template)
+@@ -4809,7 +4863,7 @@ __ieee80211_beacon_get(struct ieee80211_
+               skb = dev_alloc_skb(local->tx_headroom + beacon->head_len +
+                                   local->hw.extra_beacon_tailroom);
+               if (!skb)
+-                      goto out;
++                      return NULL;
+               skb_reserve(skb, local->tx_headroom);
+               skb_put_data(skb, beacon->head, beacon->head_len);
+@@ -4821,7 +4875,7 @@ __ieee80211_beacon_get(struct ieee80211_
+               beacon = rcu_dereference(ifmsh->beacon);
+               if (!beacon)
+-                      goto out;
++                      return NULL;
+               if (beacon->csa_counter_offsets[0]) {
+                       if (!is_template)
+@@ -4844,7 +4898,7 @@ __ieee80211_beacon_get(struct ieee80211_
+                                   beacon->tail_len +
+                                   local->hw.extra_beacon_tailroom);
+               if (!skb)
+-                      goto out;
++                      return NULL;
+               skb_reserve(skb, local->tx_headroom);
+               skb_put_data(skb, beacon->head, beacon->head_len);
+               ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb, is_template);
+@@ -4857,7 +4911,7 @@ __ieee80211_beacon_get(struct ieee80211_
+               skb_put_data(skb, beacon->tail, beacon->tail_len);
+       } else {
+               WARN_ON(1);
+-              goto out;
++              return NULL;
+       }
+       /* CSA offsets */
+@@ -4900,8 +4954,6 @@ __ieee80211_beacon_get(struct ieee80211_
+       info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT |
+                       IEEE80211_TX_CTL_ASSIGN_SEQ |
+                       IEEE80211_TX_CTL_FIRST_FRAGMENT;
+- out:
+-      rcu_read_unlock();
+       return skb;
+ }
+@@ -4911,16 +4963,86 @@ ieee80211_beacon_get_template(struct iee
+                             struct ieee80211_vif *vif,
+                             struct ieee80211_mutable_offsets *offs)
+ {
+-      return __ieee80211_beacon_get(hw, vif, offs, true);
++      struct sk_buff *bcn;
++
++      rcu_read_lock();
++      bcn = __ieee80211_beacon_get(hw, vif, offs, true,
++                                   IEEE80211_BCN_EMA_NONE);
++      rcu_read_unlock();
++
++      return bcn;
+ }
+ EXPORT_SYMBOL(ieee80211_beacon_get_template);
++struct sk_buff *
++ieee80211_beacon_get_template_ema_next(struct ieee80211_hw *hw,
++                                     struct ieee80211_vif *vif,
++                                     struct ieee80211_mutable_offsets *offs)
++{
++      struct sk_buff *bcn;
++
++      rcu_read_lock();
++      bcn = __ieee80211_beacon_get(hw, vif, offs, true,
++                                   IEEE80211_BCN_EMA_NEXT);
++      rcu_read_unlock();
++
++      return bcn;
++}
++EXPORT_SYMBOL(ieee80211_beacon_get_template_ema_next);
++
++void
++ieee80211_beacon_free_ema_list(struct list_head *head)
++{
++      struct ieee80211_ema_bcn_list *ema, *tmp;
++
++      list_for_each_entry_safe(ema, tmp, head, list) {
++              kfree_skb(ema->skb);
++              kfree(ema);
++      }
++}
++EXPORT_SYMBOL(ieee80211_beacon_free_ema_list);
++
++int
++ieee80211_beacon_get_template_ema_list(struct ieee80211_hw *hw,
++                                     struct ieee80211_vif *vif,
++                                     struct list_head *head)
++{
++      int cnt = 0;
++
++      rcu_read_lock();
++      while (true) {
++              struct ieee80211_ema_bcn_list *ema;
++
++              ema = kmalloc(sizeof(*ema), GFP_KERNEL);
++              if (!ema) {
++                      ieee80211_beacon_free_ema_list(head);
++                      cnt = 0;
++                      goto out;
++              }
++
++              ema->skb = __ieee80211_beacon_get(hw, vif, &ema->offs, true,
++                                                cnt);
++              if (!ema->skb) {
++                      kfree(ema);
++                      break;
++              }
++              list_add_tail(&ema->list, head);
++              cnt++;
++      }
++out:
++      rcu_read_unlock();
++
++      return cnt;
++}
++EXPORT_SYMBOL(ieee80211_beacon_get_template_ema_list);
++
+ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
+                                        struct ieee80211_vif *vif,
+                                        u16 *tim_offset, u16 *tim_length)
+ {
+       struct ieee80211_mutable_offsets offs = {};
+-      struct sk_buff *bcn = __ieee80211_beacon_get(hw, vif, &offs, false);
++      struct sk_buff *bcn = __ieee80211_beacon_get(hw, vif, &offs, false,
++                                                   IEEE80211_BCN_EMA_NONE);
+       struct sk_buff *copy;
+       struct ieee80211_supported_band *sband;
+       int shift;
diff --git a/package/kernel/mac80211/patches/subsys/603-mac80211-dont-allow-CS-on-non-transmitting-interface.patch b/package/kernel/mac80211/patches/subsys/603-mac80211-dont-allow-CS-on-non-transmitting-interface.patch
new file mode 100644 (file)
index 0000000..e945fc1
--- /dev/null
@@ -0,0 +1,31 @@
+From 73dbc6576a517c288395e7da1be98c47c85ab2f9 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 6 Oct 2020 17:22:39 +0200
+Subject: [PATCH 4/4] mac80211: dont allow CS on non-transmitting interfaces
+
+As a non-transmitting interface does not broadcast a beacon, we do not want
+to all channel switch announcements. They need to be triggerd on the
+transmitting interface.
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ net/mac80211/cfg.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
+index ee381557b1d8..1fc708b66b5e 100644
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -3506,6 +3506,9 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
+       if (sdata->vif.csa_active)
+               return -EBUSY;
++      if (sdata->vif.multiple_bssid.flags & IEEE80211_VIF_MBSS_NON_TRANSMITTING)
++              return -EINVAL;
++
+       mutex_lock(&local->chanctx_mtx);
+       conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+                                        lockdep_is_held(&local->chanctx_mtx));
+-- 
+2.25.1
+
diff --git a/package/kernel/mac80211/patches/subsys/604-mbssid-ie.patch b/package/kernel/mac80211/patches/subsys/604-mbssid-ie.patch
new file mode 100644 (file)
index 0000000..99d906f
--- /dev/null
@@ -0,0 +1,31 @@
+Index: backports-5.8-1/net/mac80211/tx.c
+===================================================================
+--- backports-5.8-1.orig/net/mac80211/tx.c
++++ backports-5.8-1/net/mac80211/tx.c
+@@ -4833,8 +4833,25 @@ __ieee80211_beacon_get(struct ieee80211_
+                                               skb_put_data(skb, beacon->multiple_bssid.ies[i],
+                                                            beacon->multiple_bssid.len[i]);
+                               }
+-                              if (offs)
++                              if (offs) {
++                                      const struct element *elem, *sub;
++                                      u8 *start;
++                                      int len;
++
+                                       offs->multiple_bssid_offset = skb->len - multiple_bssid_len;
++
++                                      start = &skb->data[offs->multiple_bssid_offset];
++                                      len = skb->len - offs->multiple_bssid_offset;
++                                      for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, start, skb->len - len) {
++                                              printk("%s:%s[%d]max_bssid_id %d\n", __FILE__, __func__, __LINE__, *elem->data);
++
++                                              for_each_element(sub, elem->data + 1, elem->datalen - 1) {
++                                                      if (sub->id)
++                                                              continue;
++                                                      printk("%s:%s[%d]non transmitted offset %d\n", __FILE__, __func__, __LINE__, (u8 *)sub - skb->data);
++                                              }
++                                      }
++                              }
+                       }
+                       if (beacon->tail)