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.c b/drivers/net/wireless/ath/wil6210/txrx.c index 48526c6509e9..c76c3eb4a641 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 @@ -1000,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); @@ -1008,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); 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); 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) {