summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/mac80211.h42
-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
6 files changed, 164 insertions, 3 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 972109f06a70..9259e97864d7 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1586,6 +1586,20 @@ enum ieee80211_ampdu_mlme_action {
1586}; 1586};
1587 1587
1588/** 1588/**
1589 * enum ieee80211_tx_sync_type - TX sync type
1590 * @IEEE80211_TX_SYNC_AUTH: sync TX for authentication
1591 * (and possibly also before direct probe)
1592 * @IEEE80211_TX_SYNC_ASSOC: sync TX for association
1593 * @IEEE80211_TX_SYNC_ACTION: sync TX for action frame
1594 * (not implemented yet)
1595 */
1596enum ieee80211_tx_sync_type {
1597 IEEE80211_TX_SYNC_AUTH,
1598 IEEE80211_TX_SYNC_ASSOC,
1599 IEEE80211_TX_SYNC_ACTION,
1600};
1601
1602/**
1589 * struct ieee80211_ops - callbacks from mac80211 to the driver 1603 * struct ieee80211_ops - callbacks from mac80211 to the driver
1590 * 1604 *
1591 * This structure contains various callbacks that the driver may 1605 * This structure contains various callbacks that the driver may
@@ -1674,6 +1688,26 @@ enum ieee80211_ampdu_mlme_action {
1674 * of the bss parameters has changed when a call is made. The callback 1688 * of the bss parameters has changed when a call is made. The callback
1675 * can sleep. 1689 * can sleep.
1676 * 1690 *
1691 * @tx_sync: Called before a frame is sent to an AP/GO. In the GO case, the
1692 * driver should sync with the GO's powersaving so the device doesn't
1693 * transmit the frame while the GO is asleep. In the regular AP case
1694 * it may be used by drivers for devices implementing other restrictions
1695 * on talking to APs, e.g. due to regulatory enforcement or just HW
1696 * restrictions.
1697 * This function is called for every authentication, association and
1698 * action frame separately since applications might attempt to auth
1699 * with multiple APs before chosing one to associate to. If it returns
1700 * an error, the corresponding authentication, association or frame
1701 * transmission is aborted and reported as having failed. It is always
1702 * called after tuning to the correct channel.
1703 * The callback might be called multiple times before @finish_tx_sync
1704 * (but @finish_tx_sync will be called once for each) but in practice
1705 * this is unlikely to happen. It can also refuse in that case if the
1706 * driver cannot handle that situation.
1707 * This callback can sleep.
1708 * @finish_tx_sync: Called as a counterpart to @tx_sync, unless that returned
1709 * an error. This callback can sleep.
1710 *
1677 * @prepare_multicast: Prepare for multicast filter configuration. 1711 * @prepare_multicast: Prepare for multicast filter configuration.
1678 * This callback is optional, and its return value is passed 1712 * This callback is optional, and its return value is passed
1679 * to configure_filter(). This callback must be atomic. 1713 * to configure_filter(). This callback must be atomic.
@@ -1901,6 +1935,14 @@ struct ieee80211_ops {
1901 struct ieee80211_vif *vif, 1935 struct ieee80211_vif *vif,
1902 struct ieee80211_bss_conf *info, 1936 struct ieee80211_bss_conf *info,
1903 u32 changed); 1937 u32 changed);
1938
1939 int (*tx_sync)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1940 const u8 *bssid, enum ieee80211_tx_sync_type type);
1941 void (*finish_tx_sync)(struct ieee80211_hw *hw,
1942 struct ieee80211_vif *vif,
1943 const u8 *bssid,
1944 enum ieee80211_tx_sync_type type);
1945
1904 u64 (*prepare_multicast)(struct ieee80211_hw *hw, 1946 u64 (*prepare_multicast)(struct ieee80211_hw *hw,
1905 struct netdev_hw_addr_list *mc_list); 1947 struct netdev_hw_addr_list *mc_list);
1906 void (*configure_filter)(struct ieee80211_hw *hw, 1948 void (*configure_filter)(struct ieee80211_hw *hw,
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,
130 trace_drv_return_void(local); 130 trace_drv_return_void(local);
131} 131}
132 132
133static inline int drv_tx_sync(struct ieee80211_local *local,
134 struct ieee80211_sub_if_data *sdata,
135 const u8 *bssid,
136 enum ieee80211_tx_sync_type type)
137{
138 int ret = 0;
139
140 might_sleep();
141
142 trace_drv_tx_sync(local, sdata, bssid, type);
143 if (local->ops->tx_sync)
144 ret = local->ops->tx_sync(&local->hw, &sdata->vif,
145 bssid, type);
146 trace_drv_return_int(local, ret);
147 return ret;
148}
149
150static inline void drv_finish_tx_sync(struct ieee80211_local *local,
151 struct ieee80211_sub_if_data *sdata,
152 const u8 *bssid,
153 enum ieee80211_tx_sync_type type)
154{
155 might_sleep();
156
157 trace_drv_finish_tx_sync(local, sdata, bssid, type);
158 if (local->ops->finish_tx_sync)
159 local->ops->finish_tx_sync(&local->hw, &sdata->vif,
160 bssid, type);
161 trace_drv_return_void(local);
162}
163
133static inline u64 drv_prepare_multicast(struct ieee80211_local *local, 164static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
134 struct netdev_hw_addr_list *mc_list) 165 struct netdev_hw_addr_list *mc_list)
135{ 166{
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,
319 ) 319 )
320); 320);
321 321
322DECLARE_EVENT_CLASS(tx_sync_evt,
323 TP_PROTO(struct ieee80211_local *local,
324 struct ieee80211_sub_if_data *sdata,
325 const u8 *bssid,
326 enum ieee80211_tx_sync_type type),
327 TP_ARGS(local, sdata, bssid, type),
328
329 TP_STRUCT__entry(
330 LOCAL_ENTRY
331 VIF_ENTRY
332 __array(char, bssid, ETH_ALEN)
333 __field(u32, sync_type)
334 ),
335
336 TP_fast_assign(
337 LOCAL_ASSIGN;
338 VIF_ASSIGN;
339 memcpy(__entry->bssid, bssid, ETH_ALEN);
340 __entry->sync_type = type;
341 ),
342
343 TP_printk(
344 LOCAL_PR_FMT VIF_PR_FMT " bssid:%pM type:%d",
345 LOCAL_PR_ARG, VIF_PR_ARG, __entry->bssid, __entry->sync_type
346 )
347);
348
349DEFINE_EVENT(tx_sync_evt, drv_tx_sync,
350 TP_PROTO(struct ieee80211_local *local,
351 struct ieee80211_sub_if_data *sdata,
352 const u8 *bssid,
353 enum ieee80211_tx_sync_type type),
354 TP_ARGS(local, sdata, bssid, type)
355);
356
357DEFINE_EVENT(tx_sync_evt, drv_finish_tx_sync,
358 TP_PROTO(struct ieee80211_local *local,
359 struct ieee80211_sub_if_data *sdata,
360 const u8 *bssid,
361 enum ieee80211_tx_sync_type type),
362 TP_ARGS(local, sdata, bssid, type)
363);
364
322TRACE_EVENT(drv_prepare_multicast, 365TRACE_EVENT(drv_prepare_multicast,
323 TP_PROTO(struct ieee80211_local *local, int mc_count), 366 TP_PROTO(struct ieee80211_local *local, int mc_count),
324 367
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 {
323 u8 key[WLAN_KEY_LEN_WEP104]; 323 u8 key[WLAN_KEY_LEN_WEP104];
324 u8 key_len, key_idx; 324 u8 key_len, key_idx;
325 bool privacy; 325 bool privacy;
326 bool synced;
326 } probe_auth; 327 } probe_auth;
327 struct { 328 struct {
328 struct cfg80211_bss *bss; 329 struct cfg80211_bss *bss;
@@ -336,6 +337,7 @@ struct ieee80211_work {
336 u8 ssid_len; 337 u8 ssid_len;
337 u8 supp_rates_len; 338 u8 supp_rates_len;
338 bool wmm_used, use_11n, uapsd_used; 339 bool wmm_used, use_11n, uapsd_used;
340 bool synced;
339 } assoc; 341 } assoc;
340 struct { 342 struct {
341 u32 duration; 343 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
2335ieee80211_probe_auth_done(struct ieee80211_work *wk, 2335ieee80211_probe_auth_done(struct ieee80211_work *wk,
2336 struct sk_buff *skb) 2336 struct sk_buff *skb)
2337{ 2337{
2338 struct ieee80211_local *local = wk->sdata->local;
2339
2338 if (!skb) { 2340 if (!skb) {
2339 cfg80211_send_auth_timeout(wk->sdata->dev, wk->filter_ta); 2341 cfg80211_send_auth_timeout(wk->sdata->dev, wk->filter_ta);
2340 return WORK_DONE_DESTROY; 2342 goto destroy;
2341 } 2343 }
2342 2344
2343 if (wk->type == IEEE80211_WORK_AUTH) { 2345 if (wk->type == IEEE80211_WORK_AUTH) {
2344 cfg80211_send_rx_auth(wk->sdata->dev, skb->data, skb->len); 2346 cfg80211_send_rx_auth(wk->sdata->dev, skb->data, skb->len);
2345 return WORK_DONE_DESTROY; 2347 goto destroy;
2346 } 2348 }
2347 2349
2348 mutex_lock(&wk->sdata->u.mgd.mtx); 2350 mutex_lock(&wk->sdata->u.mgd.mtx);
@@ -2352,6 +2354,12 @@ ieee80211_probe_auth_done(struct ieee80211_work *wk,
2352 wk->type = IEEE80211_WORK_AUTH; 2354 wk->type = IEEE80211_WORK_AUTH;
2353 wk->probe_auth.tries = 0; 2355 wk->probe_auth.tries = 0;
2354 return WORK_DONE_REQUEUE; 2356 return WORK_DONE_REQUEUE;
2357 destroy:
2358 if (wk->probe_auth.synced)
2359 drv_finish_tx_sync(local, wk->sdata, wk->filter_ta,
2360 IEEE80211_TX_SYNC_AUTH);
2361
2362 return WORK_DONE_DESTROY;
2355} 2363}
2356 2364
2357int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, 2365int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
@@ -2424,6 +2432,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
2424static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, 2432static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
2425 struct sk_buff *skb) 2433 struct sk_buff *skb)
2426{ 2434{
2435 struct ieee80211_local *local = wk->sdata->local;
2427 struct ieee80211_mgmt *mgmt; 2436 struct ieee80211_mgmt *mgmt;
2428 struct ieee80211_rx_status *rx_status; 2437 struct ieee80211_rx_status *rx_status;
2429 struct ieee802_11_elems elems; 2438 struct ieee802_11_elems elems;
@@ -2431,7 +2440,7 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
2431 2440
2432 if (!skb) { 2441 if (!skb) {
2433 cfg80211_send_assoc_timeout(wk->sdata->dev, wk->filter_ta); 2442 cfg80211_send_assoc_timeout(wk->sdata->dev, wk->filter_ta);
2434 return WORK_DONE_DESTROY; 2443 goto destroy;
2435 } 2444 }
2436 2445
2437 if (wk->type == IEEE80211_WORK_ASSOC_BEACON_WAIT) { 2446 if (wk->type == IEEE80211_WORK_ASSOC_BEACON_WAIT) {
@@ -2451,6 +2460,10 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
2451 status = le16_to_cpu(mgmt->u.assoc_resp.status_code); 2460 status = le16_to_cpu(mgmt->u.assoc_resp.status_code);
2452 2461
2453 if (status == WLAN_STATUS_SUCCESS) { 2462 if (status == WLAN_STATUS_SUCCESS) {
2463 if (wk->assoc.synced)
2464 drv_finish_tx_sync(local, wk->sdata, wk->filter_ta,
2465 IEEE80211_TX_SYNC_ASSOC);
2466
2454 mutex_lock(&wk->sdata->u.mgd.mtx); 2467 mutex_lock(&wk->sdata->u.mgd.mtx);
2455 if (!ieee80211_assoc_success(wk, mgmt, skb->len)) { 2468 if (!ieee80211_assoc_success(wk, mgmt, skb->len)) {
2456 mutex_unlock(&wk->sdata->u.mgd.mtx); 2469 mutex_unlock(&wk->sdata->u.mgd.mtx);
@@ -2464,6 +2477,11 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
2464 } 2477 }
2465 2478
2466 cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len); 2479 cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len);
2480 destroy:
2481 if (wk->assoc.synced)
2482 drv_finish_tx_sync(local, wk->sdata, wk->filter_ta,
2483 IEEE80211_TX_SYNC_ASSOC);
2484
2467 return WORK_DONE_DESTROY; 2485 return WORK_DONE_DESTROY;
2468} 2486}
2469 2487
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 @@
25 25
26#include "ieee80211_i.h" 26#include "ieee80211_i.h"
27#include "rate.h" 27#include "rate.h"
28#include "driver-ops.h"
28 29
29#define IEEE80211_AUTH_TIMEOUT (HZ / 5) 30#define IEEE80211_AUTH_TIMEOUT (HZ / 5)
30#define IEEE80211_AUTH_MAX_TRIES 3 31#define IEEE80211_AUTH_MAX_TRIES 3
@@ -427,6 +428,14 @@ ieee80211_direct_probe(struct ieee80211_work *wk)
427 struct ieee80211_sub_if_data *sdata = wk->sdata; 428 struct ieee80211_sub_if_data *sdata = wk->sdata;
428 struct ieee80211_local *local = sdata->local; 429 struct ieee80211_local *local = sdata->local;
429 430
431 if (!wk->probe_auth.synced) {
432 int ret = drv_tx_sync(local, sdata, wk->filter_ta,
433 IEEE80211_TX_SYNC_AUTH);
434 if (ret)
435 return WORK_ACT_TIMEOUT;
436 }
437 wk->probe_auth.synced = true;
438
430 wk->probe_auth.tries++; 439 wk->probe_auth.tries++;
431 if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) { 440 if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) {
432 printk(KERN_DEBUG "%s: direct probe to %pM timed out\n", 441 printk(KERN_DEBUG "%s: direct probe to %pM timed out\n",
@@ -466,6 +475,14 @@ ieee80211_authenticate(struct ieee80211_work *wk)
466 struct ieee80211_sub_if_data *sdata = wk->sdata; 475 struct ieee80211_sub_if_data *sdata = wk->sdata;
467 struct ieee80211_local *local = sdata->local; 476 struct ieee80211_local *local = sdata->local;
468 477
478 if (!wk->probe_auth.synced) {
479 int ret = drv_tx_sync(local, sdata, wk->filter_ta,
480 IEEE80211_TX_SYNC_AUTH);
481 if (ret)
482 return WORK_ACT_TIMEOUT;
483 }
484 wk->probe_auth.synced = true;
485
469 wk->probe_auth.tries++; 486 wk->probe_auth.tries++;
470 if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) { 487 if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) {
471 printk(KERN_DEBUG "%s: authentication with %pM" 488 printk(KERN_DEBUG "%s: authentication with %pM"
@@ -499,6 +516,14 @@ ieee80211_associate(struct ieee80211_work *wk)
499 struct ieee80211_sub_if_data *sdata = wk->sdata; 516 struct ieee80211_sub_if_data *sdata = wk->sdata;
500 struct ieee80211_local *local = sdata->local; 517 struct ieee80211_local *local = sdata->local;
501 518
519 if (!wk->assoc.synced) {
520 int ret = drv_tx_sync(local, sdata, wk->filter_ta,
521 IEEE80211_TX_SYNC_ASSOC);
522 if (ret)
523 return WORK_ACT_TIMEOUT;
524 }
525 wk->assoc.synced = true;
526
502 wk->assoc.tries++; 527 wk->assoc.tries++;
503 if (wk->assoc.tries > IEEE80211_ASSOC_MAX_TRIES) { 528 if (wk->assoc.tries > IEEE80211_ASSOC_MAX_TRIES) {
504 printk(KERN_DEBUG "%s: association with %pM" 529 printk(KERN_DEBUG "%s: association with %pM"