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

Commit d38deb2d authored by Alexei Avshalom Lazar's avatar Alexei Avshalom Lazar
Browse files

wil6210: support sniffer in EDMA mode



Sniffer in EDMA mode is required for supporting sniffer for
CB2 traffic.
Sniffer mode is supported only with extended RX status messages,
hence use_compressed_rx_status is cleared in sniffer mode.
The sniffer info is configured in a new section added to
WMI_CFG_DEF_RX_OFFLOAD command.
The radiotap header is added to the RX data and its size is taken into
account when allocating the RX SKBs.

Change-Id: I36fa4502eab2880ae39cf0a0697eb5793cb45335
Signed-off-by: default avatarMaya Erez <merez@codeaurora.org>
Signed-off-by: default avatarAhmad Masri <amasri@codeaurora.org>
Signed-off-by: default avatarAlexei Avshalom Lazar <ailizaro@codeaurora.org>
parent a7ee6826
Loading
Loading
Loading
Loading
+18 −6
Original line number Diff line number Diff line
// SPDX-License-Identifier: ISC
/*
 * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
 * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
 */

#include <linux/etherdevice.h>
@@ -1034,7 +1034,7 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy,
	struct wil6210_vif *vif = ndev_to_vif(ndev);
	struct wireless_dev *wdev = vif_to_wdev(vif);
	int rc;
	bool fw_reset = false;
	bool compressed_rx_status, fw_reset = false;

	wil_dbg_misc(wil, "change_iface: type=%d\n", type);

@@ -1046,6 +1046,13 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy,
		}
	}

	/* monitor mode uses uncompressed rx status to get phy statistics */
	compressed_rx_status = wil->use_compressed_rx_status;
	if (type == NL80211_IFTYPE_MONITOR)
		wil->use_compressed_rx_status = false;
	else if (wdev->iftype == NL80211_IFTYPE_MONITOR)
		wil->use_compressed_rx_status =  true;

	/* do not reset FW when there are active VIFs,
	 * because it can cause significant disruption
	 */
@@ -1059,7 +1066,7 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy,
		mutex_unlock(&wil->mutex);

		if (rc)
			return rc;
			goto fail;
		fw_reset = true;
	}

@@ -1074,7 +1081,8 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy,
			wil->monitor_flags = params->flags;
		break;
	default:
		return -EOPNOTSUPP;
		rc = -EOPNOTSUPP;
		goto fail;
	}

	if (vif->mid != 0 && wil_has_active_ifaces(wil, true, false)) {
@@ -1082,14 +1090,18 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy,
			wil_vif_prepare_stop(vif);
		rc = wmi_port_delete(wil, vif->mid);
		if (rc)
			return rc;
			goto fail;
		rc = wmi_port_allocate(wil, vif->mid, ndev->dev_addr, type);
		if (rc)
			return rc;
			goto fail;
	}

	wdev->iftype = type;
	return 0;

fail:
	wil->use_compressed_rx_status = compressed_rx_status;
	return rc;
}

static int wil_cfg80211_scan(struct wiphy *wiphy,
+1 −15
Original line number Diff line number Diff line
// SPDX-License-Identifier: ISC
/*
 * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
 * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
 */

#include <linux/etherdevice.h>
#include <net/ieee80211_radiotap.h>
#include <linux/if_arp.h>
#include <linux/moduleparam.h>
#include <linux/ip.h>
@@ -331,19 +330,6 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct wil_ring *vring,
static void wil_rx_add_radiotap_header(struct wil6210_priv *wil,
				       struct sk_buff *skb)
{
	struct wil6210_rtap {
		struct ieee80211_radiotap_header rthdr;
		/* fields should be in the order of bits in rthdr.it_present */
		/* flags */
		u8 flags;
		/* channel */
		__le16 chnl_freq __aligned(2);
		__le16 chnl_flags;
		/* MCS */
		u8 mcs_present;
		u8 mcs_flags;
		u8 mcs_index;
	} __packed;
	struct vring_rx_desc *d = wil_skb_rxdesc(skb);
	struct wil6210_rtap *rtap;
	int rtap_len = sizeof(struct wil6210_rtap);
+16 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: ISC */
/*
 * Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
 * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
 */

#ifndef WIL6210_TXRX_H
#define WIL6210_TXRX_H

#include <net/ieee80211_radiotap.h>
#include "wil6210.h"
#include "txrx_edma.h"

@@ -491,6 +492,20 @@ struct packet_rx_info {
	u8 cid;
};

struct wil6210_rtap {
	struct ieee80211_radiotap_header rthdr;
	/* fields should be in the order of bits in rthdr.it_present */
	/* flags */
	u8 flags;
	/* channel */
	__le16 chnl_freq __aligned(2);
	__le16 chnl_flags;
	/* MCS */
	u8 mcs_present;
	u8 mcs_flags;
	u8 mcs_index;
} __packed;

/* this struct will be stored in the skb cb buffer
 * max length of the struct is limited to 48 bytes
 */
+76 −10
Original line number Diff line number Diff line
// SPDX-License-Identifier: ISC
/*
 * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved.
 * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved.
 */

#include <linux/etherdevice.h>
#include <linux/moduleparam.h>
#include <net/ieee80211_radiotap.h>
#include <linux/if_arp.h>
#include <linux/prefetch.h>
#include <linux/types.h>
#include <linux/list.h>
@@ -181,17 +183,20 @@ static int wil_ring_alloc_skb_edma(struct wil6210_priv *wil,
	struct wil_rx_enhanced_desc dd, *d = &dd;
	struct wil_rx_enhanced_desc *_d = (struct wil_rx_enhanced_desc *)
		&ring->va[i].rx.enhanced;
	struct net_device *ndev = wil->main_ndev;
	int headroom = ndev->type == ARPHRD_IEEE80211_RADIOTAP ?
			WIL6210_RTAP_SIZE : headroom_size;

	if (unlikely(list_empty(free))) {
		wil->rx_buff_mgmt.free_list_empty_cnt++;
		return -EAGAIN;
	}

	skb = dev_alloc_skb(sz + headroom_size);
	skb = dev_alloc_skb(sz + headroom);
	if (unlikely(!skb))
		return -ENOMEM;

	skb_reserve(skb, headroom_size);
	skb_reserve(skb, headroom);
	skb_put(skb, sz);

	/**
@@ -902,6 +907,48 @@ static int wil_rx_error_check_edma(struct wil6210_priv *wil,
	return 0;
}

/**
 * Adds radiotap header
 *
 * Any error indicated as "Bad FCS"
 */
static void wil_rx_add_radiotap_header_edma(struct wil6210_priv *wil,
					    struct wil_rx_status_extended *s,
					    struct sk_buff *skb)
{
	struct wil6210_rtap *rtap;
	int rtap_len = sizeof(struct wil6210_rtap);
	struct ieee80211_channel *ch = wil->monitor_chandef.chan;

	if (skb_headroom(skb) < rtap_len &&
	    pskb_expand_head(skb, rtap_len, 0, GFP_ATOMIC)) {
		wil_err(wil, "Unable to expand headroom to %d\n", rtap_len);
		return;
	}

#if defined(BACKPORT_HAS_SKB_PUT_PUSH_RETURN_VOID)
	rtap = skb_push(skb, rtap_len);
#else
	rtap = (void *)skb_push(skb, rtap_len);
#endif
	memset(rtap, 0, rtap_len);

	rtap->rthdr.it_version = PKTHDR_RADIOTAP_VERSION;
	rtap->rthdr.it_len = cpu_to_le16(rtap_len);
	rtap->rthdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
					(1 << IEEE80211_RADIOTAP_CHANNEL) |
					(1 << IEEE80211_RADIOTAP_MCS));
	if (wil_rx_status_get_error(s))
		rtap->flags |= IEEE80211_RADIOTAP_F_BADFCS;

	rtap->chnl_freq = cpu_to_le16(ch ? ch->center_freq : 58320);
	rtap->chnl_flags = cpu_to_le16(0);

	rtap->mcs_present = IEEE80211_RADIOTAP_MCS_HAVE_MCS;
	rtap->mcs_flags = 0;
	rtap->mcs_index = wil_rx_status_get_mcs(s);
}

static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil,
					      struct wil_status_ring *sring)
{
@@ -922,6 +969,8 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil,
	u8 data_offset;
	struct wil_rx_status_extended *s;
	u16 sring_idx = sring - wil->srings;
	struct net_device *ndev = wil->main_ndev;
	struct wireless_dev *wdev = ndev->ieee80211_ptr;

	BUILD_BUG_ON(sizeof(struct wil_rx_status_extended) > sizeof(skb->cb));

@@ -1011,13 +1060,6 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil,
	}
	stats = &wil->sta[cid].stats;

	if (unlikely(dmalen < ETH_HLEN)) {
		wil_dbg_txrx(wil, "Short frame, len = %d\n", dmalen);
		stats->rx_short_frame++;
		rxdata->skipping = true;
		goto skipping;
	}

	if (unlikely(dmalen > sz)) {
		wil_err(wil, "Rx size too large: %d bytes!\n", dmalen);
		print_hex_dump(KERN_ERR, "RxS ", DUMP_PREFIX_OFFSET, 16, 1,
@@ -1027,6 +1069,17 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil,

		stats->rx_large_frame++;
		rxdata->skipping = true;
		goto skipping;
	}

	/* no extra checks if in sniffer mode */
	if (wdev->iftype == NL80211_IFTYPE_MONITOR)
		goto skipping;

	if (unlikely(dmalen < ETH_HLEN)) {
		wil_dbg_txrx(wil, "Short frame, len = %d\n", dmalen);
		stats->rx_short_frame++;
		rxdata->skipping = true;
	}

skipping:
@@ -1106,6 +1159,10 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil,
	wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1,
			  skb->data, skb_headlen(skb), false);

	/* use radiotap header only if required */
	if (ndev->type == ARPHRD_IEEE80211_RADIOTAP)
		wil_rx_add_radiotap_header_edma(wil, msg, skb);

	/* Has to be done after dma_unmap_single as skb->cb is also
	 * used for holding the pa
	 */
@@ -1122,6 +1179,7 @@ void wil_rx_handle_edma(struct wil6210_priv *wil, int *quota)
	struct wil_status_ring *sring;
	struct sk_buff *skb;
	int i;
	struct wireless_dev *wdev;

	if (unlikely(!ring->va)) {
		wil_err(wil, "Rx IRQ while Rx not yet initialized\n");
@@ -1155,6 +1213,14 @@ void wil_rx_handle_edma(struct wil6210_priv *wil, int *quota)
					continue;
				}
				ndev = vif_to_ndev(vif);
				wdev = ndev->ieee80211_ptr;
				if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
					skb->dev = ndev;
					skb_reset_mac_header(skb);
					skb->ip_summed = CHECKSUM_UNNECESSARY;
					skb->pkt_type = PACKET_OTHERHOST;
					skb->protocol = htons(ETH_P_802_2);
				}
				wil_netif_rx_any(skb, ndev);
			} else {
				wil_rx_reorder(wil, skb);
+13 −1
Original line number Diff line number Diff line
// SPDX-License-Identifier: ISC
/*
 * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
 * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
 */

#include <linux/moduleparam.h>
@@ -4053,6 +4053,7 @@ int wil_wmi_cfg_def_rx_offload(struct wil6210_priv *wil,
			       u16 max_rx_pl_per_desc, bool checksum)
{
	struct net_device *ndev = wil->main_ndev;
	struct wireless_dev *wdev = ndev->ieee80211_ptr;
	struct wil6210_vif *vif = ndev_to_vif(ndev);
	int rc;
	struct wmi_cfg_def_rx_offload_cmd cmd = {
@@ -4070,6 +4071,17 @@ int wil_wmi_cfg_def_rx_offload(struct wil6210_priv *wil,
		.evt = {.status = WMI_FW_STATUS_FAILURE},
	};

	if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
		struct ieee80211_channel *ch = wil->monitor_chandef.chan;

		cmd.sniffer_cfg.phy_support =
			wil->monitor_flags & MONITOR_FLAG_CONTROL ?
			WMI_SNIFFER_EDMA_CP : WMI_SNIFFER_EDMA_BOTH;
		if (ch)
			cmd.sniffer_cfg.channel = ch->hw_value - 1;
		cmd.sniffer_cfg.edmg_channel = wil->force_edmg_channel;
	}

	rc = wmi_call(wil, WMI_CFG_DEF_RX_OFFLOAD_CMDID, vif->mid, &cmd,
		      sizeof(cmd), WMI_CFG_DEF_RX_OFFLOAD_DONE_EVENTID, &reply,
		      sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS);
Loading