Skip to content
This repository was archived by the owner on Sep 24, 2020. It is now read-only.

Commit a7a6bdd

Browse files
ariknemjmberg-intel
authored andcommitted
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 <[email protected]> Signed-off-by: Arik Nemtsov <[email protected]> Signed-off-by: Johannes Berg <[email protected]>
1 parent 5383758 commit a7a6bdd

File tree

10 files changed

+381
-5
lines changed

10 files changed

+381
-5
lines changed

include/net/mac80211.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2915,6 +2915,16 @@ enum ieee80211_reconfig_type {
29152915
*
29162916
* @get_txpower: get current maximum tx power (in dBm) based on configuration
29172917
* and hardware limits.
2918+
*
2919+
* @tdls_channel_switch: Start channel-switching with a TDLS peer. The driver
2920+
* is responsible for continually initiating channel-switching operations
2921+
* and returning to the base channel for communication with the AP. The
2922+
* driver receives a channel-switch request template and the location of
2923+
* the switch-timing IE within the template as part of the invocation.
2924+
* The template is valid only within the call, and the driver can
2925+
* optionally copy the skb for further re-use.
2926+
* @tdls_cancel_channel_switch: Stop channel-switching with a TDLS peer. Both
2927+
* peers must be on the base channel when the call completes.
29182928
*/
29192929
struct ieee80211_ops {
29202930
void (*tx)(struct ieee80211_hw *hw,
@@ -3126,6 +3136,15 @@ struct ieee80211_ops {
31263136
u32 (*get_expected_throughput)(struct ieee80211_sta *sta);
31273137
int (*get_txpower)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
31283138
int *dbm);
3139+
3140+
int (*tdls_channel_switch)(struct ieee80211_hw *hw,
3141+
struct ieee80211_vif *vif,
3142+
struct ieee80211_sta *sta, u8 oper_class,
3143+
struct cfg80211_chan_def *chandef,
3144+
struct sk_buff *skb, u32 ch_sw_tm_ie);
3145+
void (*tdls_cancel_channel_switch)(struct ieee80211_hw *hw,
3146+
struct ieee80211_vif *vif,
3147+
struct ieee80211_sta *sta);
31293148
};
31303149

31313150
/**

net/mac80211/cfg.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3752,6 +3752,8 @@ const struct cfg80211_ops mac80211_config_ops = {
37523752
.set_rekey_data = ieee80211_set_rekey_data,
37533753
.tdls_oper = ieee80211_tdls_oper,
37543754
.tdls_mgmt = ieee80211_tdls_mgmt,
3755+
.tdls_channel_switch = ieee80211_tdls_channel_switch,
3756+
.tdls_cancel_channel_switch = ieee80211_tdls_cancel_channel_switch,
37553757
.probe_client = ieee80211_probe_client,
37563758
.set_noack_map = ieee80211_set_noack_map,
37573759
#ifdef CONFIG_PM

net/mac80211/debugfs_sta.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
7474
test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : ""
7575

7676
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",
7878
TEST(AUTH), TEST(ASSOC), TEST(PS_STA),
7979
TEST(PS_DRIVER), TEST(AUTHORIZED),
8080
TEST(SHORT_PREAMBLE),
@@ -83,10 +83,10 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
8383
TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL),
8484
TEST(UAPSD), TEST(SP), TEST(TDLS_PEER),
8585
TEST(TDLS_PEER_AUTH), TEST(TDLS_INITIATOR),
86-
TEST(TDLS_CHAN_SWITCH), TEST(4ADDR_EVENT),
87-
TEST(INSERTED), TEST(RATE_CONTROL),
88-
TEST(TOFFSET_KNOWN), TEST(MPSP_OWNER),
89-
TEST(MPSP_RECIPIENT));
86+
TEST(TDLS_CHAN_SWITCH), TEST(TDLS_OFF_CHANNEL),
87+
TEST(4ADDR_EVENT), TEST(INSERTED),
88+
TEST(RATE_CONTROL), TEST(TOFFSET_KNOWN),
89+
TEST(MPSP_OWNER), TEST(MPSP_RECIPIENT));
9090
#undef TEST
9191
return simple_read_from_buffer(userbuf, count, ppos, buf, res);
9292
}

net/mac80211/driver-ops.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,4 +1296,45 @@ static inline int drv_get_txpower(struct ieee80211_local *local,
12961296
return ret;
12971297
}
12981298

1299+
static inline int
1300+
drv_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+
1323+
static inline void
1324+
drv_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+
12991340
#endif /* __MAC80211_DRIVER_OPS */

net/mac80211/ieee80211_i.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2007,6 +2007,12 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
20072007
int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
20082008
const u8 *peer, enum nl80211_tdls_operation oper);
20092009
void ieee80211_tdls_peer_del_work(struct work_struct *wk);
2010+
int ieee80211_tdls_channel_switch(struct wiphy *wiphy, struct net_device *dev,
2011+
const u8 *addr, u8 oper_class,
2012+
struct cfg80211_chan_def *chandef);
2013+
void ieee80211_tdls_cancel_channel_switch(struct wiphy *wiphy,
2014+
struct net_device *dev,
2015+
const u8 *addr);
20102016

20112017
extern const struct ethtool_ops ieee80211_ethtool_ops;
20122018

net/mac80211/main.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
764764
local->hw.offchannel_tx_hw_queue >= local->hw.queues))
765765
return -EINVAL;
766766

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+
767772
#ifdef CONFIG_PM
768773
if (hw->wiphy->wowlan && (!local->ops->suspend || !local->ops->resume))
769774
return -EINVAL;

net/mac80211/sta_info.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,15 @@ static int __must_check __sta_info_destroy_part1(struct sta_info *sta)
847847
if (WARN_ON(ret))
848848
return ret;
849849

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+
850859
list_del_rcu(&sta->list);
851860

852861
drv_sta_pre_rcu_remove(local, sta->sdata, sta);

net/mac80211/sta_info.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@
5050
* @WLAN_STA_TDLS_INITIATOR: We are the initiator of the TDLS link with this
5151
* station.
5252
* @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
5355
* @WLAN_STA_UAPSD: Station requested unscheduled SP while driver was
5456
* keeping station in power-save mode, reply when the driver
5557
* unblocks the station.
@@ -80,6 +82,7 @@ enum ieee80211_sta_info_flags {
8082
WLAN_STA_TDLS_PEER_AUTH,
8183
WLAN_STA_TDLS_INITIATOR,
8284
WLAN_STA_TDLS_CHAN_SWITCH,
85+
WLAN_STA_TDLS_OFF_CHANNEL,
8386
WLAN_STA_UAPSD,
8487
WLAN_STA_SP,
8588
WLAN_STA_4ADDR_EVENT,

0 commit comments

Comments
 (0)