Commit 71364716 authored by Ron Rindjunsky's avatar Ron Rindjunsky Committed by David S. Miller

mac80211: A-MPDU Rx adding BAR handling capability

This patch adds the ability to handle Block Ack Request
Signed-off-by: default avatarRon Rindjunsky <ron.rindjunsky@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b580781e
...@@ -801,7 +801,8 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); ...@@ -801,7 +801,8 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
extern void *mac80211_wiphy_privid; /* for wiphy privid */ extern void *mac80211_wiphy_privid; /* for wiphy privid */
extern const unsigned char rfc1042_header[6]; extern const unsigned char rfc1042_header[6];
extern const unsigned char bridge_tunnel_header[6]; extern const unsigned char bridge_tunnel_header[6];
u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len); u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
enum ieee80211_if_types type);
int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
int rate, int erp, int short_preamble); int rate, int erp, int short_preamble);
void mac80211_ev_michael_mic_failure(struct net_device *dev, int keyidx, void mac80211_ev_michael_mic_failure(struct net_device *dev, int keyidx,
......
...@@ -24,6 +24,10 @@ ...@@ -24,6 +24,10 @@
#include "tkip.h" #include "tkip.h"
#include "wme.h" #include "wme.h"
u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
struct tid_ampdu_rx *tid_agg_rx,
struct sk_buff *skb, u16 mpdu_seq_num,
int bar_req);
/* /*
* monitor mode reception * monitor mode reception
* *
...@@ -64,7 +68,9 @@ static inline int should_drop_frame(struct ieee80211_rx_status *status, ...@@ -64,7 +68,9 @@ static inline int should_drop_frame(struct ieee80211_rx_status *status,
if (((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FTYPE)) == if (((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FTYPE)) ==
cpu_to_le16(IEEE80211_FTYPE_CTL)) && cpu_to_le16(IEEE80211_FTYPE_CTL)) &&
((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE)) != ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE)) !=
cpu_to_le16(IEEE80211_STYPE_PSPOLL))) cpu_to_le16(IEEE80211_STYPE_PSPOLL)) &&
((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE)) !=
cpu_to_le16(IEEE80211_STYPE_BACK_REQ)))
return 1; return 1;
return 0; return 0;
} }
...@@ -634,7 +640,8 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) ...@@ -634,7 +640,8 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
* BSSID to avoid keeping the current IBSS network alive in cases where * BSSID to avoid keeping the current IBSS network alive in cases where
* other STAs are using different BSSID. */ * other STAs are using different BSSID. */
if (rx->sdata->type == IEEE80211_IF_TYPE_IBSS) { if (rx->sdata->type == IEEE80211_IF_TYPE_IBSS) {
u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len); u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
IEEE80211_IF_TYPE_IBSS);
if (compare_ether_addr(bssid, rx->sdata->u.sta.bssid) == 0) if (compare_ether_addr(bssid, rx->sdata->u.sta.bssid) == 0)
sta->last_rx = jiffies; sta->last_rx = jiffies;
} else } else
...@@ -1376,6 +1383,49 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) ...@@ -1376,6 +1383,49 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
return TXRX_QUEUED; return TXRX_QUEUED;
} }
static ieee80211_txrx_result
ieee80211_rx_h_ctrl(struct ieee80211_txrx_data *rx)
{
struct ieee80211_local *local = rx->local;
struct ieee80211_hw *hw = &local->hw;
struct sk_buff *skb = rx->skb;
struct ieee80211_bar *bar = (struct ieee80211_bar *) skb->data;
struct tid_ampdu_rx *tid_agg_rx;
u16 start_seq_num;
u16 tid;
if (likely((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL))
return TXRX_CONTINUE;
if ((rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BACK_REQ) {
if (!rx->sta)
return TXRX_CONTINUE;
tid = le16_to_cpu(bar->control) >> 12;
tid_agg_rx = &(rx->sta->ampdu_mlme.tid_rx[tid]);
if (tid_agg_rx->state != HT_AGG_STATE_OPERATIONAL)
return TXRX_CONTINUE;
start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4;
/* reset session timer */
if (tid_agg_rx->timeout) {
unsigned long expires =
jiffies + (tid_agg_rx->timeout / 1000) * HZ;
mod_timer(&tid_agg_rx->session_timer, expires);
}
/* manage reordering buffer according to requested */
/* sequence number */
rcu_read_lock();
ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL,
start_seq_num, 1);
rcu_read_unlock();
return TXRX_DROP;
}
return TXRX_CONTINUE;
}
static ieee80211_txrx_result static ieee80211_txrx_result
ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx)
{ {
...@@ -1527,6 +1577,7 @@ ieee80211_rx_handler ieee80211_rx_handlers[] = ...@@ -1527,6 +1577,7 @@ ieee80211_rx_handler ieee80211_rx_handlers[] =
ieee80211_rx_h_remove_qos_control, ieee80211_rx_h_remove_qos_control,
ieee80211_rx_h_amsdu, ieee80211_rx_h_amsdu,
ieee80211_rx_h_data, ieee80211_rx_h_data,
ieee80211_rx_h_ctrl,
ieee80211_rx_h_mgmt, ieee80211_rx_h_mgmt,
NULL NULL
}; };
...@@ -1683,8 +1734,6 @@ void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, struct sk_buff *skb, ...@@ -1683,8 +1734,6 @@ void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, struct sk_buff *skb,
return; return;
} }
bssid = ieee80211_get_bssid(hdr, skb->len);
list_for_each_entry_rcu(sdata, &local->interfaces, list) { list_for_each_entry_rcu(sdata, &local->interfaces, list) {
if (!netif_running(sdata->dev)) if (!netif_running(sdata->dev))
continue; continue;
...@@ -1692,6 +1741,7 @@ void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, struct sk_buff *skb, ...@@ -1692,6 +1741,7 @@ void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, struct sk_buff *skb,
if (sdata->type == IEEE80211_IF_TYPE_MNTR) if (sdata->type == IEEE80211_IF_TYPE_MNTR)
continue; continue;
bssid = ieee80211_get_bssid(hdr, skb->len, sdata->type);
rx.flags |= IEEE80211_TXRXD_RXRA_MATCH; rx.flags |= IEEE80211_TXRXD_RXRA_MATCH;
prepares = prepare_for_handlers(sdata, bssid, &rx, hdr); prepares = prepare_for_handlers(sdata, bssid, &rx, hdr);
/* prepare_for_handlers can change sta */ /* prepare_for_handlers can change sta */
...@@ -1767,6 +1817,10 @@ static inline u16 seq_sub(u16 sq1, u16 sq2) ...@@ -1767,6 +1817,10 @@ static inline u16 seq_sub(u16 sq1, u16 sq2)
} }
/*
* As it function blongs to Rx path it must be called with
* the proper rcu_read_lock protection for its flow.
*/
u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
struct tid_ampdu_rx *tid_agg_rx, struct tid_ampdu_rx *tid_agg_rx,
struct sk_buff *skb, u16 mpdu_seq_num, struct sk_buff *skb, u16 mpdu_seq_num,
......
...@@ -127,7 +127,8 @@ void ieee80211_prepare_rates(struct ieee80211_local *local, ...@@ -127,7 +127,8 @@ void ieee80211_prepare_rates(struct ieee80211_local *local,
} }
} }
u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len) u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
enum ieee80211_if_types type)
{ {
u16 fc; u16 fc;
...@@ -159,6 +160,18 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len) ...@@ -159,6 +160,18 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len)
case IEEE80211_FTYPE_CTL: case IEEE80211_FTYPE_CTL:
if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL) if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)
return hdr->addr1; return hdr->addr1;
else if ((fc & IEEE80211_FCTL_STYPE) ==
IEEE80211_STYPE_BACK_REQ) {
switch (type) {
case IEEE80211_IF_TYPE_STA:
return hdr->addr2;
case IEEE80211_IF_TYPE_AP:
case IEEE80211_IF_TYPE_VLAN:
return hdr->addr1;
default:
return NULL;
}
}
else else
return NULL; return NULL;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment