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

Commit b2c81339 authored by Ahmad Masri's avatar Ahmad Masri Committed by Gerrit - the friendly Code Review server
Browse files

wil6210: check integrity of received AMSDU packets



Check integrity of received AMSDU packet, 802.11ad QoS spec requires
that AMSDU frame contains only MSDUs whose destination address (DA)
and sender address (SA) parameter values map to the same receiver
address (RA) and transmitter address (TA) values.
wil6210 Talyn HW does not check this before it cuts the AMSDU frame
into multiple received MSDU packets.
Adding checks to wil6210 driver to enforce spec compliance behavior
by checking all AMSDU sub frames if it complies with the following:
1- On AP, check packet SA is its client mac address, and on Client
   check that the DA is the local mac address. If not drop the packet
2- if AMSDU sub frame was dropped on item 1, drop all next sub frame
   of the AMSDU by checking it has same sn/tid.

This patch drops all WDS frames before it checks valid AMSDU, WDS
includes supporting MAC header with 4 addresses which is not supported
yet, moreover, WDS implies different validity checks on AMSDU frame.

Change-Id: I71a39f95c034f05023e0e7ae3ffb5d2b4f8c6b24
Signed-off-by: default avatarAhmad Masri <amasri@codeaurora.org>
parent c993cbae
Loading
Loading
Loading
Loading
+9 −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-2021, The Linux Foundation. All rights reserved.
 */

#include <linux/moduleparam.h>
@@ -310,6 +310,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
	/* statistics */
	memset(&sta->stats, 0, sizeof(sta->stats));
	sta->stats.tx_latency_min_us = U32_MAX;
	wil_sta_info_amsdu_init(sta);
}

static void _wil6210_disconnect_complete(struct wil6210_vif *vif,
@@ -712,6 +713,13 @@ void wil_bcast_fini_all(struct wil6210_priv *wil)
	}
}

void wil_sta_info_amsdu_init(struct wil_sta_info *sta)
{
	sta->amsdu_drop_sn = -1;
	sta->amsdu_drop_tid = -1;
	sta->amsdu_drop = 0;
}

int wil_priv_init(struct wil6210_priv *wil)
{
	uint i;
+1 −2
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-2021, The Linux Foundation. All rights reserved.
 */

#include <linux/module.h>
@@ -98,7 +98,6 @@ int wil_set_capabilities(struct wil6210_priv *wil)
		set_bit(hw_capa_no_flash, wil->hw_capa);
		wil->use_enhanced_dma_hw = true;
		wil->use_rx_hw_reordering = true;
		wil->use_compressed_rx_status = true;
		if (wil_ipa_offload())
			/* IPA offload must use single MSI */
			n_msi = 1;
+93 −1
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-2021 The Linux Foundation. All rights reserved.
 */

#include <linux/etherdevice.h>
@@ -806,6 +806,92 @@ static int wil_tx_ring_modify_edma(struct wil6210_vif *vif, int ring_id,
	return -EOPNOTSUPP;
}

static int wil_check_amsdu(struct wil6210_priv *wil, void *msg, int cid,
			   struct wil_ring_rx_data *rxdata,
			   struct sk_buff *skb)
{
	u8 *sa, *da;
	int mid, tid;
	u16 seq;
	struct wil6210_vif *vif;
	struct net_device *ndev;
	struct wil_sta_info *sta;

	/* drop all WDS packets - not supported */
	if (wil_rx_status_get_ds_type(wil, msg) == WIL_RX_EDMA_DS_TYPE_WDS) {
		wil_dbg_txrx(wil, "WDS is not supported");
		return -EAGAIN;
	}

	/* check amsdu packets */
	sta = &wil->sta[cid];
	if (!wil_rx_status_is_basic_amsdu(msg)) {
		if (sta->amsdu_drop_sn != -1)
			wil_sta_info_amsdu_init(sta);
		return 0;
	}

	mid = wil_rx_status_get_mid(msg);
	tid = wil_rx_status_get_tid(msg);
	seq = le16_to_cpu(wil_rx_status_get_seq(wil, msg));
	vif = wil->vifs[mid];

	if (unlikely(!vif)) {
		wil_dbg_txrx(wil, "amsdu with invalid mid %d", mid);
		return -EAGAIN;
	}

	if (unlikely(sta->amsdu_drop)) {
		if (sta->amsdu_drop_sn == seq && sta->amsdu_drop_tid == tid) {
			wil_dbg_txrx(wil, "Drop AMSDU sub frame, sn=%d\n",
				     seq);
			return -EAGAIN;
		}

		/* previous AMSDU finished - clear drop amsdu flag */
		sta->amsdu_drop = 0;
	}

	da = wil_skb_get_da(skb);
	/* for all sub frame of the AMSDU, check that the SA or DA are valid
	 * compared with client/AP mac addresses
	 */
	switch (vif->wdev.iftype) {
	case NL80211_IFTYPE_STATION:
	case NL80211_IFTYPE_P2P_CLIENT:
		if (is_multicast_ether_addr(da))
			return 0;

		/* On client side, DA should be the client mac address */
		ndev = vif_to_ndev(vif);
		if (ether_addr_equal(ndev->dev_addr, da))
			return 0;
		break;

	case NL80211_IFTYPE_P2P_GO:
	case NL80211_IFTYPE_AP:
		sa = wil_skb_get_sa(skb);
		/* On AP side, the packet SA should be the client mac address.
		 * check also the DA is not rfc 1042 header
		 */
		if (ether_addr_equal(sta->addr, sa) &&
		    !ether_addr_equal(rfc1042_header, da))
			return 0;
		break;
	default:
		return 0;
	}

	sta->amsdu_drop_sn = seq;
	sta->amsdu_drop_tid = tid;
	sta->amsdu_drop = 1;
	wil_dbg_txrx(wil,
		     "Drop AMSDU frame, sn=%d. Drop this and all next sub frames\n",
		     seq);

	return -EAGAIN;
}

/* This function is used only for RX SW reorder */
static int wil_check_bar(struct wil6210_priv *wil, void *msg, int cid,
			 struct sk_buff *skb, struct wil_net_stats *stats)
@@ -1107,6 +1193,12 @@ 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);

	if (!wil->use_compressed_rx_status &&
	    wil_check_amsdu(wil, msg, cid, rxdata, skb)) {
		kfree_skb(skb);
		goto again;
	}

	/* Has to be done after dma_unmap_single as skb->cb is also
	 * used for holding the pa
	 */
+19 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: ISC */
/*
 * Copyright (c) 2012-2016,2018-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2012-2016,2018-2021, The Linux Foundation. All rights reserved.
 */

#ifndef WIL6210_TXRX_EDMA_H
@@ -47,6 +47,9 @@

#define WIL_RX_EDMA_MID_VALID_BIT		BIT(22)

#define WIL_RX_EDMA_AMSDU_BASIC_MASK		0x1
#define WIL_RX_EDMA_DS_TYPE_WDS			0x3

#define WIL_EDMA_DESC_TX_MAC_CFG_0_QID_POS 16
#define WIL_EDMA_DESC_TX_MAC_CFG_0_QID_LEN 6

@@ -457,6 +460,21 @@ static inline int wil_rx_status_get_fc1(struct wil6210_priv *wil, void *msg)
			    0, 5) << 2;
}

static inline int wil_rx_status_get_ds_type(struct wil6210_priv *wil, void *msg)
{
	if (wil->use_compressed_rx_status)
		return 0;

	return WIL_GET_BITS(((struct wil_rx_status_extended *)msg)->ext.d0,
			    19, 20);
}

static inline int wil_rx_status_is_basic_amsdu(void *msg)
{
	return (WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d1,
			     28, 29) == WIL_RX_EDMA_AMSDU_BASIC_MASK);
}

static inline __le16 wil_rx_status_get_seq(struct wil6210_priv *wil, void *msg)
{
	if (wil->use_compressed_rx_status)
+7 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: ISC */
/*
 * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
 * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
 * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
 */

#ifndef __WIL6210_H__
@@ -783,6 +783,11 @@ struct wil_sta_info {
	struct wil_tid_crypto_rx group_crypto_rx;
	u8 aid; /* 1-254; 0 if unknown/not reported */
	u8 fst_link_loss;

	/* amsdu frame related info to check if the frame is valid */
	int amsdu_drop_sn;
	int amsdu_drop_tid;
	u8 amsdu_drop;
};

enum {
@@ -1563,4 +1568,5 @@ void update_supported_bands(struct wil6210_priv *wil);
int wmi_reset_spi_slave(struct wil6210_priv *wil);

void wil_clear_fw_log_addr(struct wil6210_priv *wil);
void wil_sta_info_amsdu_init(struct wil_sta_info *sta);
#endif /* __WIL6210_H__ */
Loading