summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/net/mac80211.h12
-rw-r--r--net/mac80211/driver-ops.h16
-rw-r--r--net/mac80211/tdls.c10
-rw-r--r--net/mac80211/trace.h7
4 files changed, 44 insertions, 1 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 8d876dc8b299..18c2bdbaf988 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2764,6 +2764,15 @@ enum ieee80211_roc_type {
* mac80211 will transmit the frame right away.
* The callback is optional and can (should!) sleep.
*
+ * @mgd_protect_tdls_discover: Protect a TDLS discovery session. After sending
+ * a TDLS discovery-request, we expect a reply to arrive on the AP's
+ * channel. We must stay on the channel (no PSM, scan, etc.), since a TDLS
+ * setup-response is a direct packet not buffered by the AP.
+ * mac80211 will call this function just before the transmission of a TDLS
+ * discovery-request. The recommended period of protection is at least
+ * 2 * (DTIM period).
+ * The callback is optional and can sleep.
+ *
* @add_chanctx: Notifies device driver about new channel context creation.
* @remove_chanctx: Notifies device driver about channel context destruction.
* @change_chanctx: Notifies device driver about channel context changes that
@@ -2981,6 +2990,9 @@ struct ieee80211_ops {
void (*mgd_prepare_tx)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
+ void (*mgd_protect_tdls_discover)(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif);
+
int (*add_chanctx)(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx);
void (*remove_chanctx)(struct ieee80211_hw *hw,
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index bd782dcffcc7..2265bd7a44ba 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -970,6 +970,22 @@ static inline void drv_mgd_prepare_tx(struct ieee80211_local *local,
trace_drv_return_void(local);
}
+static inline void
+drv_mgd_protect_tdls_discover(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata)
+{
+ might_sleep();
+
+ if (!check_sdata_in_driver(sdata))
+ return;
+ WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION);
+
+ trace_drv_mgd_protect_tdls_discover(local, sdata);
+ if (local->ops->mgd_protect_tdls_discover)
+ local->ops->mgd_protect_tdls_discover(&local->hw, &sdata->vif);
+ trace_drv_return_void(local);
+}
+
static inline int drv_add_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
{
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
index b87e369561f4..f7185338a0fa 100644
--- a/net/mac80211/tdls.c
+++ b/net/mac80211/tdls.c
@@ -10,6 +10,7 @@
#include <linux/ieee80211.h>
#include <net/cfg80211.h>
#include "ieee80211_i.h"
+#include "driver-ops.h"
/* give usermode some time for retries in setting up the TDLS session */
#define TDLS_PEER_SETUP_TIMEOUT (15 * HZ)
@@ -442,8 +443,15 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
peer_capability, initiator,
extra_ies, extra_ies_len);
break;
- case WLAN_TDLS_SETUP_CONFIRM:
case WLAN_TDLS_DISCOVERY_REQUEST:
+ /*
+ * Protect the discovery so we can hear the TDLS discovery
+ * response frame. It is transmitted directly and not buffered
+ * by the AP.
+ */
+ drv_mgd_protect_tdls_discover(sdata->local, sdata);
+ /* fall-through */
+ case WLAN_TDLS_SETUP_CONFIRM:
case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
/* no special handling */
ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer,
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index cfe1a0688b5c..02ac535d1274 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -1330,6 +1330,13 @@ DEFINE_EVENT(local_sdata_evt, drv_mgd_prepare_tx,
TP_ARGS(local, sdata)
);
+DEFINE_EVENT(local_sdata_evt, drv_mgd_protect_tdls_discover,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata),
+
+ TP_ARGS(local, sdata)
+);
+
DECLARE_EVENT_CLASS(local_chanctx,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx),