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

Commit 66989652 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 c0c39404
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -1050,8 +1050,6 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy,
	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
+9 −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.
 */

#include <linux/moduleparam.h>
@@ -313,6 +313,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,
@@ -723,6 +724,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-2020 The Linux Foundation. All rights reserved.
 * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
 */

#include <linux/etherdevice.h>
@@ -811,6 +811,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)
@@ -1159,6 +1245,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;
	}

	/* use radiotap header only if required */
	if (ndev->type == ARPHRD_IEEE80211_RADIOTAP)
		wil_rx_add_radiotap_header_edma(wil, msg, skb);
+19 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: ISC */
/* Copyright (c) 2012-2016,2018-2019, The Linux Foundation.
/* Copyright (c) 2012-2016,2018-2021, The Linux Foundation.
 * All rights reserved.
 */

@@ -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)
Loading