Skip to content

Commit

Permalink
mac80211: Build TX radiotap header dynamically
Browse files Browse the repository at this point in the history
Get rid of the ieee80211_tx_status_rtap_hdr struct and instead build the
rtap header dynamically. This makes it easier to extend the rtap header
generation in the future.

Add ieee80211_tx_radiotap_len to calculate the expected size of the
rtap header before generating it. Since we can't check if the rtap
header fits into the requested headroom during compile time anymore
add a WARN_ON_ONCE.

Also move the actual rtap header generation into its own function.

Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Helmut Schaa authored and John W. Linville committed Oct 14, 2011
1 parent 7bd9897 commit a2fe816
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 52 deletions.
12 changes: 0 additions & 12 deletions net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -1177,18 +1177,6 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
struct net_device *dev);

/*
* radiotap header for status frames
*/
struct ieee80211_tx_status_rtap_hdr {
struct ieee80211_radiotap_header hdr;
u8 rate;
u8 padding_for_rate;
__le16 tx_flags;
u8 data_retries;
} __packed;


/* HT */
void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
struct ieee80211_ht_cap *ht_cap_ie,
Expand Down
6 changes: 1 addition & 5 deletions net/mac80211/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -904,12 +904,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
* and we need some headroom for passing the frame to monitor
* interfaces, but never both at the same time.
*/
#ifndef __CHECKER__
BUILD_BUG_ON(IEEE80211_TX_STATUS_HEADROOM !=
sizeof(struct ieee80211_tx_status_rtap_hdr));
#endif
local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom,
sizeof(struct ieee80211_tx_status_rtap_hdr));
IEEE80211_TX_STATUS_HEADROOM);

debugfs_hw_add(local);

Expand Down
112 changes: 77 additions & 35 deletions net/mac80211/status.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 ...
Expand All @@ -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;
Expand All @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit a2fe816

Please sign in to comment.