* [PATCH 01/10] mac80211: Add support for declaring MU-MIMO capability
2015-07-08 12:41 [PATCH 00/10] random patches to mac80211 Emmanuel Grumbach
@ 2015-07-08 12:41 ` Emmanuel Grumbach
2015-07-08 12:41 ` [PATCH 02/10] cfg80211: use RTNL locked reg_can_beacon for IR-relaxation Emmanuel Grumbach
` (8 subsequent siblings)
9 siblings, 0 replies; 18+ messages in thread
From: Emmanuel Grumbach @ 2015-07-08 12:41 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Sara Sharon, Emmanuel Grumbach
From: Sara Sharon <sara.sharon@intel.com>
Add support for declaring MU-MIMO beamformee capability for
relevant hardware.
When sending association request, the capability is included if both
hardware and the AP support it, and no other virtual interface
is using it.
This is in order to avoid multiple interfaces using MU-MIMO in parallel
which might lead to contradictions in the group-id mechanism.
Signed-off-by: Sara Sharon <sara.sharon@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
---
net/mac80211/ieee80211_i.h | 2 ++
net/mac80211/mlme.c | 37 ++++++++++++++++++++++++++++++++++++-
2 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 52930e9..90580e9 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -721,6 +721,7 @@ struct ieee80211_if_mesh {
* back to wireless media and to the local net stack.
* @IEEE80211_SDATA_DISCONNECT_RESUME: Disconnect after resume.
* @IEEE80211_SDATA_IN_DRIVER: indicates interface was added to driver
+ * @IEEE80211_SDATA_MU_MIMO_OWNER: indicates interface owns MU-MIMO capability
*/
enum ieee80211_sub_if_data_flags {
IEEE80211_SDATA_ALLMULTI = BIT(0),
@@ -728,6 +729,7 @@ enum ieee80211_sub_if_data_flags {
IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(3),
IEEE80211_SDATA_DISCONNECT_RESUME = BIT(4),
IEEE80211_SDATA_IN_DRIVER = BIT(5),
+ IEEE80211_SDATA_MU_MIMO_OWNER = BIT(6),
};
/**
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 6332ff7..705ef1d 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -6,6 +6,7 @@
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH
+ * Copyright (C) 2015 Intel Deutschland GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -538,11 +539,16 @@ static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
ieee80211_ie_build_ht_cap(pos, &ht_cap, cap);
}
+/* This function determines vht capability flags for the association
+ * and builds the IE.
+ * Note - the function may set the owner of the MU-MIMO capability
+ */
static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb,
struct ieee80211_supported_band *sband,
struct ieee80211_vht_cap *ap_vht_cap)
{
+ struct ieee80211_local *local = sdata->local;
u8 *pos;
u32 cap;
struct ieee80211_sta_vht_cap vht_cap;
@@ -576,7 +582,34 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
*/
if (!(ap_vht_cap->vht_cap_info &
cpu_to_le32(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)))
- cap &= ~IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
+ cap &= ~(IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
+ IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
+ else if (!(ap_vht_cap->vht_cap_info &
+ cpu_to_le32(IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)))
+ cap &= ~IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+
+ /*
+ * If some other vif is using the MU-MIMO capablity we cannot associate
+ * using MU-MIMO - this will lead to contradictions in the group-id
+ * mechanism.
+ * Ownership is defined since association request, in order to avoid
+ * simultaneous associations with MU-MIMO.
+ */
+ if (cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) {
+ bool disable_mu_mimo = false;
+ struct ieee80211_sub_if_data *other;
+
+ list_for_each_entry_rcu(other, &local->interfaces, list) {
+ if (other->flags & IEEE80211_SDATA_MU_MIMO_OWNER) {
+ disable_mu_mimo = true;
+ break;
+ }
+ }
+ if (disable_mu_mimo)
+ cap &= ~IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+ else
+ sdata->flags |= IEEE80211_SDATA_MU_MIMO_OWNER;
+ }
mask = IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
@@ -2058,6 +2091,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask));
memset(&ifmgd->vht_capa, 0, sizeof(ifmgd->vht_capa));
memset(&ifmgd->vht_capa_mask, 0, sizeof(ifmgd->vht_capa_mask));
+ sdata->flags &= ~IEEE80211_SDATA_MU_MIMO_OWNER;
sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
@@ -2520,6 +2554,7 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
eth_zero_addr(sdata->u.mgd.bssid);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
sdata->u.mgd.flags = 0;
+ sdata->flags &= ~IEEE80211_SDATA_MU_MIMO_OWNER;
mutex_lock(&sdata->local->mtx);
ieee80211_vif_release_channel(sdata);
mutex_unlock(&sdata->local->mtx);
--
2.1.4
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 02/10] cfg80211: use RTNL locked reg_can_beacon for IR-relaxation
2015-07-08 12:41 [PATCH 00/10] random patches to mac80211 Emmanuel Grumbach
2015-07-08 12:41 ` [PATCH 01/10] mac80211: Add support for declaring MU-MIMO capability Emmanuel Grumbach
@ 2015-07-08 12:41 ` Emmanuel Grumbach
2015-07-17 13:18 ` Johannes Berg
2015-07-08 12:41 ` [PATCH 03/10] mac80211: TDLS: handle chan-switch in RTNL locked work Emmanuel Grumbach
` (7 subsequent siblings)
9 siblings, 1 reply; 18+ messages in thread
From: Emmanuel Grumbach @ 2015-07-08 12:41 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Arik Nemtsov, Arik Nemtsov, Emmanuel Grumbach
From: Arik Nemtsov <arik@wizery.com>
The RTNL is required to check for IR-relaxation conditions that allow
more channels to beacon. Export an RTNL locked version of reg_can_beacon
and use it where possible in AP/STA interface type flows, where
IR-relaxation may be applicable.
Fixes: 06f207fc5418 ("cfg80211: change GO_CONCURRENT to IR_CONCURRENT for STA")
Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
---
include/net/cfg80211.h | 17 +++++++++++++++++
net/mac80211/tdls.c | 6 +++---
net/wireless/chan.c | 45 ++++++++++++++++++++++++++++++++++-----------
net/wireless/nl80211.c | 14 ++++++++------
net/wireless/reg.c | 2 +-
net/wireless/trace.h | 11 +++++++----
6 files changed, 70 insertions(+), 25 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 9a529c4..f0889a2 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4867,6 +4867,23 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef,
enum nl80211_iftype iftype);
+/**
+ * cfg80211_reg_can_beacon_relax - check if beaconing is allowed with relaxation
+ * @wiphy: the wiphy
+ * @chandef: the channel definition
+ * @iftype: interface type
+ *
+ * Return: %true if there is no secondary channel or the secondary channel(s)
+ * can be used for beaconing (i.e. is not a radar channel etc.). This version
+ * also checks if IR-relaxation conditions apply, to allow beaconing under
+ * more permissive conditions.
+ *
+ * Requires the RTNL to be held.
+ */
+bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
+ struct cfg80211_chan_def *chandef,
+ enum nl80211_iftype iftype);
+
/*
* cfg80211_ch_switch_notify - update wdev channel and notify userspace
* @dev: the device which switched channels
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
index 8536789..20c9dbd 100644
--- a/net/mac80211/tdls.c
+++ b/net/mac80211/tdls.c
@@ -69,6 +69,7 @@ ieee80211_tdls_add_subband(struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel *ch;
struct cfg80211_chan_def chandef;
int i, subband_start;
+ struct wiphy *wiphy = sdata->local->hw.wiphy;
for (i = start; i <= end; i += spacing) {
if (!ch_cnt)
@@ -79,9 +80,8 @@ ieee80211_tdls_add_subband(struct ieee80211_sub_if_data *sdata,
/* we will be active on the channel */
cfg80211_chandef_create(&chandef, ch,
NL80211_CHAN_NO_HT);
- if (cfg80211_reg_can_beacon(sdata->local->hw.wiphy,
- &chandef,
- sdata->wdev.iftype)) {
+ if (cfg80211_reg_can_beacon_relax(wiphy, &chandef,
+ sdata->wdev.iftype)) {
ch_cnt++;
/*
* check if the next channel is also part of
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 915b328..59cabc9 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -797,23 +797,18 @@ static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy,
return false;
}
-bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
- struct cfg80211_chan_def *chandef,
- enum nl80211_iftype iftype)
+static bool _cfg80211_reg_can_beacon(struct wiphy *wiphy,
+ struct cfg80211_chan_def *chandef,
+ enum nl80211_iftype iftype,
+ bool check_no_ir)
{
bool res;
u32 prohibited_flags = IEEE80211_CHAN_DISABLED |
IEEE80211_CHAN_RADAR;
- trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype);
+ trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
- /*
- * Under certain conditions suggested by some regulatory bodies a
- * GO/STA can IR on channels marked with IEEE80211_NO_IR. Set this flag
- * only if such relaxations are not enabled and the conditions are not
- * met.
- */
- if (!cfg80211_ir_permissive_chan(wiphy, iftype, chandef->chan))
+ if (check_no_ir)
prohibited_flags |= IEEE80211_CHAN_NO_IR;
if (cfg80211_chandef_dfs_required(wiphy, chandef, iftype) > 0 &&
@@ -827,8 +822,36 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
trace_cfg80211_return_bool(res);
return res;
}
+
+bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
+ struct cfg80211_chan_def *chandef,
+ enum nl80211_iftype iftype)
+{
+ return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, true);
+}
EXPORT_SYMBOL(cfg80211_reg_can_beacon);
+bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
+ struct cfg80211_chan_def *chandef,
+ enum nl80211_iftype iftype)
+{
+ bool check_no_ir;
+
+ ASSERT_RTNL();
+
+ /*
+ * Under certain conditions suggested by some regulatory bodies a
+ * GO/STA can IR on channels marked with IEEE80211_NO_IR. Set this flag
+ * only if such relaxations are not enabled and the conditions are not
+ * met.
+ */
+ check_no_ir = !cfg80211_ir_permissive_chan(wiphy, iftype,
+ chandef->chan);
+
+ return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
+}
+EXPORT_SYMBOL(cfg80211_reg_can_beacon_relax);
+
int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
struct cfg80211_chan_def *chandef)
{
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c264eff..76b4157 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2003,7 +2003,8 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
switch (iftype) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
- if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, iftype)) {
+ if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
+ iftype)) {
result = -EINVAL;
break;
}
@@ -3403,8 +3404,8 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
} else if (!nl80211_get_ap_channel(rdev, ¶ms))
return -EINVAL;
- if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef,
- wdev->iftype))
+ if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, ¶ms.chandef,
+ wdev->iftype))
return -EINVAL;
if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
@@ -6492,8 +6493,8 @@ skip_beacons:
if (err)
return err;
- if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef,
- wdev->iftype))
+ if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, ¶ms.chandef,
+ wdev->iftype))
return -EINVAL;
err = cfg80211_chandef_dfs_required(wdev->wiphy,
@@ -10170,7 +10171,8 @@ static int nl80211_tdls_channel_switch(struct sk_buff *skb,
return -EINVAL;
/* we will be active on the TDLS link */
- if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, wdev->iftype))
+ if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
+ wdev->iftype))
return -EINVAL;
/* don't allow switching to DFS channels */
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 62d8ea4..847da65 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1589,7 +1589,7 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
case NL80211_IFTYPE_ADHOC:
- return cfg80211_reg_can_beacon(wiphy, &chandef, iftype);
+ return cfg80211_reg_can_beacon_relax(wiphy, &chandef, iftype);
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT:
return cfg80211_chandef_usable(wiphy, &chandef,
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index af3617c..a808279 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -2358,20 +2358,23 @@ TRACE_EVENT(cfg80211_cqm_rssi_notify,
TRACE_EVENT(cfg80211_reg_can_beacon,
TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef,
- enum nl80211_iftype iftype),
- TP_ARGS(wiphy, chandef, iftype),
+ enum nl80211_iftype iftype, bool check_no_ir),
+ TP_ARGS(wiphy, chandef, iftype, check_no_ir),
TP_STRUCT__entry(
WIPHY_ENTRY
CHAN_DEF_ENTRY
__field(enum nl80211_iftype, iftype)
+ __field(bool, check_no_ir)
),
TP_fast_assign(
WIPHY_ASSIGN;
CHAN_DEF_ASSIGN(chandef);
__entry->iftype = iftype;
+ __entry->check_no_ir = check_no_ir;
),
- TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", iftype=%d",
- WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->iftype)
+ TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", iftype=%d check_no_ir=%s",
+ WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->iftype,
+ BOOL_TO_STR(__entry->check_no_ir))
);
TRACE_EVENT(cfg80211_chandef_dfs_required,
--
2.1.4
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 03/10] mac80211: TDLS: handle chan-switch in RTNL locked work
2015-07-08 12:41 [PATCH 00/10] random patches to mac80211 Emmanuel Grumbach
2015-07-08 12:41 ` [PATCH 01/10] mac80211: Add support for declaring MU-MIMO capability Emmanuel Grumbach
2015-07-08 12:41 ` [PATCH 02/10] cfg80211: use RTNL locked reg_can_beacon for IR-relaxation Emmanuel Grumbach
@ 2015-07-08 12:41 ` Emmanuel Grumbach
2015-07-08 12:41 ` [PATCH 04/10] mac80211: TDLS: deny ch-switch req on disallowed channels Emmanuel Grumbach
` (6 subsequent siblings)
9 siblings, 0 replies; 18+ messages in thread
From: Emmanuel Grumbach @ 2015-07-08 12:41 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Arik Nemtsov, Arik Nemtsov, Emmanuel Grumbach
From: Arik Nemtsov <arik@wizery.com>
Move TDLS channel-switch Rx handling into an RTNL locked work. This is
required to add proper regulatory checking to incoming channel-switch
requests.
Queue incoming requests in a dedicated skb queue and handle the request
in a device-specific work to avoid deadlocking on interface removal.
Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
---
net/mac80211/ieee80211_i.h | 8 +++++---
net/mac80211/iface.c | 2 --
net/mac80211/main.c | 5 +++++
net/mac80211/rx.c | 5 ++---
net/mac80211/tdls.c | 34 ++++++++++++++++++++++++++++++++--
5 files changed, 44 insertions(+), 10 deletions(-)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 90580e9..36f217e 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1008,7 +1008,6 @@ enum sdata_queue_type {
IEEE80211_SDATA_QUEUE_AGG_STOP = 2,
IEEE80211_SDATA_QUEUE_RX_AGG_START = 3,
IEEE80211_SDATA_QUEUE_RX_AGG_STOP = 4,
- IEEE80211_SDATA_QUEUE_TDLS_CHSW = 5,
};
enum {
@@ -1351,6 +1350,10 @@ struct ieee80211_local {
/* extended capabilities provided by mac80211 */
u8 ext_capa[8];
+
+ /* TDLS channel switch */
+ struct work_struct tdls_chsw_work;
+ struct sk_buff_head skb_queue_tdls_chsw;
};
static inline struct ieee80211_sub_if_data *
@@ -2054,9 +2057,8 @@ int ieee80211_tdls_channel_switch(struct wiphy *wiphy, struct net_device *dev,
void ieee80211_tdls_cancel_channel_switch(struct wiphy *wiphy,
struct net_device *dev,
const u8 *addr);
-void ieee80211_process_tdls_channel_switch(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb);
void ieee80211_teardown_tdls_peers(struct ieee80211_sub_if_data *sdata);
+void ieee80211_tdls_chsw_work(struct work_struct *wk);
extern const struct ethtool_ops ieee80211_ethtool_ops;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index ed1edac..e648ea8 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1242,8 +1242,6 @@ static void ieee80211_iface_work(struct work_struct *work)
WLAN_BACK_RECIPIENT, 0,
false);
mutex_unlock(&local->sta_mtx);
- } else if (skb->pkt_type == IEEE80211_SDATA_QUEUE_TDLS_CHSW) {
- ieee80211_process_tdls_channel_switch(sdata, skb);
} else if (ieee80211_is_action(mgmt->frame_control) &&
mgmt->u.action.category == WLAN_CATEGORY_BACK) {
int len = skb->len;
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index dba0a86..ff79a13 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -629,6 +629,8 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
INIT_WORK(&local->sched_scan_stopped_work,
ieee80211_sched_scan_stopped_work);
+ INIT_WORK(&local->tdls_chsw_work, ieee80211_tdls_chsw_work);
+
spin_lock_init(&local->ack_status_lock);
idr_init(&local->ack_status_frames);
@@ -645,6 +647,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
skb_queue_head_init(&local->skb_queue);
skb_queue_head_init(&local->skb_queue_unreliable);
+ skb_queue_head_init(&local->skb_queue_tdls_chsw);
ieee80211_alloc_led_names(local);
@@ -1161,6 +1164,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
cancel_work_sync(&local->restart_work);
cancel_work_sync(&local->reconfig_filter);
+ cancel_work_sync(&local->tdls_chsw_work);
flush_work(&local->sched_scan_stopped_work);
ieee80211_clear_tx_pending(local);
@@ -1171,6 +1175,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
wiphy_warn(local->hw.wiphy, "skb_queue not empty\n");
skb_queue_purge(&local->skb_queue);
skb_queue_purge(&local->skb_queue_unreliable);
+ skb_queue_purge(&local->skb_queue_tdls_chsw);
destroy_workqueue(local->workqueue);
wiphy_unregister(local->hw.wiphy);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 3a14628..f673304 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2410,9 +2410,8 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
tf->category == WLAN_CATEGORY_TDLS &&
(tf->action_code == WLAN_TDLS_CHANNEL_SWITCH_REQUEST ||
tf->action_code == WLAN_TDLS_CHANNEL_SWITCH_RESPONSE)) {
- rx->skb->pkt_type = IEEE80211_SDATA_QUEUE_TDLS_CHSW;
- skb_queue_tail(&sdata->skb_queue, rx->skb);
- ieee80211_queue_work(&rx->local->hw, &sdata->work);
+ skb_queue_tail(&local->skb_queue_tdls_chsw, rx->skb);
+ schedule_work(&local->tdls_chsw_work);
if (rx->sta)
rx->sta->rx_packets++;
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
index 20c9dbd..91e86bf 100644
--- a/net/mac80211/tdls.c
+++ b/net/mac80211/tdls.c
@@ -12,6 +12,7 @@
#include <linux/ieee80211.h>
#include <linux/log2.h>
#include <net/cfg80211.h>
+#include <linux/rtnetlink.h>
#include "ieee80211_i.h"
#include "driver-ops.h"
@@ -1800,12 +1801,15 @@ out:
return ret;
}
-void ieee80211_process_tdls_channel_switch(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb)
+static void
+ieee80211_process_tdls_channel_switch(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb)
{
struct ieee80211_tdls_data *tf = (void *)skb->data;
struct wiphy *wiphy = sdata->local->hw.wiphy;
+ ASSERT_RTNL();
+
/* make sure the driver supports it */
if (!(wiphy->features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH))
return;
@@ -1847,3 +1851,29 @@ void ieee80211_teardown_tdls_peers(struct ieee80211_sub_if_data *sdata)
}
rcu_read_unlock();
}
+
+void ieee80211_tdls_chsw_work(struct work_struct *wk)
+{
+ struct ieee80211_local *local =
+ container_of(wk, struct ieee80211_local, tdls_chsw_work);
+ struct ieee80211_sub_if_data *sdata;
+ struct sk_buff *skb;
+ struct ieee80211_tdls_data *tf;
+
+ rtnl_lock();
+ while ((skb = skb_dequeue(&local->skb_queue_tdls_chsw))) {
+ tf = (struct ieee80211_tdls_data *)skb->data;
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ if (!ieee80211_sdata_running(sdata) ||
+ sdata->vif.type != NL80211_IFTYPE_STATION ||
+ !ether_addr_equal(tf->da, sdata->vif.addr))
+ continue;
+
+ ieee80211_process_tdls_channel_switch(sdata, skb);
+ break;
+ }
+
+ kfree_skb(skb);
+ }
+ rtnl_unlock();
+}
--
2.1.4
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 04/10] mac80211: TDLS: deny ch-switch req on disallowed channels
2015-07-08 12:41 [PATCH 00/10] random patches to mac80211 Emmanuel Grumbach
` (2 preceding siblings ...)
2015-07-08 12:41 ` [PATCH 03/10] mac80211: TDLS: handle chan-switch in RTNL locked work Emmanuel Grumbach
@ 2015-07-08 12:41 ` Emmanuel Grumbach
2015-07-08 12:41 ` [PATCH 05/10] mac80211: clear local->suspended before calling drv_resume() Emmanuel Grumbach
` (5 subsequent siblings)
9 siblings, 0 replies; 18+ messages in thread
From: Emmanuel Grumbach @ 2015-07-08 12:41 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Arik Nemtsov, Arik Nemtsov, Emmanuel Grumbach
From: Arik Nemtsov <arik@wizery.com>
If a TDLS station is not allowed to beacon on a channel, don't accept
a channel switch request to this channel.
Move channel building code up to avoid lockdep violations - reg_can_beacon
needs to take the wdev lock.
Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
---
net/mac80211/tdls.c | 49 +++++++++++++++++++++++++++++++------------------
1 file changed, 31 insertions(+), 18 deletions(-)
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
index 91e86bf..aee701a 100644
--- a/net/mac80211/tdls.c
+++ b/net/mac80211/tdls.c
@@ -1737,6 +1737,31 @@ ieee80211_process_tdls_channel_switch_req(struct ieee80211_sub_if_data *sdata,
return -EINVAL;
}
+ if (!elems.sec_chan_offs) {
+ chan_type = NL80211_CHAN_HT20;
+ } else {
+ switch (elems.sec_chan_offs->sec_chan_offs) {
+ case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+ chan_type = NL80211_CHAN_HT40PLUS;
+ break;
+ case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+ chan_type = NL80211_CHAN_HT40MINUS;
+ break;
+ default:
+ chan_type = NL80211_CHAN_HT20;
+ break;
+ }
+ }
+
+ cfg80211_chandef_create(&chandef, chan, chan_type);
+
+ /* we will be active on the TDLS link */
+ if (!cfg80211_reg_can_beacon_relax(sdata->local->hw.wiphy, &chandef,
+ sdata->wdev.iftype)) {
+ tdls_dbg(sdata, "TDLS chan switch to forbidden channel\n");
+ return -EINVAL;
+ }
+
mutex_lock(&local->sta_mtx);
sta = sta_info_get(sdata, tf->sa);
if (!sta || !test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) {
@@ -1757,27 +1782,15 @@ ieee80211_process_tdls_channel_switch_req(struct ieee80211_sub_if_data *sdata,
goto out;
}
- if (!sta->sta.ht_cap.ht_supported) {
- chan_type = NL80211_CHAN_NO_HT;
- } else if (!elems.sec_chan_offs) {
- chan_type = NL80211_CHAN_HT20;
- } else {
- switch (elems.sec_chan_offs->sec_chan_offs) {
- case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
- chan_type = NL80211_CHAN_HT40PLUS;
- break;
- case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
- chan_type = NL80211_CHAN_HT40MINUS;
- break;
- default:
- chan_type = NL80211_CHAN_HT20;
- break;
- }
+ /* peer should have known better */
+ if (!sta->sta.ht_cap.ht_supported && elems.sec_chan_offs &&
+ elems.sec_chan_offs->sec_chan_offs) {
+ tdls_dbg(sdata, "TDLS chan switch - wide chan unsupported\n");
+ ret = -ENOTSUPP;
+ goto out;
}
- cfg80211_chandef_create(&chandef, chan, chan_type);
params.chandef = &chandef;
-
params.switch_time = le16_to_cpu(elems.ch_sw_timing->switch_time);
params.switch_timeout = le16_to_cpu(elems.ch_sw_timing->switch_timeout);
--
2.1.4
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 05/10] mac80211: clear local->suspended before calling drv_resume()
2015-07-08 12:41 [PATCH 00/10] random patches to mac80211 Emmanuel Grumbach
` (3 preceding siblings ...)
2015-07-08 12:41 ` [PATCH 04/10] mac80211: TDLS: deny ch-switch req on disallowed channels Emmanuel Grumbach
@ 2015-07-08 12:41 ` Emmanuel Grumbach
2015-07-17 13:45 ` Johannes Berg
2015-07-08 12:41 ` [PATCH 06/10] mac80211: remove ieee80211_aes_cmac_calculate_k1_k2() Emmanuel Grumbach
` (4 subsequent siblings)
9 siblings, 1 reply; 18+ messages in thread
From: Emmanuel Grumbach @ 2015-07-08 12:41 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Eliad Peller, Eliad Peller, Emmanuel Grumbach
From: Eliad Peller <eliad@wizery.com>
Currently, mac80211 calls drv_resume() on wowlan resume,
but drops any incoming frame until local->suspended is
cleared later on.
This requires the low-level driver to support a new state,
in which it is expected to fully work (as it was resumed)
but not passing rx frames yet (as they will be dropped).
iwlwifi (and probably other drivers as well) has issues
supporting such mode.
Since in the wowlan case we already short-circuit
ieee80211_reconfig, there's nothing that prevents us from
clearing local->suspend before calling drv_resume(),
and letting the low-level driver work normally.
Signed-off-by: Eliad Peller <eliadx.peller@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
---
net/mac80211/util.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index e54596f9..1104421 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1716,16 +1716,24 @@ int ieee80211_reconfig(struct ieee80211_local *local)
struct ieee80211_sub_if_data *sched_scan_sdata;
struct cfg80211_sched_scan_request *sched_scan_req;
bool sched_scan_stopped = false;
+ bool suspended = local->suspended;
/* nothing to do if HW shouldn't run */
if (!local->open_count)
goto wake_up;
#ifdef CONFIG_PM
- if (local->suspended)
+ if (suspended)
local->resuming = true;
if (local->wowlan) {
+ /*
+ * In the wowlan case, both mac80211 and the device
+ * are functional when the resume op is called, so
+ * clear local->suspended so the device could operate
+ * normally (e.g. pass rx frames).
+ */
+ local->suspended = false;
res = drv_resume(local);
local->wowlan = false;
if (res < 0) {
@@ -1738,8 +1746,10 @@ int ieee80211_reconfig(struct ieee80211_local *local)
/*
* res is 1, which means the driver requested
* to go through a regular reset on wakeup.
+ * restore local->suspended in this case.
*/
reconfig_due_to_wowlan = true;
+ local->suspended = true;
}
#endif
@@ -1751,7 +1761,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
*/
res = drv_start(local);
if (res) {
- if (local->suspended)
+ if (suspended)
WARN(1, "Hardware became unavailable upon resume. This could be a software issue prior to suspend or a hardware issue.\n");
else
WARN(1, "Hardware became unavailable during restart.\n");
@@ -2045,10 +2055,10 @@ int ieee80211_reconfig(struct ieee80211_local *local)
* If this is for hw restart things are still running.
* We may want to change that later, however.
*/
- if (local->open_count && (!local->suspended || reconfig_due_to_wowlan))
+ if (local->open_count && (!suspended || reconfig_due_to_wowlan))
drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_RESTART);
- if (!local->suspended)
+ if (!suspended)
return 0;
#ifdef CONFIG_PM
--
2.1.4
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 06/10] mac80211: remove ieee80211_aes_cmac_calculate_k1_k2()
2015-07-08 12:41 [PATCH 00/10] random patches to mac80211 Emmanuel Grumbach
` (4 preceding siblings ...)
2015-07-08 12:41 ` [PATCH 05/10] mac80211: clear local->suspended before calling drv_resume() Emmanuel Grumbach
@ 2015-07-08 12:41 ` Emmanuel Grumbach
2015-07-17 13:43 ` Johannes Berg
2015-07-08 12:41 ` [PATCH 07/10] mac80211: add possibility to advertise 802.11 FTM support Emmanuel Grumbach
` (3 subsequent siblings)
9 siblings, 1 reply; 18+ messages in thread
From: Emmanuel Grumbach @ 2015-07-08 12:41 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
The iwlwifi driver was the only driver that used this, but as
it turns out it never needed it, so we can remove it.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
include/net/mac80211.h | 13 -------------
net/mac80211/aes_cmac.c | 17 -----------------
2 files changed, 30 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 484cc14..e3314e5 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -4331,19 +4331,6 @@ void ieee80211_get_tkip_p2k(struct ieee80211_key_conf *keyconf,
struct sk_buff *skb, u8 *p2k);
/**
- * ieee80211_aes_cmac_calculate_k1_k2 - calculate the AES-CMAC sub keys
- *
- * This function computes the two AES-CMAC sub-keys, based on the
- * previously installed master key.
- *
- * @keyconf: the parameter passed with the set key
- * @k1: a buffer to be filled with the 1st sub-key
- * @k2: a buffer to be filled with the 2nd sub-key
- */
-void ieee80211_aes_cmac_calculate_k1_k2(struct ieee80211_key_conf *keyconf,
- u8 *k1, u8 *k2);
-
-/**
* ieee80211_get_key_tx_seq - get key TX sequence counter
*
* @keyconf: the parameter passed with the set key
diff --git a/net/mac80211/aes_cmac.c b/net/mac80211/aes_cmac.c
index 4192806..bdf0790 100644
--- a/net/mac80211/aes_cmac.c
+++ b/net/mac80211/aes_cmac.c
@@ -145,20 +145,3 @@ void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm)
{
crypto_free_cipher(tfm);
}
-
-void ieee80211_aes_cmac_calculate_k1_k2(struct ieee80211_key_conf *keyconf,
- u8 *k1, u8 *k2)
-{
- u8 l[AES_BLOCK_SIZE] = {};
- struct ieee80211_key *key =
- container_of(keyconf, struct ieee80211_key, conf);
-
- crypto_cipher_encrypt_one(key->u.aes_cmac.tfm, l, l);
-
- memcpy(k1, l, AES_BLOCK_SIZE);
- gf_mulx(k1);
-
- memcpy(k2, k1, AES_BLOCK_SIZE);
- gf_mulx(k2);
-}
-EXPORT_SYMBOL(ieee80211_aes_cmac_calculate_k1_k2);
--
2.1.4
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PATCH 06/10] mac80211: remove ieee80211_aes_cmac_calculate_k1_k2()
2015-07-08 12:41 ` [PATCH 06/10] mac80211: remove ieee80211_aes_cmac_calculate_k1_k2() Emmanuel Grumbach
@ 2015-07-17 13:43 ` Johannes Berg
2015-08-13 9:32 ` Johannes Berg
0 siblings, 1 reply; 18+ messages in thread
From: Johannes Berg @ 2015-07-17 13:43 UTC (permalink / raw)
To: Emmanuel Grumbach; +Cc: linux-wireless
On Wed, 2015-07-08 at 15:41 +0300, Emmanuel Grumbach wrote:
> From: Johannes Berg <johannes.berg@intel.com>
>
> The iwlwifi driver was the only driver that used this, but as
> it turns out it never needed it, so we can remove it.
>
I'm not applying this for now since it depends on the iwlwifi patch to
remove usage thereof :)
I think we said I'd apply that one also through my tree, but since it's
not urgent I'll sort it out later.
johannes
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 06/10] mac80211: remove ieee80211_aes_cmac_calculate_k1_k2()
2015-07-17 13:43 ` Johannes Berg
@ 2015-08-13 9:32 ` Johannes Berg
0 siblings, 0 replies; 18+ messages in thread
From: Johannes Berg @ 2015-08-13 9:32 UTC (permalink / raw)
To: Emmanuel Grumbach; +Cc: linux-wireless
On Fri, 2015-07-17 at 15:43 +0200, Johannes Berg wrote:
> On Wed, 2015-07-08 at 15:41 +0300, Emmanuel Grumbach wrote:
> > From: Johannes Berg <johannes.berg@intel.com>
> >
> > The iwlwifi driver was the only driver that used this, but as
> > it turns out it never needed it, so we can remove it.
> >
> I'm not applying this for now since it depends on the iwlwifi patch
> to remove usage thereof :)
>
> I think we said I'd apply that one also through my tree, but since
> it's not urgent I'll sort it out later.
>
Which I've done now - so this is also in now.
johannes
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 07/10] mac80211: add possibility to advertise 802.11 FTM support
2015-07-08 12:41 [PATCH 00/10] random patches to mac80211 Emmanuel Grumbach
` (5 preceding siblings ...)
2015-07-08 12:41 ` [PATCH 06/10] mac80211: remove ieee80211_aes_cmac_calculate_k1_k2() Emmanuel Grumbach
@ 2015-07-08 12:41 ` Emmanuel Grumbach
2015-07-17 13:44 ` Johannes Berg
2015-07-08 12:41 ` [PATCH 08/10] mac80211: shut down interfaces before destroying interface list Emmanuel Grumbach
` (2 subsequent siblings)
9 siblings, 1 reply; 18+ messages in thread
From: Emmanuel Grumbach @ 2015-07-08 12:41 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Gregory Greenman, Emmanuel Grumbach
From: Gregory Greenman <gregory.greenman@intel.com>
Add possibility for a driver to advertise 802.11 Fine Timing Measurement
support.
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
---
include/linux/ieee80211.h | 6 ++++++
include/net/mac80211.h | 6 ++++++
net/mac80211/debugfs.c | 1 +
net/mac80211/ieee80211_i.h | 2 +-
net/mac80211/main.c | 3 +++
5 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index b9c7897..63c2209 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -2077,6 +2077,12 @@ enum ieee80211_tdls_actioncode {
#define WLAN_EXT_CAPA8_OPMODE_NOTIF BIT(6)
#define WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED BIT(7)
+/*
+ * Fine Timing Measurement Initiator - bit 71 of @WLAN_EID_EXT_CAPABILITY
+ * information element
+ */
+#define WLAN_EXT_CAPA9_FTM_INITIATOR BIT(7)
+
/* TDLS specific payload type in the LLC/SNAP header */
#define WLAN_TDLS_SNAP_RFTYPE 0x2
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index e3314e5..6efb766 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1892,6 +1892,11 @@ struct ieee80211_txq {
* @IEEE80211_HW_TDLS_WIDER_BW: The device/driver supports wider bandwidth
* than then BSS bandwidth for a TDLS link on the base channel.
*
+ * @IEEE80211_HW_SUPPORTS_FTM_INITIATOR:
+ * Hardware supports 802.11 Fine Timing Measurement Initiator.
+ * This flag should be set only if the support can be provided without
+ * involvement of the stack; otherwise leave it to stack to decide.
+ *
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
*/
enum ieee80211_hw_flags {
@@ -1925,6 +1930,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_SUPPORTS_CLONED_SKBS,
IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS,
IEEE80211_HW_TDLS_WIDER_BW,
+ IEEE80211_HW_SUPPORTS_FTM_INITIATOR,
/* keep last, obviously */
NUM_IEEE80211_HW_FLAGS
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index ced6bf3..936f064 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -123,6 +123,7 @@ static const char *hw_flag_names[NUM_IEEE80211_HW_FLAGS + 1] = {
FLAG(SUPPORTS_CLONED_SKBS),
FLAG(SINGLE_SCAN_ON_ALL_BANDS),
FLAG(TDLS_WIDER_BW),
+ FLAG(SUPPORTS_FTM_INITIATOR),
/* keep last for the build bug below */
(void *)0x1
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 36f217e..38db179 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1349,7 +1349,7 @@ struct ieee80211_local {
struct cfg80211_chan_def monitor_chandef;
/* extended capabilities provided by mac80211 */
- u8 ext_capa[8];
+ u8 ext_capa[9];
/* TDLS channel switch */
struct work_struct tdls_chsw_work;
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index ff79a13..ee1bc81 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -1007,6 +1007,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (ieee80211_hw_check(&local->hw, CHANCTX_STA_CSA))
local->ext_capa[0] |= WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING;
+ if (ieee80211_hw_check(&local->hw, SUPPORTS_FTM_INITIATOR))
+ local->ext_capa[8] |= WLAN_EXT_CAPA9_FTM_INITIATOR;
+
local->hw.wiphy->max_num_csa_counters = IEEE80211_MAX_CSA_COUNTERS_NUM;
result = wiphy_register(local->hw.wiphy);
--
2.1.4
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 08/10] mac80211: shut down interfaces before destroying interface list
2015-07-08 12:41 [PATCH 00/10] random patches to mac80211 Emmanuel Grumbach
` (6 preceding siblings ...)
2015-07-08 12:41 ` [PATCH 07/10] mac80211: add possibility to advertise 802.11 FTM support Emmanuel Grumbach
@ 2015-07-08 12:41 ` Emmanuel Grumbach
2015-07-17 9:16 ` Johannes Berg
2015-07-08 12:41 ` [PATCH 09/10] mac80211: allow drivers to set netdev hw_features Emmanuel Grumbach
2015-07-08 12:41 ` [PATCH 10/10] mac80211: enable changing netdev features with ethtool Emmanuel Grumbach
9 siblings, 1 reply; 18+ messages in thread
From: Emmanuel Grumbach @ 2015-07-08 12:41 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
If the hardware is unregistered while interfaces are up, mac80211 will
unregister all interfaces, which in turns causes mac80211 to be called
again to remove them all from the driver and eventually shut down the
hardware.
During this shutdown, however, it's currently already unsafe to iterate
the list of interfaces atomically, as the list is manipulated in an
unsafe manner. This puts an undue burden on the driver - it must stop
all its activities before calling ieee80211_unregister_hw(), while in
the normal stop path it can do all cleanup in the stop method. If, for
example, it's using the iteration during RX for some reason, it would
have to stop RX before unregistering to avoid crashes.
Fix this problem by closing all interfaces before unregistering them.
This will cause the driver stop to have completed before we manipulate
the interface list, and after the driver is stopped *and* has called
ieee80211_unregister_hw() it really musn't be iterating any more as
the memory will be freed as well.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
net/mac80211/iface.c | 25 ++++++++++++++-----------
1 file changed, 14 insertions(+), 11 deletions(-)
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index e648ea8..0fba7f9 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1861,10 +1861,6 @@ void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata)
ieee80211_teardown_sdata(sdata);
}
-/*
- * Remove all interfaces, may only be called at hardware unregistration
- * time because it doesn't do RCU-safe list removals.
- */
void ieee80211_remove_interfaces(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata, *tmp;
@@ -1873,14 +1869,21 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local)
ASSERT_RTNL();
- /*
- * Close all AP_VLAN interfaces first, as otherwise they
- * might be closed while the AP interface they belong to
- * is closed, causing unregister_netdevice_many() to crash.
+ /* Before destroying the interfaces, make sure they're all stopped so
+ * that the hardware is stopped. Otherwise, the driver might still be
+ * iterating the interfaces during the shutdown, e.g. from a worker
+ * or from RX processing or similar, and if it does so (using atomic
+ * iteration) while we're manipulating the list, the iteration will
+ * crash.
+ *
+ * After this, the hardware should be stopped and the driver should
+ * have stopped all of its activities, so that we can do RCU-unaware
+ * manipulations of the interface list below.
*/
- list_for_each_entry(sdata, &local->interfaces, list)
- if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
- dev_close(sdata->dev);
+ cfg80211_shutdown_all_interfaces(local->hw.wiphy);
+
+ WARN(local->open_count, "%s: open count remains %d\n",
+ wiphy_name(local->hw.wiphy), local->open_count);
mutex_lock(&local->iflist_mtx);
list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
--
2.1.4
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PATCH 08/10] mac80211: shut down interfaces before destroying interface list
2015-07-08 12:41 ` [PATCH 08/10] mac80211: shut down interfaces before destroying interface list Emmanuel Grumbach
@ 2015-07-17 9:16 ` Johannes Berg
0 siblings, 0 replies; 18+ messages in thread
From: Johannes Berg @ 2015-07-17 9:16 UTC (permalink / raw)
To: Emmanuel Grumbach; +Cc: linux-wireless
On Wed, 2015-07-08 at 15:41 +0300, Emmanuel Grumbach wrote:
> From: Johannes Berg <johannes.berg@intel.com>
>
> If the hardware is unregistered while interfaces are up, mac80211
> will
> unregister all interfaces, which in turns causes mac80211 to be
> called
> again to remove them all from the driver and eventually shut down the
> hardware.
>
> During this shutdown, however, it's currently already unsafe to
> iterate
> the list of interfaces atomically, as the list is manipulated in an
> unsafe manner. This puts an undue burden on the driver - it must stop
> all its activities before calling ieee80211_unregister_hw(), while in
> the normal stop path it can do all cleanup in the stop method. If,
> for
> example, it's using the iteration during RX for some reason, it would
> have to stop RX before unregistering to avoid crashes.
>
> Fix this problem by closing all interfaces before unregistering them.
> This will cause the driver stop to have completed before we
> manipulate
> the interface list, and after the driver is stopped *and* has called
> ieee80211_unregister_hw() it really musn't be iterating any more as
> the memory will be freed as well.
>
Applied.
johannes
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 09/10] mac80211: allow drivers to set netdev hw_features
2015-07-08 12:41 [PATCH 00/10] random patches to mac80211 Emmanuel Grumbach
` (7 preceding siblings ...)
2015-07-08 12:41 ` [PATCH 08/10] mac80211: shut down interfaces before destroying interface list Emmanuel Grumbach
@ 2015-07-08 12:41 ` Emmanuel Grumbach
2015-07-08 12:41 ` [PATCH 10/10] mac80211: enable changing netdev features with ethtool Emmanuel Grumbach
9 siblings, 0 replies; 18+ messages in thread
From: Emmanuel Grumbach @ 2015-07-08 12:41 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
By allowing drivers to set hw_features and not just features we
gain the ability to turn certain features off with ethtool.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
include/net/mac80211.h | 4 +++-
net/mac80211/iface.c | 3 ++-
net/mac80211/main.c | 3 ++-
3 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 6efb766..4caef55 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2016,6 +2016,8 @@ enum ieee80211_hw_flags {
* @netdev_features: netdev features to be set in each netdev created
* from this HW. Note that not all features are usable with mac80211,
* other features will be rejected during HW registration.
+ * @netdev_hw_features: features to advertise as netdev hw_features, which
+ * impacts the ability of ethtool to modify them
*
* @uapsd_queues: This bitmap is included in (re)association frame to indicate
* for each access category if it is uAPSD trigger-enabled and delivery-
@@ -2058,7 +2060,7 @@ struct ieee80211_hw {
u8 offchannel_tx_hw_queue;
u8 radiotap_mcs_details;
u16 radiotap_vht_details;
- netdev_features_t netdev_features;
+ netdev_features_t netdev_features, netdev_hw_features;
u8 uapsd_queues;
u8 uapsd_max_sp_len;
u8 n_cipher_schemes;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 0fba7f9..e3bb35f 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1814,7 +1814,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
sdata->u.mgd.use_4addr = params->use_4addr;
}
- ndev->features |= local->hw.netdev_features;
+ ndev->features = local->hw.netdev_features;
+ ndev->hw_features = local->hw.netdev_hw_features;
netdev_set_default_ethtool_ops(ndev, &ieee80211_ethtool_ops);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index ee1bc81..6b830c6 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -850,7 +850,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
feature_whitelist = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_HIGHDMA |
NETIF_F_GSO_SOFTWARE;
- if (WARN_ON(hw->netdev_features & ~feature_whitelist))
+ if (WARN_ON(hw->netdev_features & ~feature_whitelist ||
+ hw->netdev_hw_features & ~feature_whitelist))
return -EINVAL;
if (hw->max_report_rates == 0)
--
2.1.4
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 10/10] mac80211: enable changing netdev features with ethtool
2015-07-08 12:41 [PATCH 00/10] random patches to mac80211 Emmanuel Grumbach
` (8 preceding siblings ...)
2015-07-08 12:41 ` [PATCH 09/10] mac80211: allow drivers to set netdev hw_features Emmanuel Grumbach
@ 2015-07-08 12:41 ` Emmanuel Grumbach
2015-07-17 13:46 ` Johannes Berg
9 siblings, 1 reply; 18+ messages in thread
From: Emmanuel Grumbach @ 2015-07-08 12:41 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Avri Altman, Emmanuel Grumbach
From: Avri Altman <avri.altman@intel.com>
For drivers that have offloading features, these are currently
forced and cannot be modified in any way. Enable that so users
can change the features if needed, but of course this requires
driver interaction.
For AP_VLAN don't allow direct changes but propagate them from
the AP interface.
Additionally, add NETIF_F_RXCSUM to the whitelist, if a driver
has this capability it doesn't have to advertise this but can
just set the skb->checksum field accordingly, but advertising
it will allow it to be changed with ethtool.
Signed-off-by: Avri Altman <avri.altman@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
---
include/net/mac80211.h | 6 ++++++
net/mac80211/driver-ops.h | 22 ++++++++++++++++++++++
net/mac80211/ieee80211_i.h | 6 ++++++
net/mac80211/iface.c | 39 +++++++++++++++++++++++++++++++++++++++
net/mac80211/main.c | 5 +----
net/mac80211/trace.h | 28 ++++++++++++++++++++++++++++
6 files changed, 102 insertions(+), 4 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 4caef55..6348cd9 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -3080,6 +3080,8 @@ enum ieee80211_reconfig_type {
*
* @get_ringparam: Get tx and rx ring current and maximum sizes.
*
+ * @set_features: change netdev features for the given virtual interface
+ *
* @tx_frames_pending: Check if there is any pending frame in the hardware
* queues before entering power save.
*
@@ -3384,6 +3386,10 @@ struct ieee80211_ops {
int (*set_ringparam)(struct ieee80211_hw *hw, u32 tx, u32 rx);
void (*get_ringparam)(struct ieee80211_hw *hw,
u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max);
+ int (*set_features)(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ netdev_features_t features,
+ netdev_features_t changed);
bool (*tx_frames_pending)(struct ieee80211_hw *hw);
int (*set_bitrate_mask)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
const struct cfg80211_bitrate_mask *mask);
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 32a2e70..b955586 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -895,6 +895,28 @@ static inline void drv_get_ringparam(struct ieee80211_local *local,
trace_drv_return_void(local);
}
+static inline int drv_set_features(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ netdev_features_t features,
+ netdev_features_t changed)
+{
+ int ret = -EOPNOTSUPP;
+
+ might_sleep();
+
+ if (!check_sdata_in_driver(sdata))
+ return -EIO;
+
+ trace_drv_set_features(local, sdata, features, changed);
+ if (local->ops->set_features)
+ ret = local->ops->set_features(&local->hw,
+ &sdata->vif,
+ features, changed);
+ trace_drv_return_int(local, ret);
+
+ return ret;
+}
+
static inline bool drv_tx_frames_pending(struct ieee80211_local *local)
{
bool ret = false;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 38db179..1d165a4 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -83,6 +83,12 @@ struct ieee80211_local;
#define IEEE80211_DEAUTH_FRAME_LEN (24 /* hdr */ + 2 /* reason */)
+/* Only these features can be passed through mac80211 */
+#define IEEE80211_SUPPORTED_NETDEV_FEATURES \
+ (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM | \
+ NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_HIGHDMA | \
+ NETIF_F_GSO_SOFTWARE)
+
struct ieee80211_fragment_entry {
struct sk_buff_head skb_list;
unsigned long first_frag_time;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index e3bb35f..cf5405f 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -6,6 +6,7 @@
* Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
* Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH
+ * Copyright 2015 Intel Deutschland GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -1131,6 +1132,43 @@ ieee80211_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
return stats;
}
+static int ieee80211_netdev_set_features(struct net_device *dev,
+ netdev_features_t features)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = sdata->local;
+ netdev_features_t changed = dev->features ^ features;
+ int ret;
+
+ if (!(changed & IEEE80211_SUPPORTED_NETDEV_FEATURES))
+ return 0;
+
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_AP_VLAN:
+ /* these aren't known to the driver */
+ return -EOPNOTSUPP;
+ default:
+ break;
+ }
+
+ ret = drv_set_features(local, sdata, features, changed);
+ if (ret)
+ return ret;
+
+ if (sdata->vif.type == NL80211_IFTYPE_AP) {
+ struct ieee80211_sub_if_data *vlan;
+
+ /* propagate to VLANs as they're dependent */
+ list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
+ vlan->dev->features = features;
+ netdev_update_features(vlan->dev);
+ }
+ }
+
+ return 0;
+}
+
static const struct net_device_ops ieee80211_dataif_ops = {
.ndo_open = ieee80211_open,
.ndo_stop = ieee80211_stop,
@@ -1141,6 +1179,7 @@ static const struct net_device_ops ieee80211_dataif_ops = {
.ndo_set_mac_address = ieee80211_change_mac,
.ndo_select_queue = ieee80211_netdev_select_queue,
.ndo_get_stats64 = ieee80211_get_stats64,
+ .ndo_set_features = ieee80211_netdev_set_features,
};
static u16 ieee80211_monitor_select_queue(struct net_device *dev,
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 6b830c6..5b82e6c 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -846,10 +846,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
}
}
- /* Only HW csum features are currently compatible with mac80211 */
- feature_whitelist = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
- NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_HIGHDMA |
- NETIF_F_GSO_SOFTWARE;
+ feature_whitelist = IEEE80211_SUPPORTED_NETDEV_FEATURES;
if (WARN_ON(hw->netdev_features & ~feature_whitelist ||
hw->netdev_hw_features & ~feature_whitelist))
return -EINVAL;
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 6f14591..755e9fa 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -1193,6 +1193,34 @@ TRACE_EVENT(drv_get_ringparam,
)
);
+TRACE_EVENT(drv_set_features,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ netdev_features_t features,
+ netdev_features_t changed),
+
+ TP_ARGS(local, sdata, features, changed),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ __field(netdev_features_t, features)
+ __field(netdev_features_t, changed)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ __entry->features = features;
+ __entry->changed = changed;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT VIF_PR_FMT " features=0x%llx, changed=0x%llx",
+ LOCAL_PR_ARG, VIF_PR_ARG, __entry->features, __entry->changed
+ )
+);
+
DEFINE_EVENT(local_only_evt, drv_tx_frames_pending,
TP_PROTO(struct ieee80211_local *local),
TP_ARGS(local)
--
2.1.4
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PATCH 10/10] mac80211: enable changing netdev features with ethtool
2015-07-08 12:41 ` [PATCH 10/10] mac80211: enable changing netdev features with ethtool Emmanuel Grumbach
@ 2015-07-17 13:46 ` Johannes Berg
0 siblings, 0 replies; 18+ messages in thread
From: Johannes Berg @ 2015-07-17 13:46 UTC (permalink / raw)
To: Emmanuel Grumbach; +Cc: linux-wireless, Avri Altman
On Wed, 2015-07-08 at 15:41 +0300, Emmanuel Grumbach wrote:
> From: Avri Altman <avri.altman@intel.com>
>
> For drivers that have offloading features, these are currently
> forced and cannot be modified in any way. Enable that so users
> can change the features if needed, but of course this requires
> driver interaction.
>
> For AP_VLAN don't allow direct changes but propagate them from
> the AP interface.
>
> Additionally, add NETIF_F_RXCSUM to the whitelist, if a driver
> has this capability it doesn't have to advertise this but can
> just set the skb->checksum field accordingly, but advertising
> it will allow it to be changed with ethtool.
>
This patch has an issue when ethtool is called while the interface is
still down, so I'll not apply it for now. I'll try to sort out that
issue after my vacation.
As a consequence, patch 9 is worthless so I'll also leave that for now.
johannes
^ permalink raw reply [flat|nested] 18+ messages in thread