summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-07-19 10:39:53 +0200
committerJohn W. Linville <linville@tuxdriver.com>2011-07-20 15:04:35 -0400
commitb2abb6e2bcb91ae384c5857dffd0bb97b76c7a68 (patch)
tree4f6381c0a7b4dc8a1f9cd3c3bf2b94a6c971c737 /net
parente0d687bd9df218ba3d97aac15919d30816d72dcb (diff)
downloadlinux-stable-b2abb6e2bcb91ae384c5857dffd0bb97b76c7a68.tar.gz
linux-stable-b2abb6e2bcb91ae384c5857dffd0bb97b76c7a68.tar.bz2
linux-stable-b2abb6e2bcb91ae384c5857dffd0bb97b76c7a68.zip
mac80211: sync driver before TX
In P2P client mode, the GO (AP) to connect to might have periods of time where it is not available due to powersave. To allow the driver to sync with it and send frames to the GO only when it is available add a new callback tx_sync (and the corresponding finish_tx_sync). These callbacks can sleep unlike the actual TX. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/driver-ops.h31
-rw-r--r--net/mac80211/driver-trace.h43
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/mlme.c24
-rw-r--r--net/mac80211/work.c25
5 files changed, 122 insertions, 3 deletions
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index b2d6bba44054..1425380983f7 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -130,6 +130,37 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
trace_drv_return_void(local);
}
+static inline int drv_tx_sync(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ const u8 *bssid,
+ enum ieee80211_tx_sync_type type)
+{
+ int ret = 0;
+
+ might_sleep();
+
+ trace_drv_tx_sync(local, sdata, bssid, type);
+ if (local->ops->tx_sync)
+ ret = local->ops->tx_sync(&local->hw, &sdata->vif,
+ bssid, type);
+ trace_drv_return_int(local, ret);
+ return ret;
+}
+
+static inline void drv_finish_tx_sync(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ const u8 *bssid,
+ enum ieee80211_tx_sync_type type)
+{
+ might_sleep();
+
+ trace_drv_finish_tx_sync(local, sdata, bssid, type);
+ if (local->ops->finish_tx_sync)
+ local->ops->finish_tx_sync(&local->hw, &sdata->vif,
+ bssid, type);
+ trace_drv_return_void(local);
+}
+
static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
struct netdev_hw_addr_list *mc_list)
{
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index 4470f6e8b845..f47b00dc7afd 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -319,6 +319,49 @@ TRACE_EVENT(drv_bss_info_changed,
)
);
+DECLARE_EVENT_CLASS(tx_sync_evt,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ const u8 *bssid,
+ enum ieee80211_tx_sync_type type),
+ TP_ARGS(local, sdata, bssid, type),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ __array(char, bssid, ETH_ALEN)
+ __field(u32, sync_type)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ memcpy(__entry->bssid, bssid, ETH_ALEN);
+ __entry->sync_type = type;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT VIF_PR_FMT " bssid:%pM type:%d",
+ LOCAL_PR_ARG, VIF_PR_ARG, __entry->bssid, __entry->sync_type
+ )
+);
+
+DEFINE_EVENT(tx_sync_evt, drv_tx_sync,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ const u8 *bssid,
+ enum ieee80211_tx_sync_type type),
+ TP_ARGS(local, sdata, bssid, type)
+);
+
+DEFINE_EVENT(tx_sync_evt, drv_finish_tx_sync,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ const u8 *bssid,
+ enum ieee80211_tx_sync_type type),
+ TP_ARGS(local, sdata, bssid, type)
+);
+
TRACE_EVENT(drv_prepare_multicast,
TP_PROTO(struct ieee80211_local *local, int mc_count),
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index eb9d4826f775..400c09bea639 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -323,6 +323,7 @@ struct ieee80211_work {
u8 key[WLAN_KEY_LEN_WEP104];
u8 key_len, key_idx;
bool privacy;
+ bool synced;
} probe_auth;
struct {
struct cfg80211_bss *bss;
@@ -336,6 +337,7 @@ struct ieee80211_work {
u8 ssid_len;
u8 supp_rates_len;
bool wmm_used, use_11n, uapsd_used;
+ bool synced;
} assoc;
struct {
u32 duration;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index fee706d39fc2..d6470c7fd6ce 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2335,14 +2335,16 @@ static enum work_done_result
ieee80211_probe_auth_done(struct ieee80211_work *wk,
struct sk_buff *skb)
{
+ struct ieee80211_local *local = wk->sdata->local;
+
if (!skb) {
cfg80211_send_auth_timeout(wk->sdata->dev, wk->filter_ta);
- return WORK_DONE_DESTROY;
+ goto destroy;
}
if (wk->type == IEEE80211_WORK_AUTH) {
cfg80211_send_rx_auth(wk->sdata->dev, skb->data, skb->len);
- return WORK_DONE_DESTROY;
+ goto destroy;
}
mutex_lock(&wk->sdata->u.mgd.mtx);
@@ -2352,6 +2354,12 @@ ieee80211_probe_auth_done(struct ieee80211_work *wk,
wk->type = IEEE80211_WORK_AUTH;
wk->probe_auth.tries = 0;
return WORK_DONE_REQUEUE;
+ destroy:
+ if (wk->probe_auth.synced)
+ drv_finish_tx_sync(local, wk->sdata, wk->filter_ta,
+ IEEE80211_TX_SYNC_AUTH);
+
+ return WORK_DONE_DESTROY;
}
int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
@@ -2424,6 +2432,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
struct sk_buff *skb)
{
+ struct ieee80211_local *local = wk->sdata->local;
struct ieee80211_mgmt *mgmt;
struct ieee80211_rx_status *rx_status;
struct ieee802_11_elems elems;
@@ -2431,7 +2440,7 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
if (!skb) {
cfg80211_send_assoc_timeout(wk->sdata->dev, wk->filter_ta);
- return WORK_DONE_DESTROY;
+ goto destroy;
}
if (wk->type == IEEE80211_WORK_ASSOC_BEACON_WAIT) {
@@ -2451,6 +2460,10 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
status = le16_to_cpu(mgmt->u.assoc_resp.status_code);
if (status == WLAN_STATUS_SUCCESS) {
+ if (wk->assoc.synced)
+ drv_finish_tx_sync(local, wk->sdata, wk->filter_ta,
+ IEEE80211_TX_SYNC_ASSOC);
+
mutex_lock(&wk->sdata->u.mgd.mtx);
if (!ieee80211_assoc_success(wk, mgmt, skb->len)) {
mutex_unlock(&wk->sdata->u.mgd.mtx);
@@ -2464,6 +2477,11 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
}
cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len);
+ destroy:
+ if (wk->assoc.synced)
+ drv_finish_tx_sync(local, wk->sdata, wk->filter_ta,
+ IEEE80211_TX_SYNC_ASSOC);
+
return WORK_DONE_DESTROY;
}
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
index f0c74a1a9a02..380b9a7462b6 100644
--- a/net/mac80211/work.c
+++ b/net/mac80211/work.c
@@ -25,6 +25,7 @@
#include "ieee80211_i.h"
#include "rate.h"
+#include "driver-ops.h"
#define IEEE80211_AUTH_TIMEOUT (HZ / 5)
#define IEEE80211_AUTH_MAX_TRIES 3
@@ -427,6 +428,14 @@ ieee80211_direct_probe(struct ieee80211_work *wk)
struct ieee80211_sub_if_data *sdata = wk->sdata;
struct ieee80211_local *local = sdata->local;
+ if (!wk->probe_auth.synced) {
+ int ret = drv_tx_sync(local, sdata, wk->filter_ta,
+ IEEE80211_TX_SYNC_AUTH);
+ if (ret)
+ return WORK_ACT_TIMEOUT;
+ }
+ wk->probe_auth.synced = true;
+
wk->probe_auth.tries++;
if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) {
printk(KERN_DEBUG "%s: direct probe to %pM timed out\n",
@@ -466,6 +475,14 @@ ieee80211_authenticate(struct ieee80211_work *wk)
struct ieee80211_sub_if_data *sdata = wk->sdata;
struct ieee80211_local *local = sdata->local;
+ if (!wk->probe_auth.synced) {
+ int ret = drv_tx_sync(local, sdata, wk->filter_ta,
+ IEEE80211_TX_SYNC_AUTH);
+ if (ret)
+ return WORK_ACT_TIMEOUT;
+ }
+ wk->probe_auth.synced = true;
+
wk->probe_auth.tries++;
if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) {
printk(KERN_DEBUG "%s: authentication with %pM"
@@ -499,6 +516,14 @@ ieee80211_associate(struct ieee80211_work *wk)
struct ieee80211_sub_if_data *sdata = wk->sdata;
struct ieee80211_local *local = sdata->local;
+ if (!wk->assoc.synced) {
+ int ret = drv_tx_sync(local, sdata, wk->filter_ta,
+ IEEE80211_TX_SYNC_ASSOC);
+ if (ret)
+ return WORK_ACT_TIMEOUT;
+ }
+ wk->assoc.synced = true;
+
wk->assoc.tries++;
if (wk->assoc.tries > IEEE80211_ASSOC_MAX_TRIES) {
printk(KERN_DEBUG "%s: association with %pM"