@ -228,6 +228,79 @@ static void ieee80211_set_bar_pending(struct sta_info *sta, u8 tid, u16 ssn)
tid_tx - > bar_pending = true ;
}
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 ;
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 ;
__le16 txflags ;
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 ) )
txflags | = cpu_to_le16 ( IEEE80211_RADIOTAP_F_TX_FAIL ) ;
if ( ( info - > status . rates [ 0 ] . flags & IEEE80211_TX_RC_USE_RTS_CTS ) | |
( info - > status . rates [ 0 ] . flags & IEEE80211_TX_RC_USE_CTS_PROTECT ) )
txflags | = cpu_to_le16 ( IEEE80211_RADIOTAP_F_TX_CTS ) ;
else if ( info - > status . rates [ 0 ] . flags & IEEE80211_TX_RC_USE_RTS_CTS )
txflags | = cpu_to_le16 ( IEEE80211_RADIOTAP_F_TX_RTS ) ;
put_unaligned_le16 ( txflags , pos ) ;
pos + = 2 ;
/* IEEE80211_RADIOTAP_DATA_RETRIES */
/* for now report the total retry_count */
* pos = retry_count ;
pos + + ;
}
/*
* Use a static threshold for now , best value to be determined
* by testing . . .
@ -246,7 +319,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
u16 frag , type ;
__le16 fc ;
struct ieee80211_supported_band * sband ;
struct ieee80211_tx_status_rtap_hdr * rthdr ;
struct ieee80211_sub_if_data * sdata ;
struct net_device * prev_dev = NULL ;
struct sta_info * sta , * tmp ;
@ -256,6 +328,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
bool acked ;
struct ieee80211_bar * bar ;
u16 tid ;
int rtap_len ;
for ( i = 0 ; i < IEEE80211_TX_MAX_RATES ; i + + ) {
if ( info - > status . rates [ i ] . idx < 0 ) {
@ -460,44 +533,13 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
}
/* send frame to monitor interfaces now */
if ( skb_headroom ( skb ) < sizeof ( * rthdr ) ) {
rtap_len = ieee80211_tx_radiotap_len ( info ) ;
if ( WARN_ON_ONCE ( skb_headroom ( skb ) < rtap_len ) ) {
printk ( KERN_ERR " ieee80211_tx_status: headroom too small \n " ) ;
dev_kfree_skb ( skb ) ;
return ;
}
rthdr = ( struct ieee80211_tx_status_rtap_hdr * )
skb_push ( skb , sizeof ( * rthdr ) ) ;
memset ( rthdr , 0 , sizeof ( * rthdr ) ) ;
rthdr - > hdr . it_len = cpu_to_le16 ( sizeof ( * rthdr ) ) ;
rthdr - > hdr . it_present =
cpu_to_le32 ( ( 1 < < IEEE80211_RADIOTAP_TX_FLAGS ) |
( 1 < < IEEE80211_RADIOTAP_DATA_RETRIES ) |
( 1 < < IEEE80211_RADIOTAP_RATE ) ) ;
if ( ! ( info - > flags & IEEE80211_TX_STAT_ACK ) & &
! is_multicast_ether_addr ( hdr - > addr1 ) )
rthdr - > tx_flags | = cpu_to_le16 ( IEEE80211_RADIOTAP_F_TX_FAIL ) ;
/*
* XXX : Once radiotap gets the bitmap reset thing the vendor
* extensions proposal contains , we can actually report
* the whole set of tries we did .
*/
if ( ( info - > status . rates [ 0 ] . flags & IEEE80211_TX_RC_USE_RTS_CTS ) | |
( info - > status . rates [ 0 ] . flags & IEEE80211_TX_RC_USE_CTS_PROTECT ) )
rthdr - > tx_flags | = cpu_to_le16 ( IEEE80211_RADIOTAP_F_TX_CTS ) ;
else if ( info - > status . rates [ 0 ] . flags & IEEE80211_TX_RC_USE_RTS_CTS )
rthdr - > tx_flags | = cpu_to_le16 ( IEEE80211_RADIOTAP_F_TX_RTS ) ;
if ( info - > status . rates [ 0 ] . idx > = 0 & &
! ( info - > status . rates [ 0 ] . flags & IEEE80211_TX_RC_MCS ) )
rthdr - > rate = sband - > bitrates [
info - > status . rates [ 0 ] . idx ] . bitrate / 5 ;
/* for now report the total retry_count */
rthdr - > data_retries = retry_count ;
ieee80211_add_tx_radiotap_header ( sband , skb , retry_count , rtap_len ) ;
/* XXX: is this sufficient for BPF? */
skb_set_mac_header ( skb , 0 ) ;