Commit 601ae7f2 authored by Bruno Randolf's avatar Bruno Randolf Committed by John W. Linville

mac80211: make rx radiotap header more flexible

use hw flags and rx flags to determine which fields are present in the header
and use all available information from the driver.

make sure radiotap header starts at a naturally aligned address (mod 8) for
all radiotap fields.
Signed-off-by: default avatarBruno Randolf <br1@einfach.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 566bfe5a
......@@ -77,6 +77,134 @@ static inline int should_drop_frame(struct ieee80211_rx_status *status,
return 0;
}
static int
ieee80211_rx_radiotap_len(struct ieee80211_local *local,
struct ieee80211_rx_status *status)
{
int len;
/* always present fields */
len = sizeof(struct ieee80211_radiotap_header) + 9;
if (status->flag & RX_FLAG_TSFT)
len += 8;
if (local->hw.flags & IEEE80211_HW_SIGNAL_DB ||
local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
len += 1;
if (local->hw.flags & IEEE80211_HW_NOISE_DBM)
len += 1;
if (len & 1) /* padding for RX_FLAGS if necessary */
len++;
/* make sure radiotap starts at a naturally aligned address */
if (len % 8)
len = roundup(len, 8);
return len;
}
/**
* ieee80211_add_rx_radiotap_header - add radiotap header
*
* add a radiotap header containing all the fields which the hardware provided.
*/
static void
ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
struct sk_buff *skb,
struct ieee80211_rx_status *status,
struct ieee80211_rate *rate,
int rtap_len)
{
struct ieee80211_radiotap_header *rthdr;
unsigned char *pos;
rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len);
memset(rthdr, 0, rtap_len);
/* radiotap header, set always present flags */
rthdr->it_present =
cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
(1 << IEEE80211_RADIOTAP_RATE) |
(1 << IEEE80211_RADIOTAP_CHANNEL) |
(1 << IEEE80211_RADIOTAP_ANTENNA) |
(1 << IEEE80211_RADIOTAP_RX_FLAGS));
rthdr->it_len = cpu_to_le16(rtap_len);
pos = (unsigned char *)(rthdr+1);
/* the order of the following fields is important */
/* IEEE80211_RADIOTAP_TSFT */
if (status->flag & RX_FLAG_TSFT) {
*(__le64 *)pos = cpu_to_le64(status->mactime);
rthdr->it_present |=
cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT);
pos += 8;
}
/* IEEE80211_RADIOTAP_FLAGS */
if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
*pos |= IEEE80211_RADIOTAP_F_FCS;
pos++;
/* IEEE80211_RADIOTAP_RATE */
*pos = rate->bitrate / 5;
pos++;
/* IEEE80211_RADIOTAP_CHANNEL */
*(__le16 *)pos = cpu_to_le16(status->freq);
pos += 2;
if (status->band == IEEE80211_BAND_5GHZ)
*(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_OFDM |
IEEE80211_CHAN_5GHZ);
else
*(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_DYN |
IEEE80211_CHAN_2GHZ);
pos += 2;
/* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */
if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {
*pos = status->signal;
rthdr->it_present |=
cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
pos++;
}
/* IEEE80211_RADIOTAP_DBM_ANTNOISE */
if (local->hw.flags & IEEE80211_HW_NOISE_DBM) {
*pos = status->noise;
rthdr->it_present |=
cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTNOISE);
pos++;
}
/* IEEE80211_RADIOTAP_LOCK_QUALITY is missing */
/* IEEE80211_RADIOTAP_ANTENNA */
*pos = status->antenna;
pos++;
/* IEEE80211_RADIOTAP_DB_ANTSIGNAL */
if (local->hw.flags & IEEE80211_HW_SIGNAL_DB) {
*pos = status->signal;
rthdr->it_present |=
cpu_to_le32(1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL);
pos++;
}
/* IEEE80211_RADIOTAP_DB_ANTNOISE is not used */
/* IEEE80211_RADIOTAP_RX_FLAGS */
/* ensure 2 byte alignment for the 2 byte field as required */
if ((pos - (unsigned char *)rthdr) & 1)
pos++;
/* FIXME: when radiotap gets a 'bad PLCP' flag use it here */
if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
*(__le16 *)pos |= cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS);
pos += 2;
}
/*
* This function copies a received frame to all monitor interfaces and
* returns a cleaned-up SKB that no longer includes the FCS nor the
......@@ -89,17 +217,6 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
{
struct ieee80211_sub_if_data *sdata;
int needed_headroom = 0;
struct ieee80211_radiotap_header *rthdr;
__le64 *rttsft = NULL;
struct ieee80211_rtap_fixed_data {
u8 flags;
u8 rate;
__le16 chan_freq;
__le16 chan_flags;
u8 antsignal;
u8 padding_for_rxflags;
__le16 rx_flags;
} __attribute__ ((packed)) *rtfixed;
struct sk_buff *skb, *skb2;
struct net_device *prev_dev = NULL;
int present_fcs_len = 0;
......@@ -116,8 +233,8 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
if (status->flag & RX_FLAG_RADIOTAP)
rtap_len = ieee80211_get_radiotap_len(origskb->data);
else
/* room for radiotap header, always present fields and TSFT */
needed_headroom = sizeof(*rthdr) + sizeof(*rtfixed) + 8;
/* room for the radiotap header based on driver features */
needed_headroom = ieee80211_rx_radiotap_len(local, status);
if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
present_fcs_len = FCS_LEN;
......@@ -163,55 +280,9 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
}
/* if necessary, prepend radiotap information */
if (!(status->flag & RX_FLAG_RADIOTAP)) {
rtfixed = (void *) skb_push(skb, sizeof(*rtfixed));
rtap_len = sizeof(*rthdr) + sizeof(*rtfixed);
if (status->flag & RX_FLAG_TSFT) {
rttsft = (void *) skb_push(skb, sizeof(*rttsft));
rtap_len += 8;
}
rthdr = (void *) skb_push(skb, sizeof(*rthdr));
memset(rthdr, 0, sizeof(*rthdr));
memset(rtfixed, 0, sizeof(*rtfixed));
rthdr->it_present =
cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
(1 << IEEE80211_RADIOTAP_RATE) |
(1 << IEEE80211_RADIOTAP_CHANNEL) |
(1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |
(1 << IEEE80211_RADIOTAP_RX_FLAGS));
rtfixed->flags = 0;
if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
rtfixed->flags |= IEEE80211_RADIOTAP_F_FCS;
if (rttsft) {
*rttsft = cpu_to_le64(status->mactime);
rthdr->it_present |=
cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT);
}
/* FIXME: when radiotap gets a 'bad PLCP' flag use it here */
rtfixed->rx_flags = 0;
if (status->flag &
(RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
rtfixed->rx_flags |=
cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS);
rtfixed->rate = rate->bitrate / 5;
rtfixed->chan_freq = cpu_to_le16(status->freq);
if (status->band == IEEE80211_BAND_5GHZ)
rtfixed->chan_flags =
cpu_to_le16(IEEE80211_CHAN_OFDM |
IEEE80211_CHAN_5GHZ);
else
rtfixed->chan_flags =
cpu_to_le16(IEEE80211_CHAN_DYN |
IEEE80211_CHAN_2GHZ);
rtfixed->antsignal = status->signal;
rthdr->it_len = cpu_to_le16(rtap_len);
}
if (!(status->flag & RX_FLAG_RADIOTAP))
ieee80211_add_rx_radiotap_header(local, skb, status, rate,
needed_headroom);
skb_reset_mac_header(skb);
skb->ip_summed = CHECKSUM_UNNECESSARY;
......
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