aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2010-05-28 09:22:58 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-06-04 15:50:51 -0400
commit8b9a4e6e442756f670ef507f09bbc6c11dc0fca6 (patch)
treebed171512423a88dda5125f76568d481acaaabb4 /net/mac80211
parent56bf882230d2266a2e07b7f404dc96d157a65daa (diff)
mac80211: process station blockack action frames from work
Processing an association response could take a bit of time while we set up the hardware etc. During that time, the AP might already send a blockack request. If this happens very quickly on a fairly slow machine, we can end up processing the blockack request before the association processing has finished. Since the blockack processing cannot sleep right now, we also cannot make it wait in the driver. As a result, sometimes on slow machines the iwlagn driver gets totally confused, and no traffic can pass when the aggregation setup was done before the assoc setup completed. I'm working on a proper fix for this, which involves queuing all blockack category action frames from a work struct, and also allowing the ampdu_action driver callback to sleep, which will generally clean up the code and make things easier. However, this is a very involved and complex change. To fix the problem at hand in a way that can also be backported to stable, I've come up with this patch. Here, I simply process all aggregation action frames from the managed interface skb queue, which means their processing will be serialized with processing the association response, thereby fixing the problem. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Cc: stable@kernel.org Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/mlme.c52
-rw-r--r--net/mac80211/rx.c3
2 files changed, 48 insertions, 7 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 0839c4e8fd2..3310e70aa52 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1692,14 +1692,52 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
1692 rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); 1692 rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len);
1693 break; 1693 break;
1694 case IEEE80211_STYPE_ACTION: 1694 case IEEE80211_STYPE_ACTION:
1695 if (mgmt->u.action.category != WLAN_CATEGORY_SPECTRUM_MGMT) 1695 switch (mgmt->u.action.category) {
1696 case WLAN_CATEGORY_BACK: {
1697 struct ieee80211_local *local = sdata->local;
1698 int len = skb->len;
1699 struct sta_info *sta;
1700
1701 rcu_read_lock();
1702 sta = sta_info_get(sdata, mgmt->sa);
1703 if (!sta) {
1704 rcu_read_unlock();
1705 break;
1706 }
1707
1708 local_bh_disable();
1709
1710 switch (mgmt->u.action.u.addba_req.action_code) {
1711 case WLAN_ACTION_ADDBA_REQ:
1712 if (len < (IEEE80211_MIN_ACTION_SIZE +
1713 sizeof(mgmt->u.action.u.addba_req)))
1714 break;
1715 ieee80211_process_addba_request(local, sta, mgmt, len);
1716 break;
1717 case WLAN_ACTION_ADDBA_RESP:
1718 if (len < (IEEE80211_MIN_ACTION_SIZE +
1719 sizeof(mgmt->u.action.u.addba_resp)))
1720 break;
1721 ieee80211_process_addba_resp(local, sta, mgmt, len);
1722 break;
1723 case WLAN_ACTION_DELBA:
1724 if (len < (IEEE80211_MIN_ACTION_SIZE +
1725 sizeof(mgmt->u.action.u.delba)))
1726 break;
1727 ieee80211_process_delba(sdata, sta, mgmt, len);
1728 break;
1729 }
1730 local_bh_enable();
1731 rcu_read_unlock();
1696 break; 1732 break;
1697 1733 }
1698 ieee80211_sta_process_chanswitch(sdata, 1734 case WLAN_CATEGORY_SPECTRUM_MGMT:
1699 &mgmt->u.action.u.chan_switch.sw_elem, 1735 ieee80211_sta_process_chanswitch(sdata,
1700 (void *)ifmgd->associated->priv, 1736 &mgmt->u.action.u.chan_switch.sw_elem,
1701 rx_status->mactime); 1737 (void *)ifmgd->associated->priv,
1702 break; 1738 rx_status->mactime);
1739 break;
1740 }
1703 } 1741 }
1704 mutex_unlock(&ifmgd->mtx); 1742 mutex_unlock(&ifmgd->mtx);
1705 1743
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 5e0b65406c4..be9abc2e634 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1944,6 +1944,9 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
1944 if (len < IEEE80211_MIN_ACTION_SIZE + 1) 1944 if (len < IEEE80211_MIN_ACTION_SIZE + 1)
1945 break; 1945 break;
1946 1946
1947 if (sdata->vif.type == NL80211_IFTYPE_STATION)
1948 return ieee80211_sta_rx_mgmt(sdata, rx->skb);
1949
1947 switch (mgmt->u.action.u.addba_req.action_code) { 1950 switch (mgmt->u.action.u.addba_req.action_code) {
1948 case WLAN_ACTION_ADDBA_REQ: 1951 case WLAN_ACTION_ADDBA_REQ:
1949 if (len < (IEEE80211_MIN_ACTION_SIZE + 1952 if (len < (IEEE80211_MIN_ACTION_SIZE +