aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorArik Nemtsov <arik@wizery.com>2014-11-09 11:50:19 -0500
committerJohannes Berg <johannes.berg@intel.com>2014-11-19 12:45:21 -0500
commita7a6bdd0670feb8bfc26d41cda32b6064dbca50e (patch)
treed343591f508af2d1a15f5b265e7ddaf182e34129 /net
parent53837584438f8899e061ada4663ae1d09b49b96a (diff)
mac80211: introduce TDLS channel switch ops
Implement the cfg80211 TDLS channel switch ops and introduce new mac80211 ones for low-level drivers. Verify low-level driver support for the new ops when using the relevant wiphy feature bit. Also verify the peer supports channel switching before passing the command down. Add a new STA flag to track the off-channel state with the TDLS peer and make sure to cancel the channel-switch if the peer STA is unexpectedly removed. Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com> Signed-off-by: Arik Nemtsov <arik@wizery.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/cfg.c2
-rw-r--r--net/mac80211/debugfs_sta.c10
-rw-r--r--net/mac80211/driver-ops.h41
-rw-r--r--net/mac80211/ieee80211_i.h6
-rw-r--r--net/mac80211/main.c5
-rw-r--r--net/mac80211/sta_info.c9
-rw-r--r--net/mac80211/sta_info.h3
-rw-r--r--net/mac80211/tdls.c234
-rw-r--r--net/mac80211/trace.h57
9 files changed, 362 insertions, 5 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 8195e65d8a91..e75d5c53e97b 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3752,6 +3752,8 @@ const struct cfg80211_ops mac80211_config_ops = {
3752 .set_rekey_data = ieee80211_set_rekey_data, 3752 .set_rekey_data = ieee80211_set_rekey_data,
3753 .tdls_oper = ieee80211_tdls_oper, 3753 .tdls_oper = ieee80211_tdls_oper,
3754 .tdls_mgmt = ieee80211_tdls_mgmt, 3754 .tdls_mgmt = ieee80211_tdls_mgmt,
3755 .tdls_channel_switch = ieee80211_tdls_channel_switch,
3756 .tdls_cancel_channel_switch = ieee80211_tdls_cancel_channel_switch,
3755 .probe_client = ieee80211_probe_client, 3757 .probe_client = ieee80211_probe_client,
3756 .set_noack_map = ieee80211_set_noack_map, 3758 .set_noack_map = ieee80211_set_noack_map,
3757#ifdef CONFIG_PM 3759#ifdef CONFIG_PM
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 2ba7f53746da..94c70091bbd7 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -74,7 +74,7 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
74 test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" 74 test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : ""
75 75
76 int res = scnprintf(buf, sizeof(buf), 76 int res = scnprintf(buf, sizeof(buf),
77 "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", 77 "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
78 TEST(AUTH), TEST(ASSOC), TEST(PS_STA), 78 TEST(AUTH), TEST(ASSOC), TEST(PS_STA),
79 TEST(PS_DRIVER), TEST(AUTHORIZED), 79 TEST(PS_DRIVER), TEST(AUTHORIZED),
80 TEST(SHORT_PREAMBLE), 80 TEST(SHORT_PREAMBLE),
@@ -83,10 +83,10 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
83 TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL), 83 TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL),
84 TEST(UAPSD), TEST(SP), TEST(TDLS_PEER), 84 TEST(UAPSD), TEST(SP), TEST(TDLS_PEER),
85 TEST(TDLS_PEER_AUTH), TEST(TDLS_INITIATOR), 85 TEST(TDLS_PEER_AUTH), TEST(TDLS_INITIATOR),
86 TEST(TDLS_CHAN_SWITCH), TEST(4ADDR_EVENT), 86 TEST(TDLS_CHAN_SWITCH), TEST(TDLS_OFF_CHANNEL),
87 TEST(INSERTED), TEST(RATE_CONTROL), 87 TEST(4ADDR_EVENT), TEST(INSERTED),
88 TEST(TOFFSET_KNOWN), TEST(MPSP_OWNER), 88 TEST(RATE_CONTROL), TEST(TOFFSET_KNOWN),
89 TEST(MPSP_RECIPIENT)); 89 TEST(MPSP_OWNER), TEST(MPSP_RECIPIENT));
90#undef TEST 90#undef TEST
91 return simple_read_from_buffer(userbuf, count, ppos, buf, res); 91 return simple_read_from_buffer(userbuf, count, ppos, buf, res);
92} 92}
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 9759dd1f0734..ec4ae42ac15f 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -1296,4 +1296,45 @@ static inline int drv_get_txpower(struct ieee80211_local *local,
1296 return ret; 1296 return ret;
1297} 1297}
1298 1298
1299static inline int
1300drv_tdls_channel_switch(struct ieee80211_local *local,
1301 struct ieee80211_sub_if_data *sdata,
1302 struct ieee80211_sta *sta, u8 oper_class,
1303 struct cfg80211_chan_def *chandef,
1304 struct sk_buff *tmpl_skb, u32 ch_sw_tm_ie)
1305{
1306 int ret;
1307
1308 might_sleep();
1309 if (!check_sdata_in_driver(sdata))
1310 return -EIO;
1311
1312 if (!local->ops->tdls_channel_switch)
1313 return -EOPNOTSUPP;
1314
1315 trace_drv_tdls_channel_switch(local, sdata, sta, oper_class, chandef);
1316 ret = local->ops->tdls_channel_switch(&local->hw, &sdata->vif, sta,
1317 oper_class, chandef, tmpl_skb,
1318 ch_sw_tm_ie);
1319 trace_drv_return_int(local, ret);
1320 return ret;
1321}
1322
1323static inline void
1324drv_tdls_cancel_channel_switch(struct ieee80211_local *local,
1325 struct ieee80211_sub_if_data *sdata,
1326 struct ieee80211_sta *sta)
1327{
1328 might_sleep();
1329 if (!check_sdata_in_driver(sdata))
1330 return;
1331
1332 if (!local->ops->tdls_cancel_channel_switch)
1333 return;
1334
1335 trace_drv_tdls_cancel_channel_switch(local, sdata, sta);
1336 local->ops->tdls_cancel_channel_switch(&local->hw, &sdata->vif, sta);
1337 trace_drv_return_void(local);
1338}
1339
1299#endif /* __MAC80211_DRIVER_OPS */ 1340#endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index e786ab6bc72c..2c7abc077b6b 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2007,6 +2007,12 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
2007int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, 2007int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
2008 const u8 *peer, enum nl80211_tdls_operation oper); 2008 const u8 *peer, enum nl80211_tdls_operation oper);
2009void ieee80211_tdls_peer_del_work(struct work_struct *wk); 2009void ieee80211_tdls_peer_del_work(struct work_struct *wk);
2010int ieee80211_tdls_channel_switch(struct wiphy *wiphy, struct net_device *dev,
2011 const u8 *addr, u8 oper_class,
2012 struct cfg80211_chan_def *chandef);
2013void ieee80211_tdls_cancel_channel_switch(struct wiphy *wiphy,
2014 struct net_device *dev,
2015 const u8 *addr);
2010 2016
2011extern const struct ethtool_ops ieee80211_ethtool_ops; 2017extern const struct ethtool_ops ieee80211_ethtool_ops;
2012 2018
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 282a4f36eb92..774ccb2d9a76 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -764,6 +764,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
764 local->hw.offchannel_tx_hw_queue >= local->hw.queues)) 764 local->hw.offchannel_tx_hw_queue >= local->hw.queues))
765 return -EINVAL; 765 return -EINVAL;
766 766
767 if ((hw->wiphy->features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH) &&
768 (!local->ops->tdls_channel_switch ||
769 !local->ops->tdls_cancel_channel_switch))
770 return -EOPNOTSUPP;
771
767#ifdef CONFIG_PM 772#ifdef CONFIG_PM
768 if (hw->wiphy->wowlan && (!local->ops->suspend || !local->ops->resume)) 773 if (hw->wiphy->wowlan && (!local->ops->suspend || !local->ops->resume))
769 return -EINVAL; 774 return -EINVAL;
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 97372514f287..86ca62765699 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -847,6 +847,15 @@ static int __must_check __sta_info_destroy_part1(struct sta_info *sta)
847 if (WARN_ON(ret)) 847 if (WARN_ON(ret))
848 return ret; 848 return ret;
849 849
850 /*
851 * for TDLS peers, make sure to return to the base channel before
852 * removal.
853 */
854 if (test_sta_flag(sta, WLAN_STA_TDLS_OFF_CHANNEL)) {
855 drv_tdls_cancel_channel_switch(local, sdata, &sta->sta);
856 clear_sta_flag(sta, WLAN_STA_TDLS_OFF_CHANNEL);
857 }
858
850 list_del_rcu(&sta->list); 859 list_del_rcu(&sta->list);
851 860
852 drv_sta_pre_rcu_remove(local, sta->sdata, sta); 861 drv_sta_pre_rcu_remove(local, sta->sdata, sta);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index b6702c810ad3..00f56eb72c60 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -50,6 +50,8 @@
50 * @WLAN_STA_TDLS_INITIATOR: We are the initiator of the TDLS link with this 50 * @WLAN_STA_TDLS_INITIATOR: We are the initiator of the TDLS link with this
51 * station. 51 * station.
52 * @WLAN_STA_TDLS_CHAN_SWITCH: This TDLS peer supports TDLS channel-switching 52 * @WLAN_STA_TDLS_CHAN_SWITCH: This TDLS peer supports TDLS channel-switching
53 * @WLAN_STA_TDLS_OFF_CHANNEL: The local STA is currently off-channel with this
54 * TDLS peer
53 * @WLAN_STA_UAPSD: Station requested unscheduled SP while driver was 55 * @WLAN_STA_UAPSD: Station requested unscheduled SP while driver was
54 * keeping station in power-save mode, reply when the driver 56 * keeping station in power-save mode, reply when the driver
55 * unblocks the station. 57 * unblocks the station.
@@ -80,6 +82,7 @@ enum ieee80211_sta_info_flags {
80 WLAN_STA_TDLS_PEER_AUTH, 82 WLAN_STA_TDLS_PEER_AUTH,
81 WLAN_STA_TDLS_INITIATOR, 83 WLAN_STA_TDLS_INITIATOR,
82 WLAN_STA_TDLS_CHAN_SWITCH, 84 WLAN_STA_TDLS_CHAN_SWITCH,
85 WLAN_STA_TDLS_OFF_CHANNEL,
83 WLAN_STA_UAPSD, 86 WLAN_STA_UAPSD,
84 WLAN_STA_SP, 87 WLAN_STA_SP,
85 WLAN_STA_4ADDR_EVENT, 88 WLAN_STA_4ADDR_EVENT,
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
index fa141aecd986..358f9a4512ad 100644
--- a/net/mac80211/tdls.c
+++ b/net/mac80211/tdls.c
@@ -449,6 +449,48 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata,
449 ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); 449 ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator);
450} 450}
451 451
452static void
453ieee80211_tdls_add_chan_switch_req_ies(struct ieee80211_sub_if_data *sdata,
454 struct sk_buff *skb, const u8 *peer,
455 bool initiator, const u8 *extra_ies,
456 size_t extra_ies_len, u8 oper_class,
457 struct cfg80211_chan_def *chandef)
458{
459 struct ieee80211_tdls_data *tf;