mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
This commit is contained in:
commit
8f56874bd7
88 changed files with 3161 additions and 2262 deletions
|
|
@ -131,17 +131,35 @@ TRACE_EVENT(drv_config,
|
|||
LOCAL_ENTRY
|
||||
__field(u32, changed)
|
||||
__field(int, ret)
|
||||
__field(u32, flags)
|
||||
__field(int, power_level)
|
||||
__field(int, dynamic_ps_timeout)
|
||||
__field(int, max_sleep_period)
|
||||
__field(u16, listen_interval)
|
||||
__field(u8, long_frame_max_tx_count)
|
||||
__field(u8, short_frame_max_tx_count)
|
||||
__field(int, center_freq)
|
||||
__field(int, channel_type)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
__entry->changed = changed;
|
||||
__entry->ret = ret;
|
||||
__entry->flags = local->hw.conf.flags;
|
||||
__entry->power_level = local->hw.conf.power_level;
|
||||
__entry->dynamic_ps_timeout = local->hw.conf.dynamic_ps_timeout;
|
||||
__entry->max_sleep_period = local->hw.conf.max_sleep_period;
|
||||
__entry->listen_interval = local->hw.conf.listen_interval;
|
||||
__entry->long_frame_max_tx_count = local->hw.conf.long_frame_max_tx_count;
|
||||
__entry->short_frame_max_tx_count = local->hw.conf.short_frame_max_tx_count;
|
||||
__entry->center_freq = local->hw.conf.channel->center_freq;
|
||||
__entry->channel_type = local->hw.conf.channel_type;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT " ch:%#x ret:%d",
|
||||
LOCAL_PR_ARG, __entry->changed, __entry->ret
|
||||
LOCAL_PR_FMT " ch:%#x freq:%d ret:%d",
|
||||
LOCAL_PR_ARG, __entry->changed, __entry->center_freq, __entry->ret
|
||||
)
|
||||
);
|
||||
|
||||
|
|
@ -167,6 +185,8 @@ TRACE_EVENT(drv_bss_info_changed,
|
|||
__field(u64, timestamp)
|
||||
__field(u32, basic_rates)
|
||||
__field(u32, changed)
|
||||
__field(bool, enable_beacon)
|
||||
__field(u16, ht_operation_mode)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
|
|
@ -183,6 +203,8 @@ TRACE_EVENT(drv_bss_info_changed,
|
|||
__entry->assoc_cap = info->assoc_capability;
|
||||
__entry->timestamp = info->timestamp;
|
||||
__entry->basic_rates = info->basic_rates;
|
||||
__entry->enable_beacon = info->enable_beacon;
|
||||
__entry->ht_operation_mode = info->ht_operation_mode;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
|
|
|
|||
|
|
@ -163,8 +163,8 @@ typedef unsigned __bitwise__ ieee80211_rx_result;
|
|||
/* frame is destined to interface currently processed (incl. multicast frames) */
|
||||
#define IEEE80211_RX_RA_MATCH BIT(1)
|
||||
#define IEEE80211_RX_AMSDU BIT(2)
|
||||
#define IEEE80211_RX_CMNTR_REPORTED BIT(3)
|
||||
#define IEEE80211_RX_FRAGMENTED BIT(4)
|
||||
#define IEEE80211_RX_FRAGMENTED BIT(3)
|
||||
/* only add flags here that do not change with subframes of an aMPDU */
|
||||
|
||||
struct ieee80211_rx_data {
|
||||
struct sk_buff *skb;
|
||||
|
|
|
|||
|
|
@ -860,22 +860,18 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata)
|
|||
void ieee80211_remove_interfaces(struct ieee80211_local *local)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata, *tmp;
|
||||
LIST_HEAD(unreg_list);
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
|
||||
/*
|
||||
* we cannot hold the iflist_mtx across unregister_netdevice,
|
||||
* but we only need to hold it for list modifications to lock
|
||||
* out readers since we're under the RTNL here as all other
|
||||
* writers.
|
||||
*/
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
list_del(&sdata->list);
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
|
||||
unregister_netdevice(sdata->dev);
|
||||
unregister_netdevice_queue(sdata->dev, &unreg_list);
|
||||
}
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
unregister_netdevice_many(&unreg_list);
|
||||
}
|
||||
|
||||
static u32 ieee80211_idle_off(struct ieee80211_local *local,
|
||||
|
|
|
|||
|
|
@ -27,10 +27,6 @@
|
|||
#include "tkip.h"
|
||||
#include "wme.h"
|
||||
|
||||
static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
|
||||
struct tid_ampdu_rx *tid_agg_rx,
|
||||
u16 head_seq_num);
|
||||
|
||||
/*
|
||||
* monitor mode reception
|
||||
*
|
||||
|
|
@ -534,6 +530,242 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
|
|||
return RX_CONTINUE;
|
||||
}
|
||||
|
||||
#define SEQ_MODULO 0x1000
|
||||
#define SEQ_MASK 0xfff
|
||||
|
||||
static inline int seq_less(u16 sq1, u16 sq2)
|
||||
{
|
||||
return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1);
|
||||
}
|
||||
|
||||
static inline u16 seq_inc(u16 sq)
|
||||
{
|
||||
return (sq + 1) & SEQ_MASK;
|
||||
}
|
||||
|
||||
static inline u16 seq_sub(u16 sq1, u16 sq2)
|
||||
{
|
||||
return (sq1 - sq2) & SEQ_MASK;
|
||||
}
|
||||
|
||||
|
||||
static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw,
|
||||
struct tid_ampdu_rx *tid_agg_rx,
|
||||
int index,
|
||||
struct sk_buff_head *frames)
|
||||
{
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_rate *rate = NULL;
|
||||
struct sk_buff *skb = tid_agg_rx->reorder_buf[index];
|
||||
struct ieee80211_rx_status *status;
|
||||
|
||||
if (!skb)
|
||||
goto no_frame;
|
||||
|
||||
status = IEEE80211_SKB_RXCB(skb);
|
||||
|
||||
/* release the reordered frames to stack */
|
||||
sband = hw->wiphy->bands[status->band];
|
||||
if (!(status->flag & RX_FLAG_HT))
|
||||
rate = &sband->bitrates[status->rate_idx];
|
||||
tid_agg_rx->stored_mpdu_num--;
|
||||
tid_agg_rx->reorder_buf[index] = NULL;
|
||||
skb_queue_tail(frames, skb);
|
||||
|
||||
no_frame:
|
||||
tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
|
||||
}
|
||||
|
||||
static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
|
||||
struct tid_ampdu_rx *tid_agg_rx,
|
||||
u16 head_seq_num,
|
||||
struct sk_buff_head *frames)
|
||||
{
|
||||
int index;
|
||||
|
||||
while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) {
|
||||
index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
|
||||
tid_agg_rx->buf_size;
|
||||
ieee80211_release_reorder_frame(hw, tid_agg_rx, index, frames);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Timeout (in jiffies) for skb's that are waiting in the RX reorder buffer. If
|
||||
* the skb was added to the buffer longer than this time ago, the earlier
|
||||
* frames that have not yet been received are assumed to be lost and the skb
|
||||
* can be released for processing. This may also release other skb's from the
|
||||
* reorder buffer if there are no additional gaps between the frames.
|
||||
*/
|
||||
#define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10)
|
||||
|
||||
/*
|
||||
* As this function belongs to the RX path it must be under
|
||||
* rcu_read_lock protection. It returns false if the frame
|
||||
* can be processed immediately, true if it was consumed.
|
||||
*/
|
||||
static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
|
||||
struct tid_ampdu_rx *tid_agg_rx,
|
||||
struct sk_buff *skb,
|
||||
struct sk_buff_head *frames)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
u16 sc = le16_to_cpu(hdr->seq_ctrl);
|
||||
u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
|
||||
u16 head_seq_num, buf_size;
|
||||
int index;
|
||||
|
||||
buf_size = tid_agg_rx->buf_size;
|
||||
head_seq_num = tid_agg_rx->head_seq_num;
|
||||
|
||||
/* frame with out of date sequence number */
|
||||
if (seq_less(mpdu_seq_num, head_seq_num)) {
|
||||
dev_kfree_skb(skb);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* If frame the sequence number exceeds our buffering window
|
||||
* size release some previous frames to make room for this one.
|
||||
*/
|
||||
if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) {
|
||||
head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size));
|
||||
/* release stored frames up to new head to stack */
|
||||
ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num,
|
||||
frames);
|
||||
}
|
||||
|
||||
/* Now the new frame is always in the range of the reordering buffer */
|
||||
|
||||
index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size;
|
||||
|
||||
/* check if we already stored this frame */
|
||||
if (tid_agg_rx->reorder_buf[index]) {
|
||||
dev_kfree_skb(skb);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the current MPDU is in the right order and nothing else
|
||||
* is stored we can process it directly, no need to buffer it.
|
||||
*/
|
||||
if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
|
||||
tid_agg_rx->stored_mpdu_num == 0) {
|
||||
tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* put the frame in the reordering buffer */
|
||||
tid_agg_rx->reorder_buf[index] = skb;
|
||||
tid_agg_rx->reorder_time[index] = jiffies;
|
||||
tid_agg_rx->stored_mpdu_num++;
|
||||
/* release the buffer until next missing frame */
|
||||
index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
|
||||
tid_agg_rx->buf_size;
|
||||
if (!tid_agg_rx->reorder_buf[index] &&
|
||||
tid_agg_rx->stored_mpdu_num > 1) {
|
||||
/*
|
||||
* No buffers ready to be released, but check whether any
|
||||
* frames in the reorder buffer have timed out.
|
||||
*/
|
||||
int j;
|
||||
int skipped = 1;
|
||||
for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
|
||||
j = (j + 1) % tid_agg_rx->buf_size) {
|
||||
if (!tid_agg_rx->reorder_buf[j]) {
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
if (!time_after(jiffies, tid_agg_rx->reorder_time[j] +
|
||||
HT_RX_REORDER_BUF_TIMEOUT))
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
if (net_ratelimit())
|
||||
printk(KERN_DEBUG "%s: release an RX reorder "
|
||||
"frame due to timeout on earlier "
|
||||
"frames\n",
|
||||
wiphy_name(hw->wiphy));
|
||||
#endif
|
||||
ieee80211_release_reorder_frame(hw, tid_agg_rx,
|
||||
j, frames);
|
||||
|
||||
/*
|
||||
* Increment the head seq# also for the skipped slots.
|
||||
*/
|
||||
tid_agg_rx->head_seq_num =
|
||||
(tid_agg_rx->head_seq_num + skipped) & SEQ_MASK;
|
||||
skipped = 0;
|
||||
}
|
||||
} else while (tid_agg_rx->reorder_buf[index]) {
|
||||
ieee80211_release_reorder_frame(hw, tid_agg_rx, index, frames);
|
||||
index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
|
||||
tid_agg_rx->buf_size;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reorder MPDUs from A-MPDUs, keeping them on a buffer. Returns
|
||||
* true if the MPDU was buffered, false if it should be processed.
|
||||
*/
|
||||
static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
|
||||
struct sk_buff_head *frames)
|
||||
{
|
||||
struct sk_buff *skb = rx->skb;
|
||||
struct ieee80211_local *local = rx->local;
|
||||
struct ieee80211_hw *hw = &local->hw;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
struct sta_info *sta = rx->sta;
|
||||
struct tid_ampdu_rx *tid_agg_rx;
|
||||
u16 sc;
|
||||
int tid;
|
||||
|
||||
if (!ieee80211_is_data_qos(hdr->frame_control))
|
||||
goto dont_reorder;
|
||||
|
||||
/*
|
||||
* filter the QoS data rx stream according to
|
||||
* STA/TID and check if this STA/TID is on aggregation
|
||||
*/
|
||||
|
||||
if (!sta)
|
||||
goto dont_reorder;
|
||||
|
||||
tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
|
||||
|
||||
if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL)
|
||||
goto dont_reorder;
|
||||
|
||||
tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
|
||||
|
||||
/* qos null data frames are excluded */
|
||||
if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
|
||||
goto dont_reorder;
|
||||
|
||||
/* new, potentially un-ordered, ampdu frame - process it */
|
||||
|
||||
/* reset session timer */
|
||||
if (tid_agg_rx->timeout)
|
||||
mod_timer(&tid_agg_rx->session_timer,
|
||||
TU_TO_EXP_TIME(tid_agg_rx->timeout));
|
||||
|
||||
/* if this mpdu is fragmented - terminate rx aggregation session */
|
||||
sc = le16_to_cpu(hdr->seq_ctrl);
|
||||
if (sc & IEEE80211_SCTL_FRAG) {
|
||||
ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
|
||||
tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP);
|
||||
dev_kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, frames))
|
||||
return;
|
||||
|
||||
dont_reorder:
|
||||
__skb_queue_tail(frames, skb);
|
||||
}
|
||||
|
||||
static ieee80211_rx_result debug_noinline
|
||||
ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
|
||||
|
|
@ -637,6 +869,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
|
|||
if (!(rx->flags & IEEE80211_RX_RA_MATCH))
|
||||
return RX_CONTINUE;
|
||||
|
||||
/* start without a key */
|
||||
rx->key = NULL;
|
||||
|
||||
if (rx->sta)
|
||||
stakey = rcu_dereference(rx->sta->key);
|
||||
|
||||
|
|
@ -1589,7 +1824,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
|
|||
}
|
||||
|
||||
static ieee80211_rx_result debug_noinline
|
||||
ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
|
||||
ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
|
||||
{
|
||||
struct ieee80211_local *local = rx->local;
|
||||
struct ieee80211_hw *hw = &local->hw;
|
||||
|
|
@ -1619,7 +1854,8 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
|
|||
TU_TO_EXP_TIME(tid_agg_rx->timeout));
|
||||
|
||||
/* release stored frames up to start of BAR */
|
||||
ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num);
|
||||
ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num,
|
||||
frames);
|
||||
kfree_skb(skb);
|
||||
return RX_QUEUED;
|
||||
}
|
||||
|
|
@ -1868,7 +2104,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
|
|||
struct net_device *prev_dev = NULL;
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||
|
||||
if (rx->flags & IEEE80211_RX_CMNTR_REPORTED)
|
||||
if (status->flag & RX_FLAG_INTERNAL_CMTR)
|
||||
goto out_free_skb;
|
||||
|
||||
if (skb_headroom(skb) < sizeof(*rthdr) &&
|
||||
|
|
@ -1929,7 +2165,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
|
|||
} else
|
||||
goto out_free_skb;
|
||||
|
||||
rx->flags |= IEEE80211_RX_CMNTR_REPORTED;
|
||||
status->flag |= RX_FLAG_INTERNAL_CMTR;
|
||||
return;
|
||||
|
||||
out_free_skb:
|
||||
|
|
@ -1942,8 +2178,11 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
|
|||
struct sk_buff *skb,
|
||||
struct ieee80211_rate *rate)
|
||||
{
|
||||
struct sk_buff_head reorder_release;
|
||||
ieee80211_rx_result res = RX_DROP_MONITOR;
|
||||
|
||||
__skb_queue_head_init(&reorder_release);
|
||||
|
||||
rx->skb = skb;
|
||||
rx->sdata = sdata;
|
||||
|
||||
|
|
@ -1951,50 +2190,72 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
|
|||
do { \
|
||||
res = rxh(rx); \
|
||||
if (res != RX_CONTINUE) \
|
||||
goto rxh_done; \
|
||||
goto rxh_next; \
|
||||
} while (0);
|
||||
|
||||
/*
|
||||
* NB: the rxh_next label works even if we jump
|
||||
* to it from here because then the list will
|
||||
* be empty, which is a trivial check
|
||||
*/
|
||||
CALL_RXH(ieee80211_rx_h_passive_scan)
|
||||
CALL_RXH(ieee80211_rx_h_check)
|
||||
CALL_RXH(ieee80211_rx_h_decrypt)
|
||||
CALL_RXH(ieee80211_rx_h_check_more_data)
|
||||
CALL_RXH(ieee80211_rx_h_sta_process)
|
||||
CALL_RXH(ieee80211_rx_h_defragment)
|
||||
CALL_RXH(ieee80211_rx_h_ps_poll)
|
||||
CALL_RXH(ieee80211_rx_h_michael_mic_verify)
|
||||
/* must be after MMIC verify so header is counted in MPDU mic */
|
||||
CALL_RXH(ieee80211_rx_h_remove_qos_control)
|
||||
CALL_RXH(ieee80211_rx_h_amsdu)
|
||||
|
||||
ieee80211_rx_reorder_ampdu(rx, &reorder_release);
|
||||
|
||||
while ((skb = __skb_dequeue(&reorder_release))) {
|
||||
/*
|
||||
* all the other fields are valid across frames
|
||||
* that belong to an aMPDU since they are on the
|
||||
* same TID from the same station
|
||||
*/
|
||||
rx->skb = skb;
|
||||
|
||||
CALL_RXH(ieee80211_rx_h_decrypt)
|
||||
CALL_RXH(ieee80211_rx_h_check_more_data)
|
||||
CALL_RXH(ieee80211_rx_h_sta_process)
|
||||
CALL_RXH(ieee80211_rx_h_defragment)
|
||||
CALL_RXH(ieee80211_rx_h_ps_poll)
|
||||
CALL_RXH(ieee80211_rx_h_michael_mic_verify)
|
||||
/* must be after MMIC verify so header is counted in MPDU mic */
|
||||
CALL_RXH(ieee80211_rx_h_remove_qos_control)
|
||||
CALL_RXH(ieee80211_rx_h_amsdu)
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif))
|
||||
CALL_RXH(ieee80211_rx_h_mesh_fwding);
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif))
|
||||
CALL_RXH(ieee80211_rx_h_mesh_fwding);
|
||||
#endif
|
||||
CALL_RXH(ieee80211_rx_h_data)
|
||||
CALL_RXH(ieee80211_rx_h_ctrl)
|
||||
CALL_RXH(ieee80211_rx_h_action)
|
||||
CALL_RXH(ieee80211_rx_h_mgmt)
|
||||
CALL_RXH(ieee80211_rx_h_data)
|
||||
|
||||
/* special treatment -- needs the queue */
|
||||
res = ieee80211_rx_h_ctrl(rx, &reorder_release);
|
||||
if (res != RX_CONTINUE)
|
||||
goto rxh_next;
|
||||
|
||||
CALL_RXH(ieee80211_rx_h_action)
|
||||
CALL_RXH(ieee80211_rx_h_mgmt)
|
||||
|
||||
#undef CALL_RXH
|
||||
|
||||
rxh_done:
|
||||
switch (res) {
|
||||
case RX_DROP_MONITOR:
|
||||
I802_DEBUG_INC(sdata->local->rx_handlers_drop);
|
||||
if (rx->sta)
|
||||
rx->sta->rx_dropped++;
|
||||
/* fall through */
|
||||
case RX_CONTINUE:
|
||||
ieee80211_rx_cooked_monitor(rx, rate);
|
||||
break;
|
||||
case RX_DROP_UNUSABLE:
|
||||
I802_DEBUG_INC(sdata->local->rx_handlers_drop);
|
||||
if (rx->sta)
|
||||
rx->sta->rx_dropped++;
|
||||
dev_kfree_skb(rx->skb);
|
||||
break;
|
||||
case RX_QUEUED:
|
||||
I802_DEBUG_INC(sdata->local->rx_handlers_queued);
|
||||
break;
|
||||
rxh_next:
|
||||
switch (res) {
|
||||
case RX_DROP_MONITOR:
|
||||
I802_DEBUG_INC(sdata->local->rx_handlers_drop);
|
||||
if (rx->sta)
|
||||
rx->sta->rx_dropped++;
|
||||
/* fall through */
|
||||
case RX_CONTINUE:
|
||||
ieee80211_rx_cooked_monitor(rx, rate);
|
||||
break;
|
||||
case RX_DROP_UNUSABLE:
|
||||
I802_DEBUG_INC(sdata->local->rx_handlers_drop);
|
||||
if (rx->sta)
|
||||
rx->sta->rx_dropped++;
|
||||
dev_kfree_skb(rx->skb);
|
||||
break;
|
||||
case RX_QUEUED:
|
||||
I802_DEBUG_INC(sdata->local->rx_handlers_queued);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2187,233 +2448,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
|
|||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
#define SEQ_MODULO 0x1000
|
||||
#define SEQ_MASK 0xfff
|
||||
|
||||
static inline int seq_less(u16 sq1, u16 sq2)
|
||||
{
|
||||
return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1);
|
||||
}
|
||||
|
||||
static inline u16 seq_inc(u16 sq)
|
||||
{
|
||||
return (sq + 1) & SEQ_MASK;
|
||||
}
|
||||
|
||||
static inline u16 seq_sub(u16 sq1, u16 sq2)
|
||||
{
|
||||
return (sq1 - sq2) & SEQ_MASK;
|
||||
}
|
||||
|
||||
|
||||
static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw,
|
||||
struct tid_ampdu_rx *tid_agg_rx,
|
||||
int index)
|
||||
{
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_rate *rate = NULL;
|
||||
struct sk_buff *skb = tid_agg_rx->reorder_buf[index];
|
||||
struct ieee80211_rx_status *status;
|
||||
|
||||
if (!skb)
|
||||
goto no_frame;
|
||||
|
||||
status = IEEE80211_SKB_RXCB(skb);
|
||||
|
||||
/* release the reordered frames to stack */
|
||||
sband = hw->wiphy->bands[status->band];
|
||||
if (!(status->flag & RX_FLAG_HT))
|
||||
rate = &sband->bitrates[status->rate_idx];
|
||||
__ieee80211_rx_handle_packet(hw, skb, rate);
|
||||
tid_agg_rx->stored_mpdu_num--;
|
||||
tid_agg_rx->reorder_buf[index] = NULL;
|
||||
|
||||
no_frame:
|
||||
tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
|
||||
}
|
||||
|
||||
static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
|
||||
struct tid_ampdu_rx *tid_agg_rx,
|
||||
u16 head_seq_num)
|
||||
{
|
||||
int index;
|
||||
|
||||
while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) {
|
||||
index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
|
||||
tid_agg_rx->buf_size;
|
||||
ieee80211_release_reorder_frame(hw, tid_agg_rx, index);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Timeout (in jiffies) for skb's that are waiting in the RX reorder buffer. If
|
||||
* the skb was added to the buffer longer than this time ago, the earlier
|
||||
* frames that have not yet been received are assumed to be lost and the skb
|
||||
* can be released for processing. This may also release other skb's from the
|
||||
* reorder buffer if there are no additional gaps between the frames.
|
||||
*/
|
||||
#define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10)
|
||||
|
||||
/*
|
||||
* As this function belongs to the RX path it must be under
|
||||
* rcu_read_lock protection. It returns false if the frame
|
||||
* can be processed immediately, true if it was consumed.
|
||||
*/
|
||||
static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
|
||||
struct tid_ampdu_rx *tid_agg_rx,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
u16 sc = le16_to_cpu(hdr->seq_ctrl);
|
||||
u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
|
||||
u16 head_seq_num, buf_size;
|
||||
int index;
|
||||
|
||||
buf_size = tid_agg_rx->buf_size;
|
||||
head_seq_num = tid_agg_rx->head_seq_num;
|
||||
|
||||
/* frame with out of date sequence number */
|
||||
if (seq_less(mpdu_seq_num, head_seq_num)) {
|
||||
dev_kfree_skb(skb);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* If frame the sequence number exceeds our buffering window
|
||||
* size release some previous frames to make room for this one.
|
||||
*/
|
||||
if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) {
|
||||
head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size));
|
||||
/* release stored frames up to new head to stack */
|
||||
ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num);
|
||||
}
|
||||
|
||||
/* Now the new frame is always in the range of the reordering buffer */
|
||||
|
||||
index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size;
|
||||
|
||||
/* check if we already stored this frame */
|
||||
if (tid_agg_rx->reorder_buf[index]) {
|
||||
dev_kfree_skb(skb);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the current MPDU is in the right order and nothing else
|
||||
* is stored we can process it directly, no need to buffer it.
|
||||
*/
|
||||
if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
|
||||
tid_agg_rx->stored_mpdu_num == 0) {
|
||||
tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* put the frame in the reordering buffer */
|
||||
tid_agg_rx->reorder_buf[index] = skb;
|
||||
tid_agg_rx->reorder_time[index] = jiffies;
|
||||
tid_agg_rx->stored_mpdu_num++;
|
||||
/* release the buffer until next missing frame */
|
||||
index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
|
||||
tid_agg_rx->buf_size;
|
||||
if (!tid_agg_rx->reorder_buf[index] &&
|
||||
tid_agg_rx->stored_mpdu_num > 1) {
|
||||
/*
|
||||
* No buffers ready to be released, but check whether any
|
||||
* frames in the reorder buffer have timed out.
|
||||
*/
|
||||
int j;
|
||||
int skipped = 1;
|
||||
for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
|
||||
j = (j + 1) % tid_agg_rx->buf_size) {
|
||||
if (!tid_agg_rx->reorder_buf[j]) {
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
if (!time_after(jiffies, tid_agg_rx->reorder_time[j] +
|
||||
HT_RX_REORDER_BUF_TIMEOUT))
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
if (net_ratelimit())
|
||||
printk(KERN_DEBUG "%s: release an RX reorder "
|
||||
"frame due to timeout on earlier "
|
||||
"frames\n",
|
||||
wiphy_name(hw->wiphy));
|
||||
#endif
|
||||
ieee80211_release_reorder_frame(hw, tid_agg_rx, j);
|
||||
|
||||
/*
|
||||
* Increment the head seq# also for the skipped slots.
|
||||
*/
|
||||
tid_agg_rx->head_seq_num =
|
||||
(tid_agg_rx->head_seq_num + skipped) & SEQ_MASK;
|
||||
skipped = 0;
|
||||
}
|
||||
} else while (tid_agg_rx->reorder_buf[index]) {
|
||||
ieee80211_release_reorder_frame(hw, tid_agg_rx, index);
|
||||
index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
|
||||
tid_agg_rx->buf_size;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reorder MPDUs from A-MPDUs, keeping them on a buffer. Returns
|
||||
* true if the MPDU was buffered, false if it should be processed.
|
||||
*/
|
||||
static bool ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hw *hw = &local->hw;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
struct sta_info *sta;
|
||||
struct tid_ampdu_rx *tid_agg_rx;
|
||||
u16 sc;
|
||||
int tid;
|
||||
|
||||
if (!ieee80211_is_data_qos(hdr->frame_control))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* filter the QoS data rx stream according to
|
||||
* STA/TID and check if this STA/TID is on aggregation
|
||||
*/
|
||||
|
||||
sta = sta_info_get(local, hdr->addr2);
|
||||
if (!sta)
|
||||
return false;
|
||||
|
||||
tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
|
||||
|
||||
if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL)
|
||||
return false;
|
||||
|
||||
tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
|
||||
|
||||
/* qos null data frames are excluded */
|
||||
if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
|
||||
return false;
|
||||
|
||||
/* new, potentially un-ordered, ampdu frame - process it */
|
||||
|
||||
/* reset session timer */
|
||||
if (tid_agg_rx->timeout)
|
||||
mod_timer(&tid_agg_rx->session_timer,
|
||||
TU_TO_EXP_TIME(tid_agg_rx->timeout));
|
||||
|
||||
/* if this mpdu is fragmented - terminate rx aggregation session */
|
||||
sc = le16_to_cpu(hdr->seq_ctrl);
|
||||
if (sc & IEEE80211_SCTL_FRAG) {
|
||||
ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
|
||||
tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP);
|
||||
dev_kfree_skb(skb);
|
||||
return true;
|
||||
}
|
||||
|
||||
return ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the receive path handler. It is called by a low level driver when an
|
||||
* 802.11 MPDU is received from the hardware.
|
||||
|
|
@ -2495,20 +2529,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* In theory, the block ack reordering should happen after duplicate
|
||||
* removal (ieee80211_rx_h_check(), which is an RX handler). As such,
|
||||
* the call to ieee80211_rx_reorder_ampdu() should really be moved to
|
||||
* happen as a new RX handler between ieee80211_rx_h_check and
|
||||
* ieee80211_rx_h_decrypt. This cleanup may eventually happen, but for
|
||||
* the time being, the call can be here since RX reorder buf processing
|
||||
* will implicitly skip duplicates. We could, in theory at least,
|
||||
* process frames that ieee80211_rx_h_passive_scan would drop (e.g.,
|
||||
* frames from other than operational channel), but that should not
|
||||
* happen in normal networks.
|
||||
*/
|
||||
if (!ieee80211_rx_reorder_ampdu(local, skb))
|
||||
__ieee80211_rx_handle_packet(hw, skb, rate);
|
||||
__ieee80211_rx_handle_packet(hw, skb, rate);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
|
|
|
|||
|
|
@ -148,6 +148,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
struct net_device *prev_dev = NULL;
|
||||
struct sta_info *sta;
|
||||
int retry_count = -1, i;
|
||||
bool injected;
|
||||
|
||||
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
||||
/* the HW cannot have attempted that rate */
|
||||
|
|
@ -297,6 +298,9 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
/* for now report the total retry_count */
|
||||
rthdr->data_retries = retry_count;
|
||||
|
||||
/* Need to make a copy before skb->cb gets cleared */
|
||||
injected = !!(info->flags & IEEE80211_TX_CTL_INJECTED);
|
||||
|
||||
/* XXX: is this sufficient for BPF? */
|
||||
skb_set_mac_header(skb, 0);
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
|
|
@ -311,7 +315,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
continue;
|
||||
|
||||
if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) &&
|
||||
!(info->flags & IEEE80211_TX_CTL_INJECTED) &&
|
||||
!injected &&
|
||||
(type == IEEE80211_FTYPE_DATA))
|
||||
continue;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue