From patchwork Fri Oct 9 10:15:25 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Crispin X-Patchwork-Id: 11825505 X-Patchwork-Delegate: johannes@sipsolutions.net Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id EFB12109B for ; Fri, 9 Oct 2020 10:15:33 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D8B6E222B8 for ; Fri, 9 Oct 2020 10:15:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387547AbgJIKPd (ORCPT ); Fri, 9 Oct 2020 06:15:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42232 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2387565AbgJIKPc (ORCPT ); Fri, 9 Oct 2020 06:15:32 -0400 Received: from nbd.name (nbd.name [IPv6:2a01:4f8:221:3d45::2]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 223C3C0613D2 for ; Fri, 9 Oct 2020 03:15:32 -0700 (PDT) Received: from [134.101.218.207] (helo=localhost.localdomain) by ds12 with esmtpa (Exim 4.89) (envelope-from ) id 1kQpQv-0004jy-Or; Fri, 09 Oct 2020 12:15:30 +0200 From: John Crispin To: Johannes Berg Cc: linux-wireless@vger.kernel.org, John Crispin , Aloka Dixit Subject: [PATCH V4 1/4] nl80211: add basic multiple bssid support Date: Fri, 9 Oct 2020 12:15:25 +0200 Message-Id: <20201009101528.4780-2-john@phrozen.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201009101528.4780-1-john@phrozen.org> References: <20201009101528.4780-1-john@phrozen.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org This patch adds support for passing the multiple bssid config to the kernel when adding an AP gets started. If the BSS is non-transmitting we need to pass the ifidx of the transmitting parent. The multiple bssid elements are passed as an array inside the beacon data. This allows use to generate multiple bssid beacons aswell as EMA ones. Signed-off-by: Aloka Dixit Signed-off-by: John Crispin --- include/net/cfg80211.h | 33 +++++++++++++++++++++++++++++++++ include/uapi/linux/nl80211.h | 21 +++++++++++++++++++++ net/wireless/nl80211.c | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index aee47f2b5709..20782e9c5aaa 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -496,6 +496,21 @@ struct ieee80211_supported_band { const struct ieee80211_sband_iftype_data *iftype_data; }; +/** + * 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 @@ -1027,6 +1042,19 @@ struct cfg80211_crypto_settings { u8 sae_pwd_len; }; +/** + * 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) @@ -1053,6 +1081,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; @@ -1071,6 +1100,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 { @@ -1175,6 +1206,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 + * @multiple_bssid: AP settings for multiple bssid */ struct cfg80211_ap_settings { struct cfg80211_chan_def chandef; @@ -1207,6 +1239,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 ieee80211_multiple_bssid multiple_bssid; }; /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 47700a2b9af9..91b338b0b9cb 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2527,6 +2527,19 @@ enum nl80211_commands { * override mask. Used with NL80211_ATTR_S1G_CAPABILITY in * NL80211_CMD_ASSOCIATE or NL80211_CMD_CONNECT. * + * @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 @@ -3016,6 +3029,12 @@ enum nl80211_attrs { NL80211_ATTR_S1G_CAPABILITY, NL80211_ATTR_S1G_CAPABILITY_MASK, + 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, @@ -3079,6 +3098,8 @@ enum nl80211_attrs { #define NL80211_CQM_TXE_MAX_INTVL 1800 +#define NL80211_MULTIPLE_BSSID_IES_MAX 8 + /** * enum nl80211_iftype - (virtual) interface types * diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 91d4550677d0..ecaa4c8879f3 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -715,6 +715,11 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { NLA_POLICY_EXACT_LEN(IEEE80211_S1G_CAPABILITY_LEN), [NL80211_ATTR_S1G_CAPABILITY_MASK] = NLA_POLICY_EXACT_LEN(IEEE80211_S1G_CAPABILITY_LEN), + [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 */ @@ -4864,6 +4869,21 @@ static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev, 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; } @@ -5318,6 +5338,20 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) return err; } + 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(¶ms); if (info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT]) From patchwork Fri Oct 9 10:15:26 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Crispin X-Patchwork-Id: 11825507 X-Patchwork-Delegate: johannes@sipsolutions.net Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A7DED17CA for ; Fri, 9 Oct 2020 10:15:34 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9231022276 for ; Fri, 9 Oct 2020 10:15:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387571AbgJIKPd (ORCPT ); Fri, 9 Oct 2020 06:15:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42234 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2387562AbgJIKPc (ORCPT ); Fri, 9 Oct 2020 06:15:32 -0400 Received: from nbd.name (nbd.name [IPv6:2a01:4f8:221:3d45::2]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 67798C0613D4 for ; Fri, 9 Oct 2020 03:15:32 -0700 (PDT) Received: from [134.101.218.207] (helo=localhost.localdomain) by ds12 with esmtpa (Exim 4.89) (envelope-from ) id 1kQpQw-0004jy-80; Fri, 09 Oct 2020 12:15:30 +0200 From: John Crispin To: Johannes Berg Cc: linux-wireless@vger.kernel.org, John Crispin , Aloka Dixit Subject: [PATCH V4 2/4] mac80211: add multiple bssid support to interface handling Date: Fri, 9 Oct 2020 12:15:26 +0200 Message-Id: <20201009101528.4780-3-john@phrozen.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201009101528.4780-1-john@phrozen.org> References: <20201009101528.4780-1-john@phrozen.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org When bringing up multi bssid APs we need to track the parent-child relation aswell as figuring out if the BSS is (non-)transmitting. The new helper function ieee80211_set_multiple_bssid_options() takes care of storing the config as well as figuring out the runtime flags of the virtual interface. The patch also makes sure that when a parent is closed, its children are also closed. Signed-off-by: Aloka Dixit Signed-off-by: John Crispin --- 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(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 4747d446179a..fef9c893f757 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -628,6 +628,7 @@ struct ieee80211_fils_discovery { * @unsol_bcast_probe_resp_interval: Unsolicited broadcast probe response * interval. * @s1g: BSS is S1G BSS (affects Association Request format). + * @multiple_bssid: the multiple bssid settings of the AP. */ struct ieee80211_bss_conf { const u8 *bssid; @@ -698,6 +699,7 @@ struct ieee80211_bss_conf { struct ieee80211_fils_discovery fils_discovery; u32 unsol_bcast_probe_resp_interval; bool s1g; + struct ieee80211_multiple_bssid multiple_bssid; }; /** @@ -1650,6 +1652,20 @@ enum ieee80211_offload_flags { IEEE80211_OFFLOAD_ENCAP_4ADDR = BIT(1), }; +/** + * 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 * @@ -1696,6 +1712,9 @@ enum ieee80211_offload_flags { * protected by fq->lock. * @offload_flags: 802.3 -> 802.11 enapsulation offload flags, see * &enum ieee80211_offload_flags. + * @multiple_bssid.parent: a non-transmitted bssid has a transmitted parent. + * @multiple_bssid.flags: multiple bssid flags, see + * &enum ieee80211_vif_multiple_bssid_flags */ struct ieee80211_vif { enum nl80211_iftype type; @@ -1723,6 +1742,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 *)); @@ -2371,7 +2394,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. @@ -2383,6 +2406,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 { @@ -2436,6 +2461,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 diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index da70f174d629..3e81241e709f 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -111,6 +111,39 @@ static int ieee80211_set_mon_options(struct ieee80211_sub_if_data *sdata, 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_add_iface(struct wiphy *wiphy, 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 && 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; @@ -1076,6 +1126,9 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, changed |= BSS_CHANGED_HE_BSS_COLOR; } + if (sdata->vif.type == NL80211_IFTYPE_AP) + ieee80211_set_multiple_bssid_options(sdata, params); + mutex_lock(&local->mtx); err = ieee80211_vif_use_channel(sdata, ¶ms->chandef, IEEE80211_CHANCTX_SHARED); diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 90470392fdaa..ee5ead592835 100644 --- a/net/mac80211/debugfs.c +++ b/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 }; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 240862a74a0f..f29c59469257 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -377,6 +377,12 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, 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; From patchwork Fri Oct 9 10:15:27 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Crispin X-Patchwork-Id: 11825509 X-Patchwork-Delegate: johannes@sipsolutions.net Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1CE6A109B for ; Fri, 9 Oct 2020 10:15:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id EA082222B8 for ; Fri, 9 Oct 2020 10:15:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387575AbgJIKPe (ORCPT ); Fri, 9 Oct 2020 06:15:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42240 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2387570AbgJIKPd (ORCPT ); Fri, 9 Oct 2020 06:15:33 -0400 Received: from nbd.name (nbd.name [IPv6:2a01:4f8:221:3d45::2]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0D463C0613D2 for ; Fri, 9 Oct 2020 03:15:33 -0700 (PDT) Received: from [134.101.218.207] (helo=localhost.localdomain) by ds12 with esmtpa (Exim 4.89) (envelope-from ) id 1kQpQw-0004jy-FM; Fri, 09 Oct 2020 12:15:30 +0200 From: John Crispin To: Johannes Berg Cc: linux-wireless@vger.kernel.org, John Crispin , Aloka Dixit Subject: [PATCH V4 3/4] mac80211: add multiple bssid/EMA support to beacon handling Date: Fri, 9 Oct 2020 12:15:27 +0200 Message-Id: <20201009101528.4780-4-john@phrozen.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201009101528.4780-1-john@phrozen.org> References: <20201009101528.4780-1-john@phrozen.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org 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 multiple bssid/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 upon completion events. In case the HW can do full EMA offload, functions are provided that allow the driver to get a list of the periodicity number of beacons and their matching mutable offsets. Signed-off-by: Aloka Dixit Signed-off-by: John Crispin --- include/net/mac80211.h | 90 +++++++++++++++++++++ net/mac80211/cfg.c | 57 +++++++++++++- net/mac80211/ieee80211_i.h | 2 + net/mac80211/tx.c | 157 +++++++++++++++++++++++++++++++++---- 4 files changed, 286 insertions(+), 20 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index fef9c893f757..0116d6539109 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -4862,12 +4862,17 @@ void ieee80211_report_low_ack(struct ieee80211_sta *sta, u32 num_packets); * @cntdwn_counter_offs: array of IEEE80211_MAX_CNTDWN_COUNTERS_NUM offsets * to countdown counters. This array can contain zero values which * should be ignored. + * @multiple_bssid_offset: position of the multiple bssid element + * @multiple_bssid_length: size of the multiple bssid element */ struct ieee80211_mutable_offsets { u16 tim_offset; u16 tim_length; u16 cntdwn_counter_offs[IEEE80211_MAX_CNTDWN_COUNTERS_NUM]; + + u16 multiple_bssid_offset; + u16 multiple_bssid_length; }; /** @@ -4894,6 +4899,91 @@ ieee80211_beacon_get_template(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 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(). diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 3e81241e709f..11cecb2ed640 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -982,12 +982,38 @@ static int ieee80211_set_ftm_responder_params( 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; @@ -1011,7 +1037,15 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, 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(¶ms->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) @@ -1028,6 +1062,18 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, 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, + ¶ms->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->cntdwn_current_counter = csa->count; memcpy(new->cntdwn_counter_offsets, csa->counter_offsets_beacon, @@ -3091,7 +3137,8 @@ cfg80211_beacon_dup(struct cfg80211_beacon_data *beacon) 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) @@ -3134,6 +3181,10 @@ cfg80211_beacon_dup(struct cfg80211_beacon_data *beacon) 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; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c3e3578574a6..dfcb7dda1d39 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -261,6 +261,8 @@ struct beacon_data { struct ieee80211_meshconf_ie *meshconf; u16 cntdwn_counter_offsets[IEEE80211_MAX_CNTDWN_COUNTERS_NUM]; u8 cntdwn_current_counter; + struct cfg80211_multiple_bssid_data multiple_bssid; + u16 ema_index; struct rcu_head rcu_head; }; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 8ba10a48ded4..f21827b70dff 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -4735,11 +4735,26 @@ static int ieee80211_beacon_protect(struct sk_buff *skb, 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; @@ -4751,13 +4766,11 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, 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)); @@ -4767,6 +4780,8 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, beacon = rcu_dereference(ap->beacon); if (beacon) { + int multiple_bssid_len = 0; + if (beacon->cntdwn_counter_offsets[0]) { if (!is_template) ieee80211_beacon_update_cntdwn(vif); @@ -4774,6 +4789,27 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, ieee80211_set_beacon_cntdwn(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 @@ -4781,9 +4817,10 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, 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); @@ -4799,21 +4836,39 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, 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->cntdwn_counter_offsets[0]) { if (!is_template) @@ -4825,7 +4880,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, 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); @@ -4837,7 +4892,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, beacon = rcu_dereference(ifmsh->beacon); if (!beacon) - goto out; + return NULL; if (beacon->cntdwn_counter_offsets[0]) { if (!is_template) @@ -4860,7 +4915,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, 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); @@ -4873,7 +4928,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, skb_put_data(skb, beacon->tail, beacon->tail_len); } else { WARN_ON(1); - goto out; + return NULL; } /* CSA offsets */ @@ -4916,8 +4971,6 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT | IEEE80211_TX_CTL_ASSIGN_SEQ | IEEE80211_TX_CTL_FIRST_FRAGMENT; - out: - rcu_read_unlock(); return skb; } @@ -4927,16 +4980,86 @@ ieee80211_beacon_get_template(struct ieee80211_hw *hw, 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; From patchwork Fri Oct 9 10:15:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Crispin X-Patchwork-Id: 11825511 X-Patchwork-Delegate: johannes@sipsolutions.net Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 41C2217CA for ; Fri, 9 Oct 2020 10:15:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3137F222B9 for ; Fri, 9 Oct 2020 10:15:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387573AbgJIKPe (ORCPT ); Fri, 9 Oct 2020 06:15:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42238 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2387569AbgJIKPd (ORCPT ); Fri, 9 Oct 2020 06:15:33 -0400 Received: from nbd.name (nbd.name [IPv6:2a01:4f8:221:3d45::2]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2DDFCC0613D4 for ; Fri, 9 Oct 2020 03:15:33 -0700 (PDT) Received: from [134.101.218.207] (helo=localhost.localdomain) by ds12 with esmtpa (Exim 4.89) (envelope-from ) id 1kQpQw-0004jy-Vo; Fri, 09 Oct 2020 12:15:31 +0200 From: John Crispin To: Johannes Berg Cc: linux-wireless@vger.kernel.org, John Crispin , Aloka Dixit Subject: [PATCH V4 4/4] mac80211: don't allow CSA on non-transmitting interfaces Date: Fri, 9 Oct 2020 12:15:28 +0200 Message-Id: <20201009101528.4780-5-john@phrozen.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201009101528.4780-1-john@phrozen.org> References: <20201009101528.4780-1-john@phrozen.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org As a non-transmitting interface does not broadcast a beacon, we do not want to allow channel switch announcements. They need to be triggered on the transmitting interface. Signed-off-by: Aloka Dixit Signed-off-by: John Crispin --- net/mac80211/cfg.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 11cecb2ed640..7693894c4f84 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3504,6 +3504,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));