Register IPv4 notifier to notify change in IP.
Detect IPv4 address change during suspend state and reconfigure
the ARP filters to the firmware.
Change-Id: I8df10c6ef1d7be81dfd39ace268474bab6b4b353
CRs-Fixed: 587415
Conflicts:
prima/CORE/HDD/inc/wlan_hdd_power.h
diff --git a/CORE/HDD/inc/wlan_hdd_main.h b/CORE/HDD/inc/wlan_hdd_main.h
index 79149fa..1367813 100644
--- a/CORE/HDD/inc/wlan_hdd_main.h
+++ b/CORE/HDD/inc/wlan_hdd_main.h
@@ -833,6 +833,10 @@
struct work_struct ipv6NotifierWorkQueue;
#endif
+ /** IPv4 notifier callback for handling ARP offload on change in IP */
+ struct notifier_block ipv4_notifier;
+ struct work_struct ipv4NotifierWorkQueue;
+
//TODO Move this to sta Ctx
struct wireless_dev wdev ;
struct cfg80211_scan_request *request ;
@@ -1315,6 +1319,7 @@
int wlan_hdd_validate_context(hdd_context_t *pHddCtx);
v_BOOL_t hdd_is_valid_mac_address(const tANI_U8* pMacAddr);
VOS_STATUS hdd_issta_p2p_clientconnected(hdd_context_t *pHddCtx);
+void hdd_ipv4_notifier_work_queue(struct work_struct *work);
#ifdef WLAN_FEATURE_PACKET_FILTERING
int wlan_hdd_setIPv6Filter(hdd_context_t *pHddCtx, tANI_U8 filterType, tANI_U8 sessionId);
#endif
diff --git a/CORE/HDD/inc/wlan_hdd_power.h b/CORE/HDD/inc/wlan_hdd_power.h
index 0810397..b0f077b 100644
--- a/CORE/HDD/inc/wlan_hdd_power.h
+++ b/CORE/HDD/inc/wlan_hdd_power.h
@@ -91,7 +91,7 @@
VOS_STATUS hdd_wlan_re_init(void);
void hdd_conf_mcastbcast_filter(hdd_context_t* pHddCtx, v_BOOL_t setfilter);
-VOS_STATUS hdd_conf_arp_offload(hdd_adapter_t* pAdapter, v_BOOL_t fenable);
+VOS_STATUS hdd_conf_arp_offload(hdd_adapter_t* pAdapter, int fenable);
/*
* Function: hdd_conf_hostoffload
* Central function to configure the supported offloads,
diff --git a/CORE/HDD/src/wlan_hdd_early_suspend.c b/CORE/HDD/src/wlan_hdd_early_suspend.c
index 5f7049d..042bf1b 100644
--- a/CORE/HDD/src/wlan_hdd_early_suspend.c
+++ b/CORE/HDD/src/wlan_hdd_early_suspend.c
@@ -777,16 +777,94 @@
return;
}
#endif
-VOS_STATUS hdd_conf_arp_offload(hdd_adapter_t *pAdapter, v_BOOL_t fenable)
+
+void hdd_ipv4_notifier_work_queue(struct work_struct *work)
+{
+ hdd_adapter_t* pAdapter =
+ container_of(work, hdd_adapter_t, ipv4NotifierWorkQueue);
+ hdd_context_t *pHddCtx;
+ int status;
+
+ hddLog(LOG1, FL("Reconfiguring ARP Offload"));
+ pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
+ status = wlan_hdd_validate_context(pHddCtx);
+ if (0 != status)
+ {
+ hddLog(LOGE, FL("HDD context is invalid"));
+ return;
+ }
+
+ if ((eConnectionState_Associated ==
+ (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState)
+ && (VOS_TRUE == pHddCtx->sus_res_mcastbcast_filter_valid))
+ {
+ // This invocation being part of the IPv4 registration callback,
+ // we are passing second parameter as 2 to avoid registration
+ // of IPv4 notifier again.
+ hdd_conf_arp_offload(pAdapter, 2);
+ }
+}
+
+static int wlan_hdd_ipv4_changed(struct notifier_block *nb,
+ unsigned long data, void *arg)
+{
+ struct in_ifaddr *ifa = (struct in_ifaddr *)arg;
+ struct in_ifaddr **ifap = NULL;
+ struct in_device *in_dev;
+
+ struct net_device *ndev = ifa->ifa_dev->dev;
+ hdd_adapter_t *pAdapter =
+ container_of(nb, struct hdd_adapter_s, ipv4_notifier);
+
+ if (pAdapter && pAdapter->dev == ndev)
+ {
+ if ((in_dev = __in_dev_get_rtnl(pAdapter->dev)) != NULL)
+ {
+ for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
+ ifap = &ifa->ifa_next)
+ {
+ if (!strcmp(pAdapter->dev->name, ifa->ifa_label))
+ {
+ break; /* found */
+ }
+ }
+ }
+ if(ifa && ifa->ifa_local)
+ {
+ schedule_work(&pAdapter->ipv4NotifierWorkQueue);
+ }
+ }
+
+ return NOTIFY_DONE;
+}
+
+/**----------------------------------------------------------------------------
+
+ \brief hdd_conf_arp_offload() - Configure ARP offload
+
+ Called during SUSPEND to configure the ARP offload (MC BC filter) which
+ reduces power consumption.
+
+ \param - pAdapter -Adapter context for which ARP offload is to be configured
+ \param - fenable - 0 - disable.
+ 1 - enable. (with IPv4 notifier registration)
+ 2 - enable. (without IPv4 notifier registration)
+
+ \return -
+ VOS_STATUS_SUCCESS - on successful operation
+ VOS_STATUS_E_FAILURE - on failure of operation
+-----------------------------------------------------------------------------*/
+VOS_STATUS hdd_conf_arp_offload(hdd_adapter_t *pAdapter, int fenable)
{
struct in_ifaddr **ifap = NULL;
struct in_ifaddr *ifa = NULL;
struct in_device *in_dev;
int i = 0;
+ int ret = 0;
tSirHostOffloadReq offLoadRequest;
hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
- hddLog(VOS_TRACE_LEVEL_ERROR, "%s:", __func__);
+ hddLog(VOS_TRACE_LEVEL_ERROR, FL(" fenable = %d \n"), fenable);
if(fenable)
{
@@ -843,16 +921,29 @@
"feature", __func__);
return VOS_STATUS_E_FAILURE;
}
- return VOS_STATUS_SUCCESS;
}
else
{
- hddLog(VOS_TRACE_LEVEL_INFO, "%s:IP Address is not assigned", __func__);
- return VOS_STATUS_E_AGAIN;
+ hddLog(VOS_TRACE_LEVEL_INFO, FL("IP Address is not assigned\n"));
}
+
+ if (fenable == 1)
+ {
+ // Register IPv4 notifier to notify if any change in IP
+ // So that we can reconfigure the offload parameters
+ pAdapter->ipv4_notifier.notifier_call =
+ wlan_hdd_ipv4_changed;
+ ret = register_inetaddr_notifier(&pAdapter->ipv4_notifier);
+ if (ret)
+ {
+ hddLog(LOGE, FL("Failed to register IPv4 notifier"));
+ }
+ }
+ return VOS_STATUS_SUCCESS;
}
else
{
+ unregister_inetaddr_notifier(&pAdapter->ipv4_notifier);
vos_mem_zero((void *)&offLoadRequest, sizeof(tSirHostOffloadReq));
offLoadRequest.enableOrDisable = SIR_OFFLOAD_DISABLE;
offLoadRequest.offloadType = SIR_IPV4_ARP_REPLY_OFFLOAD;
diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c
index 1f0c694..cdf0b36 100755
--- a/CORE/HDD/src/wlan_hdd_main.c
+++ b/CORE/HDD/src/wlan_hdd_main.c
@@ -5805,6 +5805,9 @@
goto err_free_netdev;
}
+ // Workqueue which gets scheduled in IPv4 notification callback.
+ INIT_WORK(&pAdapter->ipv4NotifierWorkQueue, hdd_ipv4_notifier_work_queue);
+
#ifdef WLAN_NS_OFFLOAD
// Workqueue which gets scheduled in IPv6 notification callback.
INIT_WORK(&pAdapter->ipv6NotifierWorkQueue, hdd_ipv6_notifier_work_queue);
@@ -6129,6 +6132,9 @@
#endif
#endif
+#ifdef WLAN_OPEN_SOURCE
+ cancel_work_sync(&pAdapter->ipv4NotifierWorkQueue);
+#endif
if (test_bit(SME_SESSION_OPENED, &pAdapter->event_flags))
{
INIT_COMPLETION(pAdapter->session_close_comp_var);
diff --git a/prima/CORE/HDD/inc/wlan_hdd_power.h b/prima/CORE/HDD/inc/wlan_hdd_power.h
new file mode 100644
index 0000000..e977ea1
--- /dev/null
+++ b/prima/CORE/HDD/inc/wlan_hdd_power.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2012-2013 Qualcomm Atheros, Inc.
+ * All Rights Reserved.
+ * Qualcomm Atheros Confidential and Proprietary.
+ */
+#ifndef __WLAN_HDD_POWER_H
+#define __WLAN_HDD_POWER_H
+
+/**===========================================================================
+
+ \file wlan_hdd_power.h
+
+ \brief Linux HDD Power
+ Copyright 2008 (c) Qualcomm Technologies, Inc.
+ All Rights Reserved.
+ Qualcomm Technologies Confidential and Proprietary.
+
+ ==========================================================================*/
+
+
+/*--------------------------------------------------------------------------
+ * Include Files
+ *------------------------------------------------------------------------*/
+#include "wlan_hdd_main.h"
+
+/*---------------------------------------------------------------------------
+ * Preprocessor definitions and constants
+ *-------------------------------------------------------------------------*/
+ //gEnableSuspend = 1 in INI file implies suspend to standby
+ #define WLAN_MAP_SUSPEND_TO_STANDBY 1
+
+ //gEnableSuspend = 2 in INI file implies suspend to deep sleep
+ #define WLAN_MAP_SUSPEND_TO_DEEP_SLEEP 2
+
+ //gEnableSuspend = 3 in INI file implies suspend to set MCAST/BCAST filter
+ #define WLAN_MAP_SUSPEND_TO_MCAST_BCAST_FILTER 3
+
+ //gEnableDriverStop = 1 implies map driver stop to standby
+ #define WLAN_MAP_DRIVER_STOP_TO_STANDBY 1
+
+ //gEnableDriverStop = 2 implies map sriver stop to deep sleep
+ #define WLAN_MAP_DRIVER_STOP_TO_DEEP_SLEEP 2
+
+ //Maximum time (ms) to wait for standby to complete
+ #define WLAN_WAIT_TIME_STANDBY 3000
+
+ //Maximum time (ms) to wait for full pwr to complete
+ #define WLAN_WAIT_TIME_FULL_PWR 3000
+
+
+/*---------------------------------------------------------------------------
+ * Type declarations
+ *-------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------
+ * Function declarations and documentation
+ * ------------------------------------------------------------------------*/
+ eHalStatus hdd_exit_standby(hdd_context_t *pHddCtx);
+ VOS_STATUS hdd_exit_deep_sleep(hdd_context_t *pHddCtx,
+ hdd_adapter_t* pAdapter);
+ VOS_STATUS hdd_enter_standby(hdd_context_t *pHddCtx);
+ VOS_STATUS hdd_enter_deep_sleep(hdd_context_t *pHddCtx,
+ hdd_adapter_t* pAdapter);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ VOS_STATUS hdd_wlan_reset(void);
+ VOS_STATUS hdd_wlan_reset_initialization(void) ;
+#endif
+ /* SSR shutdown & re-init functions */
+ VOS_STATUS hdd_wlan_shutdown(void);
+ VOS_STATUS hdd_wlan_re_init(void);
+
+void hdd_conf_mcastbcast_filter(hdd_context_t* pHddCtx, v_BOOL_t setfilter);
+VOS_STATUS hdd_conf_arp_offload(hdd_adapter_t* pAdapter, int fenable);
+/*
+ * Function: hdd_conf_hostoffload
+ * Central function to configure the supported offloads,
+ * either enable or disable them.
+ */
+void hdd_conf_hostoffload(hdd_adapter_t * pAdapter, v_BOOL_t fenable);
+#ifdef WLAN_FEATURE_GTK_OFFLOAD
+void hdd_conf_gtk_offload(hdd_adapter_t *pAdapter, v_BOOL_t fenable);
+#endif
+#ifdef WLAN_NS_OFFLOAD
+void hdd_conf_ns_offload(hdd_adapter_t *pAdapter, int fenable);
+#endif
+#endif // if !defined __WLAN_QCT_DRIVER_H