Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a7a6bdd0 authored by Arik Nemtsov's avatar Arik Nemtsov Committed by Johannes Berg
Browse files

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: default avatarArik Nemtsov <arikx.nemtsov@intel.com>
Signed-off-by: default avatarArik Nemtsov <arik@wizery.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 53837584
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -2915,6 +2915,16 @@ enum ieee80211_reconfig_type {
 *
 * @get_txpower: get current maximum tx power (in dBm) based on configuration
 *	and hardware limits.
 *
 * @tdls_channel_switch: Start channel-switching with a TDLS peer. The driver
 *	is responsible for continually initiating channel-switching operations
 *	and returning to the base channel for communication with the AP. The
 *	driver receives a channel-switch request template and the location of
 *	the switch-timing IE within the template as part of the invocation.
 *	The template is valid only within the call, and the driver can
 *	optionally copy the skb for further re-use.
 * @tdls_cancel_channel_switch: Stop channel-switching with a TDLS peer. Both
 *	peers must be on the base channel when the call completes.
 */
struct ieee80211_ops {
	void (*tx)(struct ieee80211_hw *hw,
@@ -3126,6 +3136,15 @@ struct ieee80211_ops {
	u32 (*get_expected_throughput)(struct ieee80211_sta *sta);
	int (*get_txpower)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
			   int *dbm);

	int (*tdls_channel_switch)(struct ieee80211_hw *hw,
				   struct ieee80211_vif *vif,
				   struct ieee80211_sta *sta, u8 oper_class,
				   struct cfg80211_chan_def *chandef,
				   struct sk_buff *skb, u32 ch_sw_tm_ie);
	void (*tdls_cancel_channel_switch)(struct ieee80211_hw *hw,
					   struct ieee80211_vif *vif,
					   struct ieee80211_sta *sta);
};

/**
+2 −0
Original line number Diff line number Diff line
@@ -3752,6 +3752,8 @@ const struct cfg80211_ops mac80211_config_ops = {
	.set_rekey_data = ieee80211_set_rekey_data,
	.tdls_oper = ieee80211_tdls_oper,
	.tdls_mgmt = ieee80211_tdls_mgmt,
	.tdls_channel_switch = ieee80211_tdls_channel_switch,
	.tdls_cancel_channel_switch = ieee80211_tdls_cancel_channel_switch,
	.probe_client = ieee80211_probe_client,
	.set_noack_map = ieee80211_set_noack_map,
#ifdef CONFIG_PM
+5 −5
Original line number Diff line number Diff line
@@ -74,7 +74,7 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
	test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : ""

	int res = scnprintf(buf, sizeof(buf),
			    "%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%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
			    TEST(AUTH), TEST(ASSOC), TEST(PS_STA),
			    TEST(PS_DRIVER), TEST(AUTHORIZED),
			    TEST(SHORT_PREAMBLE),
@@ -83,10 +83,10 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
			    TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL),
			    TEST(UAPSD), TEST(SP), TEST(TDLS_PEER),
			    TEST(TDLS_PEER_AUTH), TEST(TDLS_INITIATOR),
			    TEST(TDLS_CHAN_SWITCH), TEST(4ADDR_EVENT),
			    TEST(INSERTED), TEST(RATE_CONTROL),
			    TEST(TOFFSET_KNOWN), TEST(MPSP_OWNER),
			    TEST(MPSP_RECIPIENT));
			    TEST(TDLS_CHAN_SWITCH), TEST(TDLS_OFF_CHANNEL),
			    TEST(4ADDR_EVENT), TEST(INSERTED),
			    TEST(RATE_CONTROL), TEST(TOFFSET_KNOWN),
			    TEST(MPSP_OWNER), TEST(MPSP_RECIPIENT));
#undef TEST
	return simple_read_from_buffer(userbuf, count, ppos, buf, res);
}
+41 −0
Original line number Diff line number Diff line
@@ -1296,4 +1296,45 @@ static inline int drv_get_txpower(struct ieee80211_local *local,
	return ret;
}

static inline int
drv_tdls_channel_switch(struct ieee80211_local *local,
			struct ieee80211_sub_if_data *sdata,
			struct ieee80211_sta *sta, u8 oper_class,
			struct cfg80211_chan_def *chandef,
			struct sk_buff *tmpl_skb, u32 ch_sw_tm_ie)
{
	int ret;

	might_sleep();
	if (!check_sdata_in_driver(sdata))
		return -EIO;

	if (!local->ops->tdls_channel_switch)
		return -EOPNOTSUPP;

	trace_drv_tdls_channel_switch(local, sdata, sta, oper_class, chandef);
	ret = local->ops->tdls_channel_switch(&local->hw, &sdata->vif, sta,
					      oper_class, chandef, tmpl_skb,
					      ch_sw_tm_ie);
	trace_drv_return_int(local, ret);
	return ret;
}

static inline void
drv_tdls_cancel_channel_switch(struct ieee80211_local *local,
			       struct ieee80211_sub_if_data *sdata,
			       struct ieee80211_sta *sta)
{
	might_sleep();
	if (!check_sdata_in_driver(sdata))
		return;

	if (!local->ops->tdls_cancel_channel_switch)
		return;

	trace_drv_tdls_cancel_channel_switch(local, sdata, sta);
	local->ops->tdls_cancel_channel_switch(&local->hw, &sdata->vif, sta);
	trace_drv_return_void(local);
}

#endif /* __MAC80211_DRIVER_OPS */
+6 −0
Original line number Diff line number Diff line
@@ -2007,6 +2007,12 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
			const u8 *peer, enum nl80211_tdls_operation oper);
void ieee80211_tdls_peer_del_work(struct work_struct *wk);
int ieee80211_tdls_channel_switch(struct wiphy *wiphy, struct net_device *dev,
				  const u8 *addr, u8 oper_class,
				  struct cfg80211_chan_def *chandef);
void ieee80211_tdls_cancel_channel_switch(struct wiphy *wiphy,
					  struct net_device *dev,
					  const u8 *addr);

extern const struct ethtool_ops ieee80211_ethtool_ops;

Loading