2009-11-18 20:42:47 +03:00
/*
* Copyright 2002 - 2005 , Instant802 Networks , Inc .
* Copyright 2005 - 2006 , Devicescape Software , Inc .
* Copyright 2006 - 2007 Jiri Benc < jbenc @ suse . cz >
2010-02-15 13:53:10 +03:00
* Copyright 2008 - 2010 Johannes Berg < johannes @ sipsolutions . net >
2009-11-18 20:42:47 +03:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
2011-07-15 19:47:34 +04:00
# include <linux/export.h>
2012-03-01 18:22:09 +04:00
# include <linux/etherdevice.h>
2009-11-18 20:42:47 +03:00
# include <net/mac80211.h>
2012-02-20 14:38:41 +04:00
# include <asm/unaligned.h>
2009-11-18 20:42:47 +03:00
# include "ieee80211_i.h"
# include "rate.h"
# include "mesh.h"
# include "led.h"
2011-09-29 18:04:29 +04:00
# include "wme.h"
2009-11-18 20:42:47 +03:00
void ieee80211_tx_status_irqsafe ( struct ieee80211_hw * hw ,
struct sk_buff * skb )
{
struct ieee80211_local * local = hw_to_local ( hw ) ;
struct ieee80211_tx_info * info = IEEE80211_SKB_CB ( skb ) ;
int tmp ;
skb - > pkt_type = IEEE80211_TX_STATUS_MSG ;
skb_queue_tail ( info - > flags & IEEE80211_TX_CTL_REQ_TX_STATUS ?
& local - > skb_queue : & local - > skb_queue_unreliable , skb ) ;
tmp = skb_queue_len ( & local - > skb_queue ) +
skb_queue_len ( & local - > skb_queue_unreliable ) ;
while ( tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT & &
( skb = skb_dequeue ( & local - > skb_queue_unreliable ) ) ) {
2012-10-08 16:39:33 +04:00
ieee80211_free_txskb ( hw , skb ) ;
2009-11-18 20:42:47 +03:00
tmp - - ;
I802_DEBUG_INC ( local - > tx_status_drop ) ;
}
tasklet_schedule ( & local - > tasklet ) ;
}
EXPORT_SYMBOL ( ieee80211_tx_status_irqsafe ) ;
static void ieee80211_handle_filtered_frame ( struct ieee80211_local * local ,
struct sta_info * sta ,
struct sk_buff * skb )
{
struct ieee80211_tx_info * info = IEEE80211_SKB_CB ( skb ) ;
2011-09-29 18:04:29 +04:00
struct ieee80211_hdr * hdr = ( void * ) skb - > data ;
int ac ;
2009-11-18 20:42:47 +03:00
2010-01-17 03:47:56 +03:00
/*
* This skb ' survived ' a round - trip through the driver , and
* hopefully the driver didn ' t mangle it too badly . However ,
2010-05-18 15:44:54 +04:00
* we can definitely not rely on the control information
2010-01-17 03:47:59 +03:00
* being correct . Clear it so we don ' t get junk there , and
* indicate that it needs new processing , but must not be
* modified / encrypted again .
2010-01-17 03:47:56 +03:00
*/
memset ( & info - > control , 0 , sizeof ( info - > control ) ) ;
2010-01-25 21:07:39 +03:00
info - > control . jiffies = jiffies ;
info - > control . vif = & sta - > sdata - > vif ;
2010-01-17 03:47:59 +03:00
info - > flags | = IEEE80211_TX_INTFL_NEED_TXPROCESSING |
IEEE80211_TX_INTFL_RETRANSMISSION ;
2010-09-21 23:36:18 +04:00
info - > flags & = ~ IEEE80211_TX_TEMPORARY_FLAGS ;
2010-01-17 03:47:56 +03:00
2009-11-18 20:42:47 +03:00
sta - > tx_filtered_count + + ;
2011-09-29 18:04:31 +04:00
/*
* Clear more - data bit on filtered frames , it might be set
* but later frames might time out so it might have to be
* clear again . . . It ' s all rather unlikely ( this frame
* should time out first , right ? ) but let ' s not confuse
* peers unnecessarily .
*/
if ( hdr - > frame_control & cpu_to_le16 ( IEEE80211_FCTL_MOREDATA ) )
hdr - > frame_control & = ~ cpu_to_le16 ( IEEE80211_FCTL_MOREDATA ) ;
2011-09-29 18:04:29 +04:00
if ( ieee80211_is_data_qos ( hdr - > frame_control ) ) {
2011-09-29 18:04:33 +04:00
u8 * p = ieee80211_get_qos_ctl ( hdr ) ;
int tid = * p & IEEE80211_QOS_CTL_TID_MASK ;
/*
* Clear EOSP if set , this could happen e . g .
* if an absence period ( us being a P2P GO )
* shortens the SP .
*/
if ( * p & IEEE80211_QOS_CTL_EOSP )
* p & = ~ IEEE80211_QOS_CTL_EOSP ;
2011-09-29 18:04:29 +04:00
ac = ieee802_1d_to_ac [ tid & 7 ] ;
} else {
ac = IEEE80211_AC_BE ;
}
2009-11-18 20:42:47 +03:00
/*
* Clear the TX filter mask for this STA when sending the next
* packet . If the STA went to power save mode , this will happen
* when it wakes up for the next time .
*/
2011-09-29 18:04:36 +04:00
set_sta_flag ( sta , WLAN_STA_CLEAR_PS_FILT ) ;
2009-11-18 20:42:47 +03:00
/*
* This code races in the following way :
*
* ( 1 ) STA sends frame indicating it will go to sleep and does so
* ( 2 ) hardware / firmware adds STA to filter list , passes frame up
* ( 3 ) hardware / firmware processes TX fifo and suppresses a frame
* ( 4 ) we get TX status before having processed the frame and
* knowing that the STA has gone to sleep .
*
* This is actually quite unlikely even when both those events are
* processed from interrupts coming in quickly after one another or
* even at the same time because we queue both TX status events and
* RX frames to be processed by a tasklet and process them in the
* same order that they were received or TX status last . Hence , there
* is no race as long as the frame RX is processed before the next TX
* status , which drivers can ensure , see below .
*
* Note that this can only happen if the hardware or firmware can
* actually add STAs to the filter list , if this is done by the
* driver in response to set_tim ( ) ( which will only reduce the race
* this whole filtering tries to solve , not completely solve it )
* this situation cannot happen .
*
* To completely solve this race drivers need to make sure that they
* ( a ) don ' t mix the irq - safe / not irq - safe TX status / RX processing
* functions and
* ( b ) always process RX events before TX status events if ordering
* can be unknown , for example with different interrupt status
* bits .
2011-01-31 23:29:13 +03:00
* ( c ) if PS mode transitions are manual ( i . e . the flag
* % IEEE80211_HW_AP_LINK_PS is set ) , always process PS state
* changes before calling TX status events if ordering can be
* unknown .
2009-11-18 20:42:47 +03:00
*/
2011-09-29 18:04:36 +04:00
if ( test_sta_flag ( sta , WLAN_STA_PS_STA ) & &
2011-09-29 18:04:29 +04:00
skb_queue_len ( & sta - > tx_filtered [ ac ] ) < STA_MAX_TX_BUFFER ) {
skb_queue_tail ( & sta - > tx_filtered [ ac ] , skb ) ;
2011-09-29 18:04:27 +04:00
sta_info_recalc_tim ( sta ) ;
2011-09-29 18:04:28 +04:00
if ( ! timer_pending ( & local - > sta_cleanup ) )
mod_timer ( & local - > sta_cleanup ,
round_jiffies ( jiffies +
STA_INFO_CLEANUP_INTERVAL ) ) ;
2009-11-18 20:42:47 +03:00
return ;
}
2011-09-29 18:04:36 +04:00
if ( ! test_sta_flag ( sta , WLAN_STA_PS_STA ) & &
2009-11-18 20:42:47 +03:00
! ( info - > flags & IEEE80211_TX_INTFL_RETRIED ) ) {
/* Software retry the packet once */
info - > flags | = IEEE80211_TX_INTFL_RETRIED ;
ieee80211_add_pending_skb ( local , skb ) ;
return ;
}
2012-06-22 13:29:50 +04:00
ps_dbg_ratelimited ( sta - > sdata ,
" dropped TX filtered frame, queue_len=%d PS=%d @%lu \n " ,
skb_queue_len ( & sta - > tx_filtered [ ac ] ) ,
! ! test_sta_flag ( sta , WLAN_STA_PS_STA ) , jiffies ) ;
2012-10-08 16:39:33 +04:00
ieee80211_free_txskb ( & local - > hw , skb ) ;
2009-11-18 20:42:47 +03:00
}
2011-08-28 23:11:01 +04:00
static void ieee80211_check_pending_bar ( struct sta_info * sta , u8 * addr , u8 tid )
{
struct tid_ampdu_tx * tid_tx ;
tid_tx = rcu_dereference ( sta - > ampdu_mlme . tid_tx [ tid ] ) ;
if ( ! tid_tx | | ! tid_tx - > bar_pending )
return ;
tid_tx - > bar_pending = false ;
2011-08-20 17:53:55 +04:00
ieee80211_send_bar ( & sta - > sdata - > vif , addr , tid , tid_tx - > failed_bar_ssn ) ;
2011-08-28 23:11:01 +04:00
}
2009-12-01 15:37:02 +03:00
static void ieee80211_frame_acked ( struct sta_info * sta , struct sk_buff * skb )
{
struct ieee80211_mgmt * mgmt = ( void * ) skb - > data ;
struct ieee80211_local * local = sta - > local ;
struct ieee80211_sub_if_data * sdata = sta - > sdata ;
2011-08-28 23:11:01 +04:00
if ( ieee80211_is_data_qos ( mgmt - > frame_control ) ) {
struct ieee80211_hdr * hdr = ( void * ) skb - > data ;
u8 * qc = ieee80211_get_qos_ctl ( hdr ) ;
u16 tid = qc [ 0 ] & 0xf ;
ieee80211_check_pending_bar ( sta , hdr - > addr1 , tid ) ;
}
2009-12-01 15:37:02 +03:00
if ( ieee80211_is_action ( mgmt - > frame_control ) & &
mgmt - > u . action . category = = WLAN_CATEGORY_HT & &
2012-09-11 16:34:12 +04:00
mgmt - > u . action . u . ht_smps . action = = WLAN_HT_ACTION_SMPS & &
sdata - > vif . type = = NL80211_IFTYPE_STATION & &
ieee80211_sdata_running ( sdata ) ) {
2009-12-01 15:37:02 +03:00
/*
* This update looks racy , but isn ' t - - if we come
* here we ' ve definitely got a station that we ' re
* talking to , and on a managed interface that can
* only be the AP . And the only other place updating
2012-09-11 16:34:12 +04:00
* this variable in managed mode is before association .
2009-12-01 15:37:02 +03:00
*/
switch ( mgmt - > u . action . u . ht_smps . smps_control ) {
case WLAN_HT_SMPS_CONTROL_DYNAMIC :
2012-09-11 16:34:12 +04:00
sdata - > smps_mode = IEEE80211_SMPS_DYNAMIC ;
2009-12-01 15:37:02 +03:00
break ;
case WLAN_HT_SMPS_CONTROL_STATIC :
2012-09-11 16:34:12 +04:00
sdata - > smps_mode = IEEE80211_SMPS_STATIC ;
2009-12-01 15:37:02 +03:00
break ;
case WLAN_HT_SMPS_CONTROL_DISABLED :
default : /* shouldn't happen since we don't send that */
2012-09-11 16:34:12 +04:00
sdata - > smps_mode = IEEE80211_SMPS_OFF ;
2009-12-01 15:37:02 +03:00
break ;
}
2012-09-11 16:34:12 +04:00
ieee80211_queue_work ( & local - > hw , & sdata - > recalc_smps ) ;
2009-12-01 15:37:02 +03:00
}
}
2011-08-28 23:11:01 +04:00
static void ieee80211_set_bar_pending ( struct sta_info * sta , u8 tid , u16 ssn )
{
struct tid_ampdu_tx * tid_tx ;
tid_tx = rcu_dereference ( sta - > ampdu_mlme . tid_tx [ tid ] ) ;
if ( ! tid_tx )
return ;
tid_tx - > failed_bar_ssn = ssn ;
tid_tx - > bar_pending = true ;
}
2011-10-11 20:08:54 +04:00
static int ieee80211_tx_radiotap_len ( struct ieee80211_tx_info * info )
{
int len = sizeof ( struct ieee80211_radiotap_header ) ;
/* IEEE80211_RADIOTAP_RATE rate */
if ( info - > status . rates [ 0 ] . idx > = 0 & &
! ( info - > status . rates [ 0 ] . flags & IEEE80211_TX_RC_MCS ) )
len + = 2 ;
/* IEEE80211_RADIOTAP_TX_FLAGS */
len + = 2 ;
/* IEEE80211_RADIOTAP_DATA_RETRIES */
len + = 1 ;
2011-10-11 20:08:55 +04:00
/* IEEE80211_TX_RC_MCS */
if ( info - > status . rates [ 0 ] . idx > = 0 & &
info - > status . rates [ 0 ] . flags & IEEE80211_TX_RC_MCS )
len + = 3 ;
2011-10-11 20:08:54 +04:00
return len ;
}
static void ieee80211_add_tx_radiotap_header ( struct ieee80211_supported_band
* sband , struct sk_buff * skb ,
int retry_count , int rtap_len )
{
struct ieee80211_tx_info * info = IEEE80211_SKB_CB ( skb ) ;
struct ieee80211_hdr * hdr = ( struct ieee80211_hdr * ) skb - > data ;
struct ieee80211_radiotap_header * rthdr ;
unsigned char * pos ;
2011-11-18 20:02:16 +04:00
u16 txflags ;
2011-10-11 20:08:54 +04:00
rthdr = ( struct ieee80211_radiotap_header * ) skb_push ( skb , rtap_len ) ;
memset ( rthdr , 0 , rtap_len ) ;
rthdr - > it_len = cpu_to_le16 ( rtap_len ) ;
rthdr - > it_present =
cpu_to_le32 ( ( 1 < < IEEE80211_RADIOTAP_TX_FLAGS ) |
( 1 < < IEEE80211_RADIOTAP_DATA_RETRIES ) ) ;
pos = ( unsigned char * ) ( rthdr + 1 ) ;
/*
* XXX : Once radiotap gets the bitmap reset thing the vendor
* extensions proposal contains , we can actually report
* the whole set of tries we did .
*/
/* IEEE80211_RADIOTAP_RATE */
if ( info - > status . rates [ 0 ] . idx > = 0 & &
! ( info - > status . rates [ 0 ] . flags & IEEE80211_TX_RC_MCS ) ) {
rthdr - > it_present | = cpu_to_le32 ( 1 < < IEEE80211_RADIOTAP_RATE ) ;
* pos = sband - > bitrates [ info - > status . rates [ 0 ] . idx ] . bitrate / 5 ;
/* padding for tx flags */
pos + = 2 ;
}
/* IEEE80211_RADIOTAP_TX_FLAGS */
txflags = 0 ;
if ( ! ( info - > flags & IEEE80211_TX_STAT_ACK ) & &
! is_multicast_ether_addr ( hdr - > addr1 ) )
2011-11-18 20:02:16 +04:00
txflags | = IEEE80211_RADIOTAP_F_TX_FAIL ;
2011-10-11 20:08:54 +04:00
if ( ( info - > status . rates [ 0 ] . flags & IEEE80211_TX_RC_USE_RTS_CTS ) | |
( info - > status . rates [ 0 ] . flags & IEEE80211_TX_RC_USE_CTS_PROTECT ) )
2011-11-18 20:02:16 +04:00
txflags | = IEEE80211_RADIOTAP_F_TX_CTS ;
2011-10-11 20:08:54 +04:00
else if ( info - > status . rates [ 0 ] . flags & IEEE80211_TX_RC_USE_RTS_CTS )
2011-11-18 20:02:16 +04:00
txflags | = IEEE80211_RADIOTAP_F_TX_RTS ;
2011-10-11 20:08:54 +04:00
put_unaligned_le16 ( txflags , pos ) ;
pos + = 2 ;
/* IEEE80211_RADIOTAP_DATA_RETRIES */
/* for now report the total retry_count */
* pos = retry_count ;
pos + + ;
2011-10-11 20:08:55 +04:00
/* IEEE80211_TX_RC_MCS */
if ( info - > status . rates [ 0 ] . idx > = 0 & &
info - > status . rates [ 0 ] . flags & IEEE80211_TX_RC_MCS ) {
rthdr - > it_present | = cpu_to_le32 ( 1 < < IEEE80211_RADIOTAP_MCS ) ;
pos [ 0 ] = IEEE80211_RADIOTAP_MCS_HAVE_MCS |
IEEE80211_RADIOTAP_MCS_HAVE_GI |
IEEE80211_RADIOTAP_MCS_HAVE_BW ;
if ( info - > status . rates [ 0 ] . flags & IEEE80211_TX_RC_SHORT_GI )
pos [ 1 ] | = IEEE80211_RADIOTAP_MCS_SGI ;
if ( info - > status . rates [ 0 ] . flags & IEEE80211_TX_RC_40_MHZ_WIDTH )
pos [ 1 ] | = IEEE80211_RADIOTAP_MCS_BW_40 ;
if ( info - > status . rates [ 0 ] . flags & IEEE80211_TX_RC_GREEN_FIELD )
pos [ 1 ] | = IEEE80211_RADIOTAP_MCS_FMT_GF ;
pos [ 2 ] = info - > status . rates [ 0 ] . idx ;
pos + = 3 ;
}
2011-10-11 20:08:54 +04:00
}
2012-10-26 17:53:06 +04:00
static void ieee80211_report_used_skb ( struct ieee80211_local * local ,
struct sk_buff * skb , bool dropped )
{
struct ieee80211_tx_info * info = IEEE80211_SKB_CB ( skb ) ;
struct ieee80211_hdr * hdr = ( void * ) skb - > data ;
bool acked = info - > flags & IEEE80211_TX_STAT_ACK ;
if ( dropped )
acked = false ;
if ( info - > flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX ) {
struct ieee80211_sub_if_data * sdata = NULL ;
struct ieee80211_sub_if_data * iter_sdata ;
u64 cookie = ( unsigned long ) skb ;
rcu_read_lock ( ) ;
if ( skb - > dev ) {
list_for_each_entry_rcu ( iter_sdata , & local - > interfaces ,
list ) {
if ( ! iter_sdata - > dev )
continue ;
if ( skb - > dev = = iter_sdata - > dev ) {
sdata = iter_sdata ;
break ;
}
}
} else {
sdata = rcu_dereference ( local - > p2p_sdata ) ;
}
if ( ! sdata )
skb - > dev = NULL ;
else if ( ieee80211_is_nullfunc ( hdr - > frame_control ) | |
ieee80211_is_qos_nullfunc ( hdr - > frame_control ) ) {
cfg80211_probe_status ( sdata - > dev , hdr - > addr1 ,
cookie , acked , GFP_ATOMIC ) ;
} else {
cfg80211_mgmt_tx_status ( & sdata - > wdev , cookie , skb - > data ,
skb - > len , acked , GFP_ATOMIC ) ;
}
rcu_read_unlock ( ) ;
}
if ( unlikely ( info - > ack_frame_id ) ) {
struct sk_buff * ack_skb ;
unsigned long flags ;
spin_lock_irqsave ( & local - > ack_status_lock , flags ) ;
ack_skb = idr_find ( & local - > ack_status_frames ,
info - > ack_frame_id ) ;
if ( ack_skb )
idr_remove ( & local - > ack_status_frames ,
info - > ack_frame_id ) ;
spin_unlock_irqrestore ( & local - > ack_status_lock , flags ) ;
if ( ack_skb ) {
if ( ! dropped ) {
/* consumes ack_skb */
skb_complete_wifi_ack ( ack_skb , acked ) ;
} else {
dev_kfree_skb_any ( ack_skb ) ;
}
}
}
}
2010-11-24 10:10:06 +03:00
/*
* Use a static threshold for now , best value to be determined
* by testing . . .
* Should it depend on :
* - on # of retransmissions
* - current throughput ( higher value for higher tpt ) ?
*/
# define STA_LOST_PKT_THRESHOLD 50
2009-11-18 20:42:47 +03:00
void ieee80211_tx_status ( struct ieee80211_hw * hw , struct sk_buff * skb )
{
struct sk_buff * skb2 ;
struct ieee80211_hdr * hdr = ( struct ieee80211_hdr * ) skb - > data ;
struct ieee80211_local * local = hw_to_local ( hw ) ;
struct ieee80211_tx_info * info = IEEE80211_SKB_CB ( skb ) ;
__le16 fc ;
struct ieee80211_supported_band * sband ;
struct ieee80211_sub_if_data * sdata ;
struct net_device * prev_dev = NULL ;
2009-11-25 19:46:18 +03:00
struct sta_info * sta , * tmp ;
2009-11-18 20:42:47 +03:00
int retry_count = - 1 , i ;
2010-04-22 11:27:48 +04:00
int rates_idx = - 1 ;
2010-03-11 18:28:24 +03:00
bool send_to_cooked ;
2010-12-02 23:01:08 +03:00
bool acked ;
2011-08-11 18:17:42 +04:00
struct ieee80211_bar * bar ;
2011-10-11 20:08:54 +04:00
int rtap_len ;
2009-11-18 20:42:47 +03:00
for ( i = 0 ; i < IEEE80211_TX_MAX_RATES ; i + + ) {
2012-04-06 22:48:15 +04:00
if ( ( info - > flags & IEEE80211_TX_CTL_AMPDU ) & &
! ( info - > flags & IEEE80211_TX_STAT_AMPDU ) ) {
/* just the first aggr frame carry status info */
info - > status . rates [ i ] . idx = - 1 ;
info - > status . rates [ i ] . count = 0 ;
break ;
} else if ( info - > status . rates [ i ] . idx < 0 ) {
2011-03-21 17:07:55 +03:00
break ;
} else if ( i > = hw - > max_report_rates ) {
/* the HW cannot have attempted that rate */
2009-11-18 20:42:47 +03:00
info - > status . rates [ i ] . idx = - 1 ;
info - > status . rates [ i ] . count = 0 ;
2011-03-21 17:07:55 +03:00
break ;
2009-11-18 20:42:47 +03:00
}
retry_count + = info - > status . rates [ i ] . count ;
}
2011-03-21 17:07:55 +03:00
rates_idx = i - 1 ;
2009-11-18 20:42:47 +03:00
if ( retry_count < 0 )
retry_count = 0 ;
rcu_read_lock ( ) ;
sband = local - > hw . wiphy - > bands [ info - > band ] ;
2010-02-09 12:20:28 +03:00
fc = hdr - > frame_control ;
2009-11-18 20:42:47 +03:00
2009-11-25 19:46:18 +03:00
for_each_sta_info ( local , hdr - > addr1 , sta , tmp ) {
/* skip wrong virtual interface */
mac80211: Convert compare_ether_addr to ether_addr_equal
Use the new bool function ether_addr_equal to add
some clarity and reduce the likelihood for misuse
of compare_ether_addr for sorting.
Done via cocci script:
$ cat compare_ether_addr.cocci
@@
expression a,b;
@@
- !compare_ether_addr(a, b)
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- compare_ether_addr(a, b)
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- !ether_addr_equal(a, b) == 0
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- !ether_addr_equal(a, b) != 0
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- ether_addr_equal(a, b) == 0
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- ether_addr_equal(a, b) != 0
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- !!ether_addr_equal(a, b)
+ ether_addr_equal(a, b)
Signed-off-by: Joe Perches <joe@perches.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2012-05-08 22:56:52 +04:00
if ( ! ether_addr_equal ( hdr - > addr2 , sta - > sdata - > vif . addr ) )
2009-11-25 19:46:18 +03:00
continue ;
2009-11-18 20:42:47 +03:00
2011-09-29 18:04:33 +04:00
if ( info - > flags & IEEE80211_TX_STATUS_EOSP )
2011-09-29 18:04:36 +04:00
clear_sta_flag ( sta , WLAN_STA_SP ) ;
2011-09-29 18:04:33 +04:00
2010-12-02 23:01:08 +03:00
acked = ! ! ( info - > flags & IEEE80211_TX_STAT_ACK ) ;
2011-09-29 18:04:36 +04:00
if ( ! acked & & test_sta_flag ( sta , WLAN_STA_PS_STA ) ) {
2009-11-18 20:42:47 +03:00
/*
* The STA is in power save mode , so assume
* that this TX packet failed because of that .
*/
ieee80211_handle_filtered_frame ( local , sta , skb ) ;
rcu_read_unlock ( ) ;
return ;
}
2010-04-22 11:27:48 +04:00
if ( ( local - > hw . flags & IEEE80211_HW_HAS_RATE_CONTROL ) & &
( rates_idx ! = - 1 ) )
sta - > last_tx_rate = info - > status . rates [ rates_idx ] ;
2009-11-18 20:42:47 +03:00
if ( ( info - > flags & IEEE80211_TX_STAT_AMPDU_NO_BACK ) & &
( ieee80211_is_data_qos ( fc ) ) ) {
u16 tid , ssn ;
u8 * qc ;
qc = ieee80211_get_qos_ctl ( hdr ) ;
tid = qc [ 0 ] & 0xf ;
ssn = ( ( le16_to_cpu ( hdr - > seq_ctrl ) + 0x10 )
& IEEE80211_SCTL_SEQ ) ;
2011-08-20 17:53:55 +04:00
ieee80211_send_bar ( & sta - > sdata - > vif , hdr - > addr1 ,
2009-11-18 20:42:47 +03:00
tid , ssn ) ;
}
2011-08-11 18:17:42 +04:00
if ( ! acked & & ieee80211_is_back_req ( fc ) ) {
2012-01-20 16:52:36 +04:00
u16 tid , control ;
2011-09-15 11:37:46 +04:00
2011-08-11 18:17:42 +04:00
/*
2011-09-15 11:37:46 +04:00
* BAR failed , store the last SSN and retry sending
* the BAR when the next unicast transmission on the
* same TID succeeds .
2011-08-11 18:17:42 +04:00
*/
bar = ( struct ieee80211_bar * ) skb - > data ;
2011-09-15 11:37:46 +04:00
control = le16_to_cpu ( bar - > control ) ;
if ( ! ( control & IEEE80211_BAR_CTRL_MULTI_TID ) ) {
2011-08-28 23:11:01 +04:00
u16 ssn = le16_to_cpu ( bar - > start_seq_num ) ;
2011-09-15 11:37:46 +04:00
tid = ( control &
2011-08-11 18:17:42 +04:00
IEEE80211_BAR_CTRL_TID_INFO_MASK ) > >
IEEE80211_BAR_CTRL_TID_INFO_SHIFT ;
2011-08-28 23:11:01 +04:00
ieee80211_set_bar_pending ( sta , tid , ssn ) ;
2011-08-11 18:17:42 +04:00
}
}
2009-11-18 20:42:47 +03:00
if ( info - > flags & IEEE80211_TX_STAT_TX_FILTERED ) {
ieee80211_handle_filtered_frame ( local , sta , skb ) ;
rcu_read_unlock ( ) ;
return ;
} else {
2010-12-02 23:01:08 +03:00
if ( ! acked )
2009-11-18 20:42:47 +03:00
sta - > tx_retry_failed + + ;
sta - > tx_retry_count + = retry_count ;
}
rate_control_tx_status ( local , sband , sta , skb ) ;
if ( ieee80211_vif_is_mesh ( & sta - > sdata - > vif ) )
ieee80211s_update_metric ( local , sta , skb ) ;
2009-12-01 15:37:02 +03:00
2010-12-02 23:01:08 +03:00
if ( ! ( info - > flags & IEEE80211_TX_CTL_INJECTED ) & & acked )
2009-12-01 15:37:02 +03:00
ieee80211_frame_acked ( sta , skb ) ;
2010-11-24 10:10:06 +03:00
2010-12-02 23:01:08 +03:00
if ( ( sta - > sdata - > vif . type = = NL80211_IFTYPE_STATION ) & &
( local - > hw . flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS ) )
ieee80211_sta_tx_notify ( sta - > sdata , ( void * ) skb - > data , acked ) ;
2010-11-24 10:10:06 +03:00
if ( local - > hw . flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS ) {
if ( info - > flags & IEEE80211_TX_STAT_ACK ) {
if ( sta - > lost_packets )
sta - > lost_packets = 0 ;
} else if ( + + sta - > lost_packets > = STA_LOST_PKT_THRESHOLD ) {
cfg80211_cqm_pktloss_notify ( sta - > sdata - > dev ,
sta - > sta . addr ,
sta - > lost_packets ,
GFP_ATOMIC ) ;
sta - > lost_packets = 0 ;
}
}
2009-11-18 20:42:47 +03:00
}
rcu_read_unlock ( ) ;
ieee80211_led_tx ( local , 0 ) ;
/* SNMP counters
* Fragments are passed to low - level drivers as separate skbs , so these
* are actually fragments , not frames . Update frame counters only for
* the first fragment of the frame . */
if ( info - > flags & IEEE80211_TX_STAT_ACK ) {
2011-12-08 16:11:55 +04:00
if ( ieee80211_is_first_frag ( hdr - > seq_ctrl ) ) {
2009-11-18 20:42:47 +03:00
local - > dot11TransmittedFrameCount + + ;
if ( is_multicast_ether_addr ( hdr - > addr1 ) )
local - > dot11MulticastTransmittedFrameCount + + ;
if ( retry_count > 0 )
local - > dot11RetryCount + + ;
if ( retry_count > 1 )
local - > dot11MultipleRetryCount + + ;
}
/* This counter shall be incremented for an acknowledged MPDU
* with an individual address in the address 1 field or an MPDU
* with a multicast address in the address 1 field of type Data
* or Management . */
if ( ! is_multicast_ether_addr ( hdr - > addr1 ) | |
2011-12-08 16:11:55 +04:00
ieee80211_is_data ( fc ) | |
ieee80211_is_mgmt ( fc ) )
2009-11-18 20:42:47 +03:00
local - > dot11TransmittedFragmentCount + + ;
} else {
2011-12-08 16:11:55 +04:00
if ( ieee80211_is_first_frag ( hdr - > seq_ctrl ) )
2009-11-18 20:42:47 +03:00
local - > dot11FailedCount + + ;
}
2010-02-09 12:20:28 +03:00
if ( ieee80211_is_nullfunc ( fc ) & & ieee80211_has_pm ( fc ) & &
( local - > hw . flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS ) & &
! ( info - > flags & IEEE80211_TX_CTL_INJECTED ) & &
local - > ps_sdata & & ! ( local - > scanning ) ) {
if ( info - > flags & IEEE80211_TX_STAT_ACK ) {
local - > ps_sdata - > u . mgd . flags | =
IEEE80211_STA_NULLFUNC_ACKED ;
} else
mod_timer ( & local - > dynamic_ps_timer , jiffies +
msecs_to_jiffies ( 10 ) ) ;
}
2012-10-26 17:53:06 +04:00
ieee80211_report_used_skb ( local , skb , false ) ;
2011-11-06 17:13:34 +04:00
2009-11-18 20:42:47 +03:00
/* this was a transmitted frame, but now we want to reuse it */
skb_orphan ( skb ) ;
2010-03-11 18:28:24 +03:00
/* Need to make a copy before skb->cb gets cleared */
send_to_cooked = ! ! ( info - > flags & IEEE80211_TX_CTL_INJECTED ) | |
2011-12-08 16:11:55 +04:00
! ( ieee80211_is_data ( fc ) ) ;
2010-03-11 18:28:24 +03:00
2009-11-18 20:42:47 +03:00
/*
* This is a bit racy but we can avoid a lot of work
* with this test . . .
*/
2010-03-11 18:28:24 +03:00
if ( ! local - > monitors & & ( ! send_to_cooked | | ! local - > cooked_mntrs ) ) {
2009-11-18 20:42:47 +03:00
dev_kfree_skb ( skb ) ;
return ;
}
/* send frame to monitor interfaces now */
2011-10-11 20:08:54 +04:00
rtap_len = ieee80211_tx_radiotap_len ( info ) ;
if ( WARN_ON_ONCE ( skb_headroom ( skb ) < rtap_len ) ) {
2012-05-16 01:20:30 +04:00
pr_err ( " ieee80211_tx_status: headroom too small \n " ) ;
2009-11-18 20:42:47 +03:00
dev_kfree_skb ( skb ) ;
return ;
}
2011-10-11 20:08:54 +04:00
ieee80211_add_tx_radiotap_header ( sband , skb , retry_count , rtap_len ) ;
2009-11-18 20:42:47 +03:00
/* XXX: is this sufficient for BPF? */
skb_set_mac_header ( skb , 0 ) ;
skb - > ip_summed = CHECKSUM_UNNECESSARY ;
skb - > pkt_type = PACKET_OTHERHOST ;
skb - > protocol = htons ( ETH_P_802_2 ) ;
memset ( skb - > cb , 0 , sizeof ( skb - > cb ) ) ;
rcu_read_lock ( ) ;
list_for_each_entry_rcu ( sdata , & local - > interfaces , list ) {
if ( sdata - > vif . type = = NL80211_IFTYPE_MONITOR ) {
2009-12-23 15:15:31 +03:00
if ( ! ieee80211_sdata_running ( sdata ) )
2009-11-18 20:42:47 +03:00
continue ;
if ( ( sdata - > u . mntr_flags & MONITOR_FLAG_COOK_FRAMES ) & &
2010-03-11 18:28:24 +03:00
! send_to_cooked )
2009-11-18 20:42:47 +03:00
continue ;
if ( prev_dev ) {
skb2 = skb_clone ( skb , GFP_ATOMIC ) ;
if ( skb2 ) {
skb2 - > dev = prev_dev ;
2010-10-07 19:35:40 +04:00
netif_rx ( skb2 ) ;
2009-11-18 20:42:47 +03:00
}
}
prev_dev = sdata - > dev ;
}
}
if ( prev_dev ) {
skb - > dev = prev_dev ;
2010-10-07 19:35:40 +04:00
netif_rx ( skb ) ;
2009-11-18 20:42:47 +03:00
skb = NULL ;
}
rcu_read_unlock ( ) ;
dev_kfree_skb ( skb ) ;
}
EXPORT_SYMBOL ( ieee80211_tx_status ) ;
2011-04-18 15:22:28 +04:00
void ieee80211_report_low_ack ( struct ieee80211_sta * pubsta , u32 num_packets )
{
struct sta_info * sta = container_of ( pubsta , struct sta_info , sta ) ;
cfg80211_cqm_pktloss_notify ( sta - > sdata - > dev , sta - > sta . addr ,
num_packets , GFP_ATOMIC ) ;
}
EXPORT_SYMBOL ( ieee80211_report_low_ack ) ;
2011-11-04 14:18:10 +04:00
void ieee80211_free_txskb ( struct ieee80211_hw * hw , struct sk_buff * skb )
{
2011-11-06 17:13:34 +04:00
struct ieee80211_local * local = hw_to_local ( hw ) ;
2012-10-26 17:53:06 +04:00
ieee80211_report_used_skb ( local , skb , true ) ;
2011-11-04 14:18:10 +04:00
dev_kfree_skb_any ( skb ) ;
}
EXPORT_SYMBOL ( ieee80211_free_txskb ) ;