Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a144f378 authored by Johannes Berg's avatar Johannes Berg
Browse files

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
Loading
Loading
Loading
Loading
+52 −17
Original line number Diff line number Diff line
@@ -87,11 +87,13 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local,
	int len;

	/* 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)
		len += 4;
	if (status->chains)
		len += 4 * hweight8(status->chains);

	if (ieee80211_have_rx_timestamp(status)) {
		len = ALIGN(len, 8);
@@ -100,6 +102,10 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local,
	if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
		len += 1;

	/* antenna field, if we don't have per-chain info */
	if (!status->chains)
		len += 1;

	/* padding for RX_FLAGS if necessary */
	len = ALIGN(len, 2);

@@ -116,6 +122,11 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local,
		len += 12;
	}

	if (status->chains) {
		/* antenna and antenna signal fields */
		len += 2 * hweight8(status->chains);
	}

	if (status->vendor_radiotap_len) {
		if (WARN_ON_ONCE(status->vendor_radiotap_align == 0))
			status->vendor_radiotap_align = 1;
@@ -145,8 +156,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
	struct ieee80211_radiotap_header *rthdr;
	unsigned char *pos;
	__le32 *it_present;
	u32 it_present_val;
	u16 rx_flags = 0;
	int mpdulen;
	int mpdulen, chain;
	unsigned long chains = status->chains;

	mpdulen = skb->len;
	if (!(has_fcs && (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)))
@@ -154,25 +168,39 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,

	rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len);
	memset(rthdr, 0, rtap_len);
	it_present = &rthdr->it_present;

	/* 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);
	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) {
		rthdr->it_present |=
			cpu_to_le32(BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE)) |
			cpu_to_le32(BIT(IEEE80211_RADIOTAP_EXT));
		put_unaligned_le32(status->vendor_radiotap_bitmap, pos);
		pos += 4;
		it_present_val |= BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE) |
				  BIT(IEEE80211_RADIOTAP_EXT);
		put_unaligned_le32(it_present_val, it_present);
		it_present++;
		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 */

	/* IEEE80211_RADIOTAP_TSFT */
@@ -242,9 +270,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,

	/* IEEE80211_RADIOTAP_LOCK_QUALITY is missing */

	if (!status->chains) {
		/* IEEE80211_RADIOTAP_ANTENNA */
		*pos = status->antenna;
		pos++;
	}

	/* IEEE80211_RADIOTAP_DB_ANTNOISE is not used */

@@ -341,6 +371,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
		pos += 2;
	}

	for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) {
		*pos++ = status->chain_signal[chain];
		*pos++ = chain;
	}

	if (status->vendor_radiotap_len) {
		/* ensure 2 byte alignment for the vendor field as required */
		if ((pos - (u8 *)rthdr) & 1)