소스 검색

qcacld-3.0: Drop replayed multicast packets

Integration from qcacld-2.0 to qcacld-3.0

IPv6 Multicast (Neighbor Solicitation) frames are
not rejected by the WLAN driver when these frames
are bounced back from the AP. This causes network
stack to assume the duplicate IP address on the
network and fails to assign the IPv6 address.
Currently, this is a workaround till the issue is
root caused.

Change-Id: If5d48ed903f484805e7f4be9df52582e50bd6ce5
CRs-Fixed: 748105
Ravi Joshi 8 년 전
부모
커밋
bb8d451c63
3개의 변경된 파일56개의 추가작업 그리고 0개의 파일을 삭제
  1. 14 0
      core/hdd/inc/wlan_hdd_cfg.h
  2. 11 0
      core/hdd/src/wlan_hdd_cfg.c
  3. 31 0
      core/hdd/src/wlan_hdd_tx_rx.c

+ 14 - 0
core/hdd/inc/wlan_hdd_cfg.h

@@ -3481,6 +3481,19 @@ enum dot11p_mode {
 #define CFG_INDOOR_CHANNEL_SUPPORT_MAX      (1)
 #define CFG_INDOOR_CHANNEL_SUPPORT_DEFAULT  (0)
 
+/*
+ * Enable filtering of replayed multicast packets
+ * In a typical infrastructure setup, it is quite normal to receive
+ * replayed multicast packets. These packets may cause more harm than
+ * help if not handled properly. Providing a configuration option
+ * to enable filtering of such packets
+ */
+#define CFG_FILTER_MULTICAST_REPLAY_NAME    "enable_multicast_replay_filter"
+#define CFG_FILTER_MULTICAST_REPLAY_MIN      (0)
+#define CFG_FILTER_MULTICAST_REPLAY_MAX      (1)
+#define CFG_FILTER_MULTICAST_REPLAY_DEFAULT  (1)
+
+
 /*---------------------------------------------------------------------------
    Type declarations
    -------------------------------------------------------------------------*/
@@ -4141,6 +4154,7 @@ struct hdd_config {
 	uint32_t iface_change_wait_time;
 	enum cfg_sub_20_channel_width enable_sub_20_channel_width;
 	bool indoor_channel_support;
+	bool multicast_replay_filter;
 };
 
 #define VAR_OFFSET(_Struct, _Var) (offsetof(_Struct, _Var))

+ 11 - 0
core/hdd/src/wlan_hdd_cfg.c

@@ -4007,6 +4007,14 @@ REG_TABLE_ENTRY g_registry_table[] = {
 			CFG_INTERFACE_CHANGE_WAIT_DEFAULT,
 			CFG_INTERFACE_CHANGE_WAIT_MIN,
 			CFG_INTERFACE_CHANGE_WAIT_MAX),
+
+	REG_VARIABLE(CFG_FILTER_MULTICAST_REPLAY_NAME,
+		WLAN_PARAM_Integer,
+		struct hdd_config, multicast_replay_filter,
+		VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
+		CFG_FILTER_MULTICAST_REPLAY_DEFAULT,
+		CFG_FILTER_MULTICAST_REPLAY_MIN,
+		CFG_FILTER_MULTICAST_REPLAY_MAX),
 };
 
 /**
@@ -5686,6 +5694,9 @@ void hdd_cfg_print(hdd_context_t *pHddCtx)
 	hdd_info("Name = [%s] Value = [%d]",
 		CFG_BPF_PACKET_FILTER_OFFLOAD,
 		pHddCtx->config->bpf_packet_filter_enable);
+	hdd_info("Name = [%s] Value = [%d]",
+		CFG_FILTER_MULTICAST_REPLAY_NAME,
+		pHddCtx->config->multicast_replay_filter);
 }
 
 

+ 31 - 0
core/hdd/src/wlan_hdd_tx_rx.c

@@ -37,6 +37,7 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <linux/etherdevice.h>
+#include <linux/if_ether.h>
 #include <cds_sched.h>
 
 #include <wlan_hdd_p2p.h>
@@ -851,6 +852,25 @@ int hdd_get_peer_idx(hdd_station_ctx_t *sta_ctx, struct qdf_mac_addr *addr)
 	return INVALID_PEER_IDX;
 }
 
+/*
+ * hdd_is_mcast_replay() - checks if pkt is multicast replay
+ * @skb: packet skb
+ *
+ * Return: true if replayed multicast pkt, false otherwise
+ */
+static bool hdd_is_mcast_replay(struct sk_buff *skb)
+{
+	struct ethhdr *eth;
+
+	eth = eth_hdr(skb);
+	if (unlikely(skb->pkt_type == PACKET_MULTICAST)) {
+		if (unlikely(ether_addr_equal(eth->h_source,
+				skb->dev->dev_addr)))
+			return true;
+	}
+	return false;
+}
+
 /**
  * hdd_rx_packet_cbk() - Receive packet handler
  * @context: pointer to HDD context
@@ -926,6 +946,17 @@ QDF_STATUS hdd_rx_packet_cbk(void *context, qdf_nbuf_t rxBuf)
 	++pAdapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index];
 	++pAdapter->stats.rx_packets;
 	pAdapter->stats.rx_bytes += skb->len;
+
+	/* Check & drop replayed mcast packets (for IPV6) */
+	if (pHddCtx->config->multicast_replay_filter &&
+			hdd_is_mcast_replay(skb)) {
+		++pAdapter->hdd_stats.hddTxRxStats.rxDropped[cpu_index];
+		QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_INFO,
+			"%s: Dropping multicast replay pkt", __func__);
+		kfree_skb(skb);
+		return QDF_STATUS_SUCCESS;
+	}
+
 #ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
 	qdf_wake_lock_timeout_acquire(&pHddCtx->rx_wake_lock,
 				      HDD_WAKE_LOCK_DURATION,