summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/hdd/inc/wlan_hdd_cfg.h14
-rw-r--r--core/hdd/src/wlan_hdd_cfg.c11
-rw-r--r--core/hdd/src/wlan_hdd_tx_rx.c31
3 files changed, 56 insertions, 0 deletions
diff --git a/core/hdd/inc/wlan_hdd_cfg.h b/core/hdd/inc/wlan_hdd_cfg.h
index 672a1297d534..2d51b340304c 100644
--- a/core/hdd/inc/wlan_hdd_cfg.h
+++ b/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))
diff --git a/core/hdd/src/wlan_hdd_cfg.c b/core/hdd/src/wlan_hdd_cfg.c
index 29fc5aa8f16b..b9bebdc0e1bb 100644
--- a/core/hdd/src/wlan_hdd_cfg.c
+++ b/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);
}
diff --git a/core/hdd/src/wlan_hdd_tx_rx.c b/core/hdd/src/wlan_hdd_tx_rx.c
index 5c4d503489a5..53bfa38f9c4e 100644
--- a/core/hdd/src/wlan_hdd_tx_rx.c
+++ b/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,