From c55f25ffb33f8f610ff7c94d9cd616806464211f Mon Sep 17 00:00:00 2001 From: Ahmad Masri Date: Tue, 15 Dec 2020 14:10:04 +0200 Subject: [PATCH 1/3] wil6210: AP should not forward eapol packets In AP mode, the driver checks each received frame, in case it is multicast or unicast packet targeted to one of the AP clients, the driver does the routing in L2 level. EAPOL packet is plaintext frame and it should not follow the above role. When AP receives an EAPOL packet that is multicast or targeted to a client in the AP network, the driver should not forward this packet immediately in L2. EAPOL packet should be indicated to the network stack which will check the packet validity and will decide if to forward the packet to its client or not. Change-Id: I0edf339c3be5a2300e7b8168866286e71045c0d5 Signed-off-by: Ahmad Masri --- drivers/net/wireless/ath/wil6210/txrx.c | 6 ++++-- drivers/net/wireless/ath/wil6210/txrx.h | 9 ++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 48526c6509e9..72cd994a9f4d 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -1,7 +1,7 @@ // 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 @@ -942,7 +942,9 @@ void wil_netif_rx(struct sk_buff *skb, struct net_device *ndev, int cid, wil_dbg_txrx(wil, "Rx drop %d bytes\n", len); return; } - } else if (wdev->iftype == NL80211_IFTYPE_AP && !vif->ap_isolate) { + } else if (wdev->iftype == NL80211_IFTYPE_AP && !vif->ap_isolate && + /* pass EAPOL packets to local net stack only */ + (wil_skb_get_protocol(skb) != htons(ETH_P_PAE))) { if (mcast) { /* send multicast frames both to higher layers in * local net stack and back to the wireless medium diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index d9e116ba8dce..b01e2f21423a 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: ISC */ /* * Copyright (c) 2012-2016 Qualcomm Atheros, Inc. - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. */ #ifndef WIL6210_TXRX_H @@ -610,6 +610,13 @@ static inline u8 *wil_skb_get_sa(struct sk_buff *skb) return eth->h_source; } +static inline __be16 wil_skb_get_protocol(struct sk_buff *skb) +{ + struct ethhdr *eth = (void *)skb->data; + + return eth->h_proto; +} + static inline bool wil_need_txstat(struct sk_buff *skb) { const u8 *da = wil_skb_get_da(skb); From c993cbae6e07d3e589221347d856b0cd52cb14ad Mon Sep 17 00:00:00 2001 From: Ahmad Masri Date: Sun, 3 Jan 2021 10:27:49 +0200 Subject: [PATCH 2/3] wil6210: Drop plaintext frames on secure network On secure network, only eap frames are valid unencrypted frames and allowed to be indicated to the local network, any other unencrypted frame should be dropped immediately. Change-Id: Id9d97a4c0984f7bf2d7d6941c4c61e87bc2354cd Signed-off-by: Ahmad Masri --- drivers/net/wireless/ath/wil6210/txrx.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 72cd994a9f4d..c76c3eb4a641 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -1002,6 +1002,7 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) { int cid, security; struct wil6210_priv *wil = ndev_to_wil(ndev); + struct wil6210_vif *vif = ndev_to_vif(ndev); struct wil_net_stats *stats; wil->txrx_ops.get_netif_rx_params(skb, &cid, &security); @@ -1010,6 +1011,18 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) skb_orphan(skb); + /* pass only EAPOL packets as plaintext */ + if (vif->privacy && !security && + wil_skb_get_protocol(skb) != htons(ETH_P_PAE)) { + wil_dbg_txrx(wil, + "Rx drop plaintext frame with %d bytes in secure network\n", + skb->len); + dev_kfree_skb(skb); + ndev->stats.rx_dropped++; + stats->rx_dropped++; + return; + } + if (security && (wil->txrx_ops.rx_crypto_check(wil, skb) != 0)) { wil_dbg_txrx(wil, "Rx drop %d bytes\n", skb->len); dev_kfree_skb(skb); From b2c81339a9c4041c03a9b3f023fbd50627d7b69a Mon Sep 17 00:00:00 2001 From: Ahmad Masri Date: Sun, 15 Nov 2020 17:43:32 +0200 Subject: [PATCH 3/3] 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: Ahmad Masri --- drivers/net/wireless/ath/wil6210/main.c | 10 ++- drivers/net/wireless/ath/wil6210/pcie_bus.c | 3 +- drivers/net/wireless/ath/wil6210/txrx_edma.c | 94 +++++++++++++++++++- drivers/net/wireless/ath/wil6210/txrx_edma.h | 20 ++++- drivers/net/wireless/ath/wil6210/wil6210.h | 8 +- drivers/net/wireless/ath/wil6210/wmi.c | 3 +- 6 files changed, 131 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index ff95b1a02777..528496796895 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -1,7 +1,7 @@ // 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 @@ -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; diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index ce24a406c0d3..1f85d1825883 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -1,7 +1,7 @@ // 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 @@ -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; diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c index 4fd5a9b5e045..de77d89beb56 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.c +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c @@ -1,6 +1,6 @@ // 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 @@ -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 @@ skipping: 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 */ diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.h b/drivers/net/wireless/ath/wil6210/txrx_edma.h index f04d443d9a5d..56c5aff5137c 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.h +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.h @@ -1,6 +1,6 @@ /* 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) diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 54f0a85fc386..21b4181b0ad8 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -1,7 +1,7 @@ /* 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__ */ diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index a4bce46dd4ec..e2c41938dc2e 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1,7 +1,7 @@ // 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 @@ -1092,6 +1092,7 @@ static void wmi_evt_connect(struct wil6210_vif *vif, int id, void *d, int len) ether_addr_copy(wil->sta[evt->cid].addr, evt->bssid); wil->sta[evt->cid].mid = vif->mid; wil->sta[evt->cid].status = wil_sta_conn_pending; + wil_sta_info_amsdu_init(&wil->sta[evt->cid]); rc = wil_ring_init_tx(vif, evt->cid); if (rc) {