浏览代码

qcacld-3.0: Do not acquire rx wake lock for non local ARP

Propagation from qcacld-2.0 to qcacld-3.0

Currently even for non local ARP requests wake lock is getting
acquired which is preventing the system suspend which is a power
penalty. Do not acquire wake lock for the non local ARP requests.

Change-Id: I5fcd0cf0edc5c28a4662ae49a33cc55a77f3d3e4
CRs-Fixed: 1088974
Sravan Kumar Kairam 8 年之前
父节点
当前提交
2fc4755bc7
共有 1 个文件被更改,包括 62 次插入4 次删除
  1. 62 4
      core/hdd/src/wlan_hdd_tx_rx.c

+ 62 - 4
core/hdd/src/wlan_hdd_tx_rx.c

@@ -41,6 +41,7 @@
 #include <linux/skbuff.h>
 #include <linux/etherdevice.h>
 #include <linux/if_ether.h>
+#include <linux/inetdevice.h>
 #include <cds_sched.h>
 #include <cds_utils.h>
 
@@ -1016,6 +1017,62 @@ static bool hdd_is_mcast_replay(struct sk_buff *skb)
 	return false;
 }
 
+/**
+* hdd_is_arp_local() - check if local or non local arp
+* @skb: pointer to sk_buff
+*
+* Return: true if local arp or false otherwise.
+*/
+static bool hdd_is_arp_local(struct sk_buff *skb)
+{
+	struct arphdr *arp;
+	struct in_ifaddr **ifap = NULL;
+	struct in_ifaddr *ifa = NULL;
+	struct in_device *in_dev;
+	unsigned char *arp_ptr;
+	__be32 tip;
+
+	arp = (struct arphdr *)skb->data;
+	if (arp->ar_op == htons(ARPOP_REQUEST)) {
+		in_dev = __in_dev_get_rtnl(skb->dev);
+		if (in_dev) {
+			for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
+				ifap = &ifa->ifa_next) {
+				if (!strcmp(skb->dev->name, ifa->ifa_label))
+					break;
+			}
+		}
+
+		if (ifa && ifa->ifa_local) {
+			arp_ptr = (unsigned char *)(arp + 1);
+			arp_ptr += (skb->dev->addr_len + 4 +
+					skb->dev->addr_len);
+			memcpy(&tip, arp_ptr, 4);
+			hdd_info("ARP packet: local IP: %x dest IP: %x",
+				ifa->ifa_local, tip);
+			if (ifa->ifa_local != tip)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/**
+* hdd_is_rx_wake_lock_needed() - check if wake lock is needed
+* @skb: pointer to sk_buff
+*
+* Return: true if wake lock is needed or false otherwise.
+*/
+static bool hdd_is_rx_wake_lock_needed(struct sk_buff *skb)
+{
+	if ((skb->pkt_type != PACKET_BROADCAST &&
+	     skb->pkt_type != PACKET_MULTICAST) || hdd_is_arp_local(skb))
+		return true;
+
+	return false;
+}
+
 /**
  * hdd_rx_packet_cbk() - Receive packet handler
  * @context: pointer to HDD context
@@ -1038,7 +1095,7 @@ QDF_STATUS hdd_rx_packet_cbk(void *context, qdf_nbuf_t rxBuf)
 	hdd_station_ctx_t *pHddStaCtx = NULL;
 	unsigned int cpu_index;
 	struct qdf_mac_addr *mac_addr;
-
+	bool wake_lock = false;
 
 	/* Sanity check on inputs */
 	if (unlikely((NULL == context) || (NULL == rxBuf))) {
@@ -1127,9 +1184,10 @@ QDF_STATUS hdd_rx_packet_cbk(void *context, qdf_nbuf_t rxBuf)
 		}
 
 		/* hold configurable wakelock for unicast traffic */
-		if (pHddCtx->config->rx_wakelock_timeout &&
-			skb->pkt_type != PACKET_BROADCAST &&
-			skb->pkt_type != PACKET_MULTICAST) {
+		if (pHddCtx->config->rx_wakelock_timeout)
+			wake_lock = hdd_is_rx_wake_lock_needed(skb);
+
+		if (wake_lock) {
 			cds_host_diag_log_work(&pHddCtx->rx_wake_lock,
 						   pHddCtx->config->rx_wakelock_timeout,
 						   WIFI_POWER_EVENT_WAKELOCK_HOLD_RX);