mac80211: backport latest version from trunk (as of r28137)
[openwrt-10.03/.git] / package / mac80211 / patches / 560-mac80211_defer_bar_tx.patch
1 --- a/net/mac80211/sta_info.h
2 +++ b/net/mac80211/sta_info.h
3 @@ -84,6 +84,8 @@ enum ieee80211_sta_info_flags {
4   * @stop_initiator: initiator of a session stop
5   * @tx_stop: TX DelBA frame when stopping
6   * @buf_size: reorder buffer size at receiver
7 + * @failed_bar_ssn: ssn of the last failed BAR tx attempt
8 + * @bar_pending: BAR needs to be re-sent
9   *
10   * This structure's lifetime is managed by RCU, assignments to
11   * the array holding it must hold the aggregation mutex.
12 @@ -104,6 +106,9 @@ struct tid_ampdu_tx {
13         u8 stop_initiator;
14         bool tx_stop;
15         u8 buf_size;
16 +
17 +       u16 failed_bar_ssn;
18 +       bool bar_pending;
19  };
20  
21  /**
22 --- a/net/mac80211/status.c
23 +++ b/net/mac80211/status.c
24 @@ -127,12 +127,32 @@ static void ieee80211_handle_filtered_fr
25         dev_kfree_skb(skb);
26  }
27  
28 +static void ieee80211_check_pending_bar(struct sta_info *sta, u8 *addr, u8 tid)
29 +{
30 +       struct tid_ampdu_tx *tid_tx;
31 +
32 +       tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
33 +       if (!tid_tx || !tid_tx->bar_pending)
34 +               return;
35 +
36 +       tid_tx->bar_pending = false;
37 +       ieee80211_send_bar(sta->sdata, addr, tid, tid_tx->failed_bar_ssn);
38 +}
39 +
40  static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
41  {
42         struct ieee80211_mgmt *mgmt = (void *) skb->data;
43         struct ieee80211_local *local = sta->local;
44         struct ieee80211_sub_if_data *sdata = sta->sdata;
45  
46 +       if (ieee80211_is_data_qos(mgmt->frame_control)) {
47 +               struct ieee80211_hdr *hdr = (void *) skb->data;
48 +               u8 *qc = ieee80211_get_qos_ctl(hdr);
49 +               u16 tid = qc[0] & 0xf;
50 +
51 +               ieee80211_check_pending_bar(sta, hdr->addr1, tid);
52 +       }
53 +
54         if (ieee80211_is_action(mgmt->frame_control) &&
55             sdata->vif.type == NL80211_IFTYPE_STATION &&
56             mgmt->u.action.category == WLAN_CATEGORY_HT &&
57 @@ -161,6 +181,18 @@ static void ieee80211_frame_acked(struct
58         }
59  }
60  
61 +static void ieee80211_set_bar_pending(struct sta_info *sta, u8 tid, u16 ssn)
62 +{
63 +       struct tid_ampdu_tx *tid_tx;
64 +
65 +       tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
66 +       if (!tid_tx)
67 +               return;
68 +
69 +       tid_tx->failed_bar_ssn = ssn;
70 +       tid_tx->bar_pending = true;
71 +}
72 +
73  /*
74   * Use a static threshold for now, best value to be determined
75   * by testing ...
76 @@ -254,10 +286,13 @@ void ieee80211_tx_status(struct ieee8021
77                          */
78                         bar = (struct ieee80211_bar *) skb->data;
79                         if (!(bar->control & IEEE80211_BAR_CTRL_MULTI_TID)) {
80 +                               u16 ssn = le16_to_cpu(bar->start_seq_num);
81 +
82                                 tid = (bar->control &
83                                        IEEE80211_BAR_CTRL_TID_INFO_MASK) >>
84                                       IEEE80211_BAR_CTRL_TID_INFO_SHIFT;
85 -                               ieee80211_stop_tx_ba_session(&sta->sta, tid);
86 +
87 +                               ieee80211_set_bar_pending(sta, tid, ssn);
88                         }
89                 }
90