Commit a144f378 authored by Johannes Berg's avatar Johannes Berg

mac80211: add per-chain signal information to radiotap

When per-chain signal information is available, don't add
the antenna field once but instead add a radiotap namespace
for each chain containing the chain/antenna number and the
signal strength on that chain.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
parent ad24b0da
...@@ -87,11 +87,13 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local, ...@@ -87,11 +87,13 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local,
int len; int len;
/* always present fields */ /* always present fields */
len = sizeof(struct ieee80211_radiotap_header) + 9; len = sizeof(struct ieee80211_radiotap_header) + 8;
/* allocate extra bitmap */ /* allocate extra bitmaps */
if (status->vendor_radiotap_len) if (status->vendor_radiotap_len)
len += 4; len += 4;
if (status->chains)
len += 4 * hweight8(status->chains);
if (ieee80211_have_rx_timestamp(status)) { if (ieee80211_have_rx_timestamp(status)) {
len = ALIGN(len, 8); len = ALIGN(len, 8);
...@@ -100,6 +102,10 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local, ...@@ -100,6 +102,10 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local,
if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
len += 1; len += 1;
/* antenna field, if we don't have per-chain info */
if (!status->chains)
len += 1;
/* padding for RX_FLAGS if necessary */ /* padding for RX_FLAGS if necessary */
len = ALIGN(len, 2); len = ALIGN(len, 2);
...@@ -116,6 +122,11 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local, ...@@ -116,6 +122,11 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local,
len += 12; len += 12;
} }
if (status->chains) {
/* antenna and antenna signal fields */
len += 2 * hweight8(status->chains);
}
if (status->vendor_radiotap_len) { if (status->vendor_radiotap_len) {
if (WARN_ON_ONCE(status->vendor_radiotap_align == 0)) if (WARN_ON_ONCE(status->vendor_radiotap_align == 0))
status->vendor_radiotap_align = 1; status->vendor_radiotap_align = 1;
...@@ -145,8 +156,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, ...@@ -145,8 +156,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_radiotap_header *rthdr; struct ieee80211_radiotap_header *rthdr;
unsigned char *pos; unsigned char *pos;
__le32 *it_present;
u32 it_present_val;
u16 rx_flags = 0; u16 rx_flags = 0;
int mpdulen; int mpdulen, chain;
unsigned long chains = status->chains;
mpdulen = skb->len; mpdulen = skb->len;
if (!(has_fcs && (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS))) if (!(has_fcs && (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)))
...@@ -154,25 +168,39 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, ...@@ -154,25 +168,39 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len); rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len);
memset(rthdr, 0, rtap_len); memset(rthdr, 0, rtap_len);
it_present = &rthdr->it_present;
/* radiotap header, set always present flags */ /* radiotap header, set always present flags */
rthdr->it_present =
cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
(1 << IEEE80211_RADIOTAP_CHANNEL) |
(1 << IEEE80211_RADIOTAP_ANTENNA) |
(1 << IEEE80211_RADIOTAP_RX_FLAGS));
rthdr->it_len = cpu_to_le16(rtap_len + status->vendor_radiotap_len); rthdr->it_len = cpu_to_le16(rtap_len + status->vendor_radiotap_len);
it_present_val = BIT(IEEE80211_RADIOTAP_FLAGS) |
BIT(IEEE80211_RADIOTAP_CHANNEL) |
BIT(IEEE80211_RADIOTAP_RX_FLAGS);
if (!status->chains)
it_present_val |= BIT(IEEE80211_RADIOTAP_ANTENNA);
pos = (unsigned char *)(rthdr + 1); for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) {
it_present_val |=
BIT(IEEE80211_RADIOTAP_EXT) |
BIT(IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE);
put_unaligned_le32(it_present_val, it_present);
it_present++;
it_present_val = BIT(IEEE80211_RADIOTAP_ANTENNA) |
BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
}
if (status->vendor_radiotap_len) { if (status->vendor_radiotap_len) {
rthdr->it_present |= it_present_val |= BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE) |
cpu_to_le32(BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE)) | BIT(IEEE80211_RADIOTAP_EXT);
cpu_to_le32(BIT(IEEE80211_RADIOTAP_EXT)); put_unaligned_le32(it_present_val, it_present);
put_unaligned_le32(status->vendor_radiotap_bitmap, pos); it_present++;
pos += 4; it_present_val = status->vendor_radiotap_bitmap;
} }
put_unaligned_le32(it_present_val, it_present);
pos = (void *)(it_present + 1);
/* the order of the following fields is important */ /* the order of the following fields is important */
/* IEEE80211_RADIOTAP_TSFT */ /* IEEE80211_RADIOTAP_TSFT */
...@@ -242,9 +270,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, ...@@ -242,9 +270,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
/* IEEE80211_RADIOTAP_LOCK_QUALITY is missing */ /* IEEE80211_RADIOTAP_LOCK_QUALITY is missing */
/* IEEE80211_RADIOTAP_ANTENNA */ if (!status->chains) {
*pos = status->antenna; /* IEEE80211_RADIOTAP_ANTENNA */
pos++; *pos = status->antenna;
pos++;
}
/* IEEE80211_RADIOTAP_DB_ANTNOISE is not used */ /* IEEE80211_RADIOTAP_DB_ANTNOISE is not used */
...@@ -341,6 +371,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, ...@@ -341,6 +371,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
pos += 2; pos += 2;
} }
for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) {
*pos++ = status->chain_signal[chain];
*pos++ = chain;
}
if (status->vendor_radiotap_len) { if (status->vendor_radiotap_len) {
/* ensure 2 byte alignment for the vendor field as required */ /* ensure 2 byte alignment for the vendor field as required */
if ((pos - (u8 *)rthdr) & 1) if ((pos - (u8 *)rthdr) & 1)
......
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