aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorRon Rindjunsky <ron.rindjunsky@intel.com>2007-12-25 10:00:35 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:01:00 -0500
commitb580781e038968fb2529460e8b61e3bf77de112a (patch)
tree7767e01c739010a2070c2a7534c6bd87a60b3b1b /net/mac80211
parent16c5f15c73e97e22a1fcc6518da32bdcf98aec3d (diff)
mac80211: A-MPDU Rx handling aggregation reordering
This patch handles the reordering of the Rx A-MPDU. This issue occurs when the sequence of the internal MPDUs is not in the right order. such a case can be encountered for example when some MPDUs from previous aggregations were recieved, while others failed, so current A-MPDU will contain a mix of re-transmited MPDUs and new ones. Signed-off-by: Ron Rindjunsky <ron.rindjunsky@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/ieee80211_sta.c10
-rw-r--r--net/mac80211/rx.c185
2 files changed, 192 insertions, 3 deletions
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index d5a7683fab3a..f1edaa0c0da3 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -1208,7 +1208,7 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid,
1208 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); 1208 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
1209 struct ieee80211_hw *hw = &local->hw; 1209 struct ieee80211_hw *hw = &local->hw;
1210 struct sta_info *sta; 1210 struct sta_info *sta;
1211 int ret; 1211 int ret, i;
1212 1212
1213 sta = sta_info_get(local, ra); 1213 sta = sta_info_get(local, ra);
1214 if (!sta) 1214 if (!sta)
@@ -1250,6 +1250,14 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid,
1250 ieee80211_send_delba(dev, ra, tid, 0, reason); 1250 ieee80211_send_delba(dev, ra, tid, 0, reason);
1251 1251
1252 /* free the reordering buffer */ 1252 /* free the reordering buffer */
1253 for (i = 0; i < sta->ampdu_mlme.tid_rx[tid].buf_size; i++) {
1254 if (sta->ampdu_mlme.tid_rx[tid].reorder_buf[i]) {
1255 /* release the reordered frames */
1256 dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid].reorder_buf[i]);
1257 sta->ampdu_mlme.tid_rx[tid].stored_mpdu_num--;
1258 sta->ampdu_mlme.tid_rx[tid].reorder_buf[i] = NULL;
1259 }
1260 }
1253 kfree(sta->ampdu_mlme.tid_rx[tid].reorder_buf); 1261 kfree(sta->ampdu_mlme.tid_rx[tid].reorder_buf);
1254 1262
1255 sta->ampdu_mlme.tid_rx[tid].state = HT_AGG_STATE_IDLE; 1263 sta->ampdu_mlme.tid_rx[tid].state = HT_AGG_STATE_IDLE;
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index a58a94b21401..e7b1eb8da25c 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -330,7 +330,6 @@ u32 ieee80211_rx_load_stats(struct ieee80211_local *local,
330 330
331 /* Divide channel_use by 8 to avoid wrapping around the counter */ 331 /* Divide channel_use by 8 to avoid wrapping around the counter */
332 load >>= CHAN_UTIL_SHIFT; 332 load >>= CHAN_UTIL_SHIFT;
333 local->channel_use_raw += load;
334 333
335 return load; 334 return load;
336} 335}
@@ -1749,6 +1748,186 @@ void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, struct sk_buff *skb,
1749 sta_info_put(sta); 1748 sta_info_put(sta);
1750} 1749}
1751 1750
1751#define SEQ_MODULO 0x1000
1752#define SEQ_MASK 0xfff
1753
1754static inline int seq_less(u16 sq1, u16 sq2)
1755{
1756 return (((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1));
1757}
1758
1759static inline u16 seq_inc(u16 sq)
1760{
1761 return ((sq + 1) & SEQ_MASK);
1762}
1763
1764static inline u16 seq_sub(u16 sq1, u16 sq2)
1765{
1766 return ((sq1 - sq2) & SEQ_MASK);
1767}
1768
1769
1770u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
1771 struct tid_ampdu_rx *tid_agg_rx,
1772 struct sk_buff *skb, u16 mpdu_seq_num,
1773 int bar_req)
1774{
1775 struct ieee80211_local *local = hw_to_local(hw);
1776 struct ieee80211_rx_status status;
1777 u16 head_seq_num, buf_size;
1778 int index;
1779 u32 pkt_load;
1780
1781 buf_size = tid_agg_rx->buf_size;
1782 head_seq_num = tid_agg_rx->head_seq_num;
1783
1784 /* frame with out of date sequence number */
1785 if (seq_less(mpdu_seq_num, head_seq_num)) {
1786 dev_kfree_skb(skb);
1787 return 1;
1788 }
1789
1790 /* if frame sequence number exceeds our buffering window size or
1791 * block Ack Request arrived - release stored frames */
1792 if ((!seq_less(mpdu_seq_num, head_seq_num + buf_size)) || (bar_req)) {
1793 /* new head to the ordering buffer */
1794 if (bar_req)
1795 head_seq_num = mpdu_seq_num;
1796 else
1797 head_seq_num =
1798 seq_inc(seq_sub(mpdu_seq_num, buf_size));
1799 /* release stored frames up to new head to stack */
1800 while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) {
1801 index = seq_sub(tid_agg_rx->head_seq_num,
1802 tid_agg_rx->ssn)
1803 % tid_agg_rx->buf_size;
1804
1805 if (tid_agg_rx->reorder_buf[index]) {
1806 /* release the reordered frames to stack */
1807 memcpy(&status,
1808 tid_agg_rx->reorder_buf[index]->cb,
1809 sizeof(status));
1810 pkt_load = ieee80211_rx_load_stats(local,
1811 tid_agg_rx->reorder_buf[index],
1812 &status);
1813 __ieee80211_rx_handle_packet(hw,
1814 tid_agg_rx->reorder_buf[index],
1815 &status, pkt_load);
1816 tid_agg_rx->stored_mpdu_num--;
1817 tid_agg_rx->reorder_buf[index] = NULL;
1818 }
1819 tid_agg_rx->head_seq_num =
1820 seq_inc(tid_agg_rx->head_seq_num);
1821 }
1822 if (bar_req)
1823 return 1;
1824 }
1825
1826 /* now the new frame is always in the range of the reordering */
1827 /* buffer window */
1828 index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn)
1829 % tid_agg_rx->buf_size;
1830 /* check if we already stored this frame */
1831 if (tid_agg_rx->reorder_buf[index]) {
1832 dev_kfree_skb(skb);
1833 return 1;
1834 }
1835
1836 /* if arrived mpdu is in the right order and nothing else stored */
1837 /* release it immediately */
1838 if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
1839 tid_agg_rx->stored_mpdu_num == 0) {
1840 tid_agg_rx->head_seq_num =
1841 seq_inc(tid_agg_rx->head_seq_num);
1842 return 0;
1843 }
1844
1845 /* put the frame in the reordering buffer */
1846 tid_agg_rx->reorder_buf[index] = skb;
1847 tid_agg_rx->stored_mpdu_num++;
1848 /* release the buffer until next missing frame */
1849 index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn)
1850 % tid_agg_rx->buf_size;
1851 while (tid_agg_rx->reorder_buf[index]) {
1852 /* release the reordered frame back to stack */
1853 memcpy(&status, tid_agg_rx->reorder_buf[index]->cb,
1854 sizeof(status));
1855 pkt_load = ieee80211_rx_load_stats(local,
1856 tid_agg_rx->reorder_buf[index],
1857 &status);
1858 __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index],
1859 &status, pkt_load);
1860 tid_agg_rx->stored_mpdu_num--;
1861 tid_agg_rx->reorder_buf[index] = NULL;
1862 tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
1863 index = seq_sub(tid_agg_rx->head_seq_num,
1864 tid_agg_rx->ssn) % tid_agg_rx->buf_size;
1865 }
1866 return 1;
1867}
1868
1869u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
1870 struct sk_buff *skb)
1871{
1872 struct ieee80211_hw *hw = &local->hw;
1873 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1874 struct sta_info *sta;
1875 struct tid_ampdu_rx *tid_agg_rx;
1876 u16 fc, sc;
1877 u16 mpdu_seq_num;
1878 u8 ret = 0, *qc;
1879 int tid;
1880
1881 sta = sta_info_get(local, hdr->addr2);
1882 if (!sta)
1883 return ret;
1884
1885 fc = le16_to_cpu(hdr->frame_control);
1886
1887 /* filter the QoS data rx stream according to
1888 * STA/TID and check if this STA/TID is on aggregation */
1889 if (!WLAN_FC_IS_QOS_DATA(fc))
1890 goto end_reorder;
1891
1892 qc = skb->data + ieee80211_get_hdrlen(fc) - QOS_CONTROL_LEN;
1893 tid = qc[0] & QOS_CONTROL_TID_MASK;
1894 tid_agg_rx = &(sta->ampdu_mlme.tid_rx[tid]);
1895
1896 if (tid_agg_rx->state != HT_AGG_STATE_OPERATIONAL)
1897 goto end_reorder;
1898
1899 /* null data frames are excluded */
1900 if (unlikely(fc & IEEE80211_STYPE_QOS_NULLFUNC))
1901 goto end_reorder;
1902
1903 /* new un-ordered ampdu frame - process it */
1904
1905 /* reset session timer */
1906 if (tid_agg_rx->timeout) {
1907 unsigned long expires =
1908 jiffies + (tid_agg_rx->timeout / 1000) * HZ;
1909 mod_timer(&tid_agg_rx->session_timer, expires);
1910 }
1911
1912 /* if this mpdu is fragmented - terminate rx aggregation session */
1913 sc = le16_to_cpu(hdr->seq_ctrl);
1914 if (sc & IEEE80211_SCTL_FRAG) {
1915 ieee80211_sta_stop_rx_ba_session(sta->dev, sta->addr,
1916 tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP);
1917 ret = 1;
1918 goto end_reorder;
1919 }
1920
1921 /* according to mpdu sequence number deal with reordering buffer */
1922 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
1923 ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb,
1924 mpdu_seq_num, 0);
1925end_reorder:
1926 if (sta)
1927 sta_info_put(sta);
1928 return ret;
1929}
1930
1752/* 1931/*
1753 * This is the receive path handler. It is called by a low level driver when an 1932 * This is the receive path handler. It is called by a low level driver when an
1754 * 802.11 MPDU is received from the hardware. 1933 * 802.11 MPDU is received from the hardware.
@@ -1779,8 +1958,10 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
1779 } 1958 }
1780 1959
1781 pkt_load = ieee80211_rx_load_stats(local, skb, status); 1960 pkt_load = ieee80211_rx_load_stats(local, skb, status);
1961 local->channel_use_raw += pkt_load;
1782 1962
1783 __ieee80211_rx_handle_packet(hw, skb, status, pkt_load); 1963 if (!ieee80211_rx_reorder_ampdu(local, skb))
1964 __ieee80211_rx_handle_packet(hw, skb, status, pkt_load);
1784 1965
1785 rcu_read_unlock(); 1966 rcu_read_unlock();
1786} 1967}