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 5f7049de6..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);