qcacld-3.0: Add support for arp/ns offload in PMO component

Add support for arp/ns offload in PMO component

Change-Id: I823ba0a426cce5a5717cf2b693b49c8f8a2f7a29
CRs-Fixed: 2002639
diff --git a/core/hdd/inc/wlan_hdd_power.h b/core/hdd/inc/wlan_hdd_power.h
index 0fb18a3..5a45179 100644
--- a/core/hdd/inc/wlan_hdd_power.h
+++ b/core/hdd/inc/wlan_hdd_power.h
@@ -147,9 +147,57 @@
 QDF_STATUS hdd_wlan_shutdown(void);
 QDF_STATUS hdd_wlan_re_init(void);
 
-QDF_STATUS hdd_conf_arp_offload(hdd_adapter_t *pAdapter, bool fenable);
-void hdd_conf_hostoffload(hdd_adapter_t *pAdapter, bool fenable);
+/**
+ * hdd_enable_arp_offload() - API to enable ARP offload
+ * @adapter: Adapter context for which ARP offload is to be configured
+ * @trigger: trigger reason for request
+ *
+ * Return: None
+ */
+void hdd_enable_arp_offload(hdd_adapter_t *adapter,
+		enum pmo_offload_trigger trigger);
 
+/**
+ * hdd_disable_arp_offload() - API to disable ARP offload
+ * @adapter: Adapter context for which ARP offload is to be configured
+ * @trigger: trigger reason for request
+ *
+ * Return: None
+ */
+void hdd_disable_arp_offload(hdd_adapter_t *adapter,
+		enum pmo_offload_trigger trigger);
+
+/**
+ * hdd_enable_host_offloads() - Central API to enable the supported offloads
+ * @adapter:   pointer to the adapter
+ * @trigger: trigger reason for request
+ *
+ * Central function to enable the supported offloads
+ *
+ * Return: nothing
+ */
+void hdd_enable_host_offloads(hdd_adapter_t *adapter,
+	enum pmo_offload_trigger trigger);
+
+/**
+ * hdd_disable_host_offloads() - Central API to disable the supported offloads
+ * @adapter:   pointer to the adapter
+ * @trigger: trigger reason for request
+ *
+ * Central function to disable the supported offloads
+ *
+ * Return: nothing
+ */
+void hdd_disable_host_offloads(hdd_adapter_t *adapter,
+	enum pmo_offload_trigger trigger);
+
+/**
+ * hdd_conf_mc_addr_filtering_enable() - enable MC address list in FW
+ * @pAdapter: adapter whose MC list is being set
+ * @trigger: trigger reason for request
+ *
+ * Return: nothing
+ */
 #ifdef WLAN_FEATURE_PACKET_FILTERING
 void wlan_hdd_set_mc_addr_list(hdd_adapter_t *pAdapter, uint8_t set);
 #else
@@ -165,10 +213,28 @@
 int wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy);
 
 void hdd_ipv4_notifier_work_queue(struct work_struct *work);
-#ifdef WLAN_NS_OFFLOAD
-void hdd_conf_ns_offload(hdd_adapter_t *adapter, bool fenable);
+
+
+/**
+ * hdd_enable_ns_offload() - enable NS offload
+ * @adapter:   pointer to the adapter
+ *
+ * Return: nothing
+ */
+void hdd_enable_ns_offload(hdd_adapter_t *adapter,
+	enum pmo_offload_trigger trigger);
+
+/**
+ * hdd_disable_ns_offload() - disable NS offload
+ * @adapter:   pointer to the adapter
+ *
+ * Return: nothing
+ */
+void hdd_disable_ns_offload(hdd_adapter_t *adapter,
+	enum pmo_offload_trigger trigger);
+
 void hdd_ipv6_notifier_work_queue(struct work_struct *work);
-#endif
+
 
 int wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy,
 				  struct wireless_dev *wdev,
diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c
index 18663bb..bfc4c15 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.c
+++ b/core/hdd/src/wlan_hdd_cfg80211.c
@@ -5720,7 +5720,10 @@
 		nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_FLAG]);
 
 	/* update ns offload in case it is already enabled/disabled */
-	hdd_conf_ns_offload(adapter, pHddCtx->ns_offload_enable);
+	if (pHddCtx->ns_offload_enable)
+		hdd_enable_ns_offload(adapter, pmo_ns_offload_dynamic_update);
+	else
+		hdd_disable_ns_offload(adapter, pmo_ns_offload_dynamic_update);
 
 	return 0;
 }
diff --git a/core/hdd/src/wlan_hdd_power.c b/core/hdd/src/wlan_hdd_power.c
index f8268d3..e8f73ef 100644
--- a/core/hdd/src/wlan_hdd_power.c
+++ b/core/hdd/src/wlan_hdd_power.c
@@ -80,6 +80,7 @@
 #include <wlan_logging_sock_svc.h>
 #include "scheduler_api.h"
 #include "cds_utils.h"
+#include "wlan_pmo_ucfg_api.h"
 
 /* Preprocessor definitions and constants */
 #define HDD_SSR_BRING_UP_TIME 30000
@@ -215,7 +216,7 @@
 }
 #endif /*WLAN_FEATURE_GTK_OFFLOAD */
 
-#ifdef WLAN_NS_OFFLOAD
+
 /**
  * __wlan_hdd_ipv6_changed() - IPv6 notifier callback function
  * @nb: notifier block that was registered with the kernel
@@ -312,7 +313,7 @@
 
 	read_lock_bh(&idev->lock);
 	list_for_each(p, &idev->addr_list) {
-		if (*count >= SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) {
+		if (*count >= PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) {
 			read_unlock_bh(&idev->lock);
 			return -EINVAL;
 		}
@@ -325,7 +326,7 @@
 		case IPV6_ADDR_SCOPE_LINKLOCAL:
 			qdf_mem_copy(ipv6_uc_addr[*count], &ifa->addr.s6_addr,
 				sizeof(ifa->addr.s6_addr));
-			ipv6addr_type[*count] = SIR_IPV6_ADDR_UC_TYPE;
+			ipv6addr_type[*count] = PMO_IPV6_ADDR_UC_TYPE;
 			hdd_info("Index %d scope = %s UC-Address: %pI6",
 				*count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ?
 				"LINK LOCAL" : "GLOBAL", ipv6_uc_addr[*count]);
@@ -360,7 +361,7 @@
 
 	read_lock_bh(&idev->lock);
 	for (ifaca = idev->ac_list; ifaca; ifaca = ifaca->aca_next) {
-		if (*count >= SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) {
+		if (*count >= PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) {
 			read_unlock_bh(&idev->lock);
 			return -EINVAL;
 		}
@@ -371,7 +372,7 @@
 		case IPV6_ADDR_SCOPE_LINKLOCAL:
 			qdf_mem_copy(ipv6_ac_addr[*count], &ifaca->aca_addr,
 				sizeof(ifaca->aca_addr));
-			ipv6addr_type[*count] = SIR_IPV6_ADDR_AC_TYPE;
+			ipv6addr_type[*count] = PMO_IPV6_ADDR_AC_TYPE;
 			hdd_info("Index %d scope = %s AC-Address: %pI6",
 				*count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ?
 				"LINK LOCAL" : "GLOBAL", ipv6_ac_addr[*count]);
@@ -386,165 +387,101 @@
 	return 0;
 }
 
-/**
- * hdd_disable_ns_offload() - Disables IPv6 NS offload
- * @adapter:	ponter to the adapter
- *
- * Return:	nothing
- */
-static void hdd_disable_ns_offload(hdd_adapter_t *adapter)
-{
-	tSirHostOffloadReq offloadReq;
-	QDF_STATUS status;
-
-	qdf_mem_zero((void *)&offloadReq, sizeof(tSirHostOffloadReq));
-	hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD, SIR_OFFLOAD_DISABLE);
-	offloadReq.enableOrDisable = SIR_OFFLOAD_DISABLE;
-	offloadReq.offloadType =  SIR_IPV6_NS_OFFLOAD;
-	status = sme_set_host_offload(
-		WLAN_HDD_GET_HAL_CTX(adapter),
-		adapter->sessionId, &offloadReq);
-
-	if (QDF_STATUS_SUCCESS != status)
-		hdd_err("Failed to disable NS Offload");
-}
-
-/**
- * hdd_enable_ns_offload() - Enables IPv6 NS offload
- * @adapter:	ponter to the adapter
- *
- * Return:	nothing
- */
-static void hdd_enable_ns_offload(hdd_adapter_t *adapter)
+void hdd_enable_ns_offload(hdd_adapter_t *adapter,
+	enum pmo_offload_trigger trigger)
 {
 	struct inet6_dev *in6_dev;
-	uint8_t ipv6_addr[SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA]
-					[SIR_MAC_IPV6_ADDR_LEN] = { {0,} };
-	uint8_t ipv6_addr_type[SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA] = { 0 };
-	tSirHostOffloadReq offloadReq;
 	QDF_STATUS status;
-	uint32_t count = 0;
-	int err, i;
+	hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
+	struct pmo_ns_req *ns_req = NULL;
+	int err;
+
+	ENTER();
+	if (!psoc) {
+		hdd_err("psoc is NULL");
+		goto out;
+	}
 
 	in6_dev = __in6_dev_get(adapter->dev);
 	if (NULL == in6_dev) {
 		hdd_err("IPv6 dev does not exist. Failed to request NSOffload");
-		return;
+		goto out;
 	}
 
+	ns_req = qdf_mem_malloc(sizeof(*ns_req));
+	if (!ns_req) {
+		hdd_err("fail to allocate ns_req");
+		goto out;
+	}
+
+	ns_req->psoc = psoc;
+	ns_req->vdev_id = adapter->sessionId;
+	ns_req->trigger = trigger;
+	ns_req->count = 0;
+
 	/* Unicast Addresses */
-	err = hdd_fill_ipv6_uc_addr(in6_dev, ipv6_addr, ipv6_addr_type, &count);
+	err = hdd_fill_ipv6_uc_addr(in6_dev, ns_req->ipv6_addr,
+		ns_req->ipv6_addr_type, &ns_req->count);
 	if (err) {
-		hdd_disable_ns_offload(adapter);
+		hdd_disable_ns_offload(adapter, trigger);
 		hdd_notice("Reached max supported addresses and not enabling "
 			"NS offload");
-		return;
+		goto out;
 	}
 
 	/* Anycast Addresses */
-	err = hdd_fill_ipv6_ac_addr(in6_dev, ipv6_addr, ipv6_addr_type, &count);
+	err = hdd_fill_ipv6_ac_addr(in6_dev, ns_req->ipv6_addr,
+		ns_req->ipv6_addr_type, &ns_req->count);
 	if (err) {
-		hdd_disable_ns_offload(adapter);
+		hdd_disable_ns_offload(adapter, trigger);
 		hdd_notice("Reached max supported addresses and not enabling "
 			"NS offload");
-		return;
+		goto out;
 	}
 
-	qdf_mem_zero(&offloadReq, sizeof(offloadReq));
-	for (i = 0; i < count; i++) {
-		/* Filling up the request structure
-		 * Filling the selfIPv6Addr with solicited address
-		 * A Solicited-Node multicast address is created by
-		 * taking the last 24 bits of a unicast or anycast
-		 * address and appending them to the prefix
-		 *
-		 * FF02:0000:0000:0000:0000:0001:FFXX:XXXX
-		 *
-		 * here XX is the unicast/anycast bits
-		 */
-		offloadReq.nsOffloadInfo.selfIPv6Addr[i][0] = 0xFF;
-		offloadReq.nsOffloadInfo.selfIPv6Addr[i][1] = 0x02;
-		offloadReq.nsOffloadInfo.selfIPv6Addr[i][11] = 0x01;
-		offloadReq.nsOffloadInfo.selfIPv6Addr[i][12] = 0xFF;
-		offloadReq.nsOffloadInfo.selfIPv6Addr[i][13] =
-					ipv6_addr[i][13];
-		offloadReq.nsOffloadInfo.selfIPv6Addr[i][14] =
-					ipv6_addr[i][14];
-		offloadReq.nsOffloadInfo.selfIPv6Addr[i][15] =
-					ipv6_addr[i][15];
-		offloadReq.nsOffloadInfo.slotIdx = i;
-		qdf_mem_copy(&offloadReq.nsOffloadInfo.targetIPv6Addr[i],
-			&ipv6_addr[i][0], SIR_MAC_IPV6_ADDR_LEN);
-
-		offloadReq.nsOffloadInfo.targetIPv6AddrValid[i] =
-			SIR_IPV6_ADDR_VALID;
-		offloadReq.nsOffloadInfo.target_ipv6_addr_ac_type[i] =
-			ipv6_addr_type[i];
-
-		qdf_mem_copy(&offloadReq.params.hostIpv6Addr,
-			&offloadReq.nsOffloadInfo.targetIPv6Addr[i],
-			SIR_MAC_IPV6_ADDR_LEN);
-
-		hdd_info("Setting NSOffload with solicitedIp: "
-			"%pI6, targetIp: %pI6, Index %d",
-			&offloadReq.nsOffloadInfo.selfIPv6Addr[i],
-			&offloadReq.nsOffloadInfo.targetIPv6Addr[i], i);
+	/* cache ns request */
+	status = pmo_ucfg_cache_ns_offload_req(ns_req);
+	if (status != QDF_STATUS_SUCCESS) {
+		hdd_err("Failed to cache ns request status: %d", status);
+		goto out;
 	}
 
-	hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD, SIR_OFFLOAD_ENABLE);
-	offloadReq.offloadType =  SIR_IPV6_NS_OFFLOAD;
-	offloadReq.enableOrDisable = SIR_OFFLOAD_ENABLE;
-	qdf_copy_macaddr(&offloadReq.nsOffloadInfo.self_macaddr,
-			 &adapter->macAddressCurrent);
-
-	/* set number of ns offload address count */
-	offloadReq.num_ns_offload_count = count;
-
-	/* Configure the Firmware with this */
-	status = sme_set_host_offload(WLAN_HDD_GET_HAL_CTX(adapter),
-		adapter->sessionId, &offloadReq);
-	if (QDF_STATUS_SUCCESS != status) {
+	/* enable ns request */
+	status = pmo_ucfg_enable_ns_offload_in_fwr(adapter->hdd_vdev, trigger);
+	if (status != QDF_STATUS_SUCCESS)
 		hdd_err("Failed to enable HostOffload feature with status: %d",
 			status);
-	}
+	else
+		hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD, SIR_OFFLOAD_ENABLE);
+out:
+	if (ns_req)
+		qdf_mem_free(ns_req);
+	EXIT();
+
 }
 
-/**
- * hdd_conf_ns_offload() - Configure NS offload
- * @adapter:   pointer to the adapter
- * @fenable:    flag to enable or disable
- *              0 - disable
- *              1 - enable
- *
- * Return: nothing
- */
-void hdd_conf_ns_offload(hdd_adapter_t *adapter, bool fenable)
+void hdd_disable_ns_offload(hdd_adapter_t *adapter,
+		enum pmo_offload_trigger trigger)
 {
-	hdd_context_t *hdd_ctx;
+	QDF_STATUS status;
 
 	ENTER();
-	hdd_notice(" fenable = %d", fenable);
-
-	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
-
-	/* In SAP/P2PGo mode, ARP/NS offload feature capability
-	 * is controlled by one bit.
-	 */
-
-	if ((QDF_SAP_MODE == adapter->device_mode ||
-		QDF_P2P_GO_MODE == adapter->device_mode) &&
-		!hdd_ctx->ap_arpns_support) {
-		hdd_notice("NS Offload is not supported in SAP/P2PGO mode");
-		return;
+	status = pmo_ucfg_flush_ns_offload_req(adapter->hdd_vdev);
+	if (status != QDF_STATUS_SUCCESS) {
+		hdd_err("Failed to flush NS Offload");
+		goto out;
 	}
 
-	if (fenable)
-		hdd_enable_ns_offload(adapter);
+	status = pmo_ucfg_disable_ns_offload_in_fwr(adapter->hdd_vdev, trigger);
+	if (status != QDF_STATUS_SUCCESS)
+		hdd_err("Failed to disable NS Offload");
 	else
-		hdd_disable_ns_offload(adapter);
-
+		hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD,
+			SIR_OFFLOAD_DISABLE);
+out:
 	EXIT();
-	return;
+
 }
 
 /**
@@ -564,7 +501,6 @@
 		container_of(work, hdd_adapter_t, ipv6NotifierWorkQueue);
 	hdd_context_t *pHddCtx;
 	int status;
-	bool ndi_connected = false;
 
 	ENTER();
 
@@ -573,21 +509,7 @@
 	if (0 != status)
 		return;
 
-	if (!pHddCtx->config->active_mode_offload) {
-		hdd_err("Active mode offload is disabled");
-		return;
-	}
-
-	/* check if the device is in NAN data mode */
-	if (WLAN_HDD_IS_NDI(pAdapter))
-		ndi_connected = WLAN_HDD_IS_NDI_CONNECTED(pAdapter);
-
-	if (eConnectionState_Associated ==
-	     (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState ||
-		ndi_connected)
-		if (pHddCtx->config->fhostNSOffload &&
-		    pHddCtx->ns_offload_enable)
-			hdd_conf_ns_offload(pAdapter, true);
+	hdd_enable_ns_offload(pAdapter, pmo_ipv6_change_notify);
 	EXIT();
 }
 
@@ -604,62 +526,57 @@
 	cds_ssr_unprotect(__func__);
 }
 
-/**
- * hdd_conf_hostoffload() - Central function to configure the supported offloads
- * @pAdapter:   pointer to the adapter
- * @fenable:    flag set to enable (1) or disable (0)
- *
- * Central function to configure the supported offloads either
- * enable or disable them.
- *
- * Return: nothing
- */
-void hdd_conf_hostoffload(hdd_adapter_t *pAdapter, bool fenable)
+void hdd_enable_host_offloads(hdd_adapter_t *adapter,
+	enum pmo_offload_trigger trigger)
 {
-	hdd_context_t *pHddCtx;
-
 	ENTER();
 
-	hdd_info("Configuring offloads with flag: %d", fenable);
-
-	/* Get the HDD context. */
-	pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
-
-	if (((QDF_STA_MODE != pAdapter->device_mode) &&
-	     (QDF_P2P_CLIENT_MODE != pAdapter->device_mode))) {
-		hdd_info("Offloads not supported in mode %d",
-			pAdapter->device_mode);
-		return;
+	if (!pmo_ucfg_is_vdev_supports_offload(adapter->hdd_vdev)) {
+		hdd_info("offload is not supported on this vdev opmode: %d",
+			 adapter->device_mode);
+		goto out;
 	}
 
-	if (eConnectionState_Associated !=
-	       (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState) {
-		hdd_info("Offloads not supported in state %d",
-			(WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->
-							conn_info.connState);
-		return;
+	if (!pmo_ucfg_is_vdev_connected(adapter->hdd_vdev)) {
+		hdd_info("vdev is not connected");
+		goto out;
 	}
 
-	hdd_conf_gtk_offload(pAdapter, fenable);
-
-	/* Configure ARP/NS offload during cfg80211 suspend/resume and
-	 * Enable MC address filtering during cfg80211 suspend
-	 * only if active mode offload is disabled
-	 */
-	if (!pHddCtx->config->active_mode_offload) {
-		hdd_info("configuring unconfigured active mode offloads");
-		hdd_conf_arp_offload(pAdapter, fenable);
-		wlan_hdd_set_mc_addr_list(pAdapter, fenable);
-
-		if (pHddCtx->config->fhostNSOffload &&
-		    pHddCtx->ns_offload_enable)
-			hdd_conf_ns_offload(pAdapter, fenable);
-	}
-
+	hdd_info("enable offloads");
+	hdd_conf_gtk_offload(adapter, true);
+	hdd_enable_arp_offload(adapter, trigger);
+	hdd_enable_ns_offload(adapter, trigger);
+	wlan_hdd_set_mc_addr_list(adapter, true);
+out:
 	EXIT();
-	return;
+
 }
-#endif
+
+void hdd_disable_host_offloads(hdd_adapter_t *adapter,
+	enum pmo_offload_trigger trigger)
+{
+	ENTER();
+
+	if (!pmo_ucfg_is_vdev_supports_offload(adapter->hdd_vdev)) {
+		hdd_info("offload is not supported on this vdev opmode: %d",
+				adapter->device_mode);
+			goto out;
+	}
+
+	if (!pmo_ucfg_is_vdev_connected(adapter->hdd_vdev)) {
+		hdd_info("vdev is not connected");
+		goto out;
+	}
+
+	hdd_info("disable offloads");
+	hdd_conf_gtk_offload(adapter, false);
+	hdd_disable_arp_offload(adapter, trigger);
+	hdd_disable_ns_offload(adapter, trigger);
+	wlan_hdd_set_mc_addr_list(adapter, false);
+out:
+	EXIT();
+
+}
 
 /**
  * hdd_lookup_ifaddr() - Lookup interface address data by name
@@ -806,42 +723,10 @@
 {
 	hdd_adapter_t *pAdapter =
 		container_of(work, hdd_adapter_t, ipv4NotifierWorkQueue);
-	hdd_context_t *pHddCtx;
-	hdd_station_ctx_t *sta_ctx;
-	int status;
-	bool ndi_connected;
-	bool sta_associated;
-
-	hdd_info("Configuring ARP Offload");
-
-	pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
-	status = wlan_hdd_validate_context(pHddCtx);
-	if (status)
-		return;
-
-	if (!pHddCtx->config->active_mode_offload) {
-		hdd_err("Active mode offload is disabled");
-		return;
-	}
-
-	ndi_connected = WLAN_HDD_IS_NDI(pAdapter) &&
-		WLAN_HDD_IS_NDI_CONNECTED(pAdapter);
-
-	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
-	sta_associated = sta_ctx->conn_info.connState ==
-		eConnectionState_Associated;
-
-	if (!ndi_connected && !sta_associated)
-		return;
-
-	/*
-	 * 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, true);
-
+	ENTER();
+	hdd_enable_arp_offload(pAdapter, pmo_ipv4_change_notify);
 	hdd_set_grat_arp_keepalive(pAdapter);
+	EXIT();
 }
 
 /**
@@ -944,84 +829,102 @@
 }
 
 /**
- * hdd_conf_arp_offload() - Configure ARP offload
+ * hdd_get_ipv4_local_interface() - get ipv4 local interafce from iface list
  * @pAdapter: Adapter context for which ARP offload is to be configured
- * @fenable: true : enable ARP offload false : disable arp offload
  *
  * Return:
- *	QDF_STATUS_SUCCESS - on successful operation,
- *	QDF_STATUS_E_FAILURE - on failure of operation
+ *	ifa - on successful operation,
+ *	NULL - on failure of operation
  */
-QDF_STATUS hdd_conf_arp_offload(hdd_adapter_t *pAdapter, bool fenable)
+static struct in_ifaddr *hdd_get_ipv4_local_interface(
+				hdd_adapter_t *pAdapter)
 {
-	struct in_ifaddr *ifa;
-	int i = 0;
-	tSirHostOffloadReq offLoadRequest;
-	hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
+	struct in_ifaddr **ifap = NULL;
+	struct in_ifaddr *ifa = NULL;
+	struct in_device *in_dev;
 
-	hdd_info("fenable = %d", fenable);
-
-	/* In SAP/P2P Go mode, ARP/NS Offload feature capability
-	 * is controlled by one bit.
-	 */
-	if ((QDF_SAP_MODE == pAdapter->device_mode ||
-	     QDF_P2P_GO_MODE == pAdapter->device_mode) &&
-	    !pHddCtx->ap_arpns_support) {
-		hdd_notice("ARP Offload is not supported in SAP/P2PGO mode");
-		return QDF_STATUS_SUCCESS;
-	}
-
-	if (fenable) {
-		ifa = hdd_lookup_ifaddr(pAdapter);
-		if (ifa && ifa->ifa_local) {
-			offLoadRequest.offloadType = SIR_IPV4_ARP_REPLY_OFFLOAD;
-			offLoadRequest.enableOrDisable = SIR_OFFLOAD_ENABLE;
-			hdd_wlan_offload_event(SIR_IPV4_ARP_REPLY_OFFLOAD,
-					       SIR_OFFLOAD_ENABLE);
-
-			hdd_notice("Enable ARP offload: filter programmed = %d",
-			       offLoadRequest.enableOrDisable);
-
-			/* converting u32 to IPV4 address */
-			for (i = 0; i < 4; i++) {
-				offLoadRequest.params.hostIpv4Addr[i] =
-					(ifa->ifa_local >> (i * 8)) & 0xFF;
+	in_dev = __in_dev_get_rtnl(pAdapter->dev);
+	if (in_dev) {
+		for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
+			     ifap = &ifa->ifa_next) {
+			if (!strcmp(pAdapter->dev->name, ifa->ifa_label)) {
+				/* if match break */
+				return ifa;
 			}
-			hdd_notice(" Enable SME HostOffload: %d.%d.%d.%d",
-			       offLoadRequest.params.hostIpv4Addr[0],
-			       offLoadRequest.params.hostIpv4Addr[1],
-			       offLoadRequest.params.hostIpv4Addr[2],
-			       offLoadRequest.params.hostIpv4Addr[3]);
-
-			if (QDF_STATUS_SUCCESS !=
-			    sme_set_host_offload(WLAN_HDD_GET_HAL_CTX(pAdapter),
-						 pAdapter->sessionId,
-						 &offLoadRequest)) {
-				hdd_err("Failed to enable HostOffload feature");
-				return QDF_STATUS_E_FAILURE;
-			}
-		} else {
-			hdd_notice("IP Address is not assigned");
 		}
+	}
+	ifa = NULL;
 
-		return QDF_STATUS_SUCCESS;
+	return ifa;
+}
+
+void hdd_enable_arp_offload(hdd_adapter_t *adapter,
+		enum pmo_offload_trigger trigger)
+{
+	hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
+	QDF_STATUS status;
+	struct pmo_arp_req *arp_req = NULL;
+	struct in_ifaddr *ifa = NULL;
+
+	ENTER();
+	arp_req = qdf_mem_malloc(sizeof(*arp_req));
+	if (!arp_req) {
+		hdd_err("cannot allocate arp_req");
+		goto out;
 	}
 
-	hdd_wlan_offload_event(SIR_IPV4_ARP_REPLY_OFFLOAD,
-			       SIR_OFFLOAD_DISABLE);
-	qdf_mem_zero((void *)&offLoadRequest,
-		     sizeof(tSirHostOffloadReq));
-	offLoadRequest.enableOrDisable = SIR_OFFLOAD_DISABLE;
-	offLoadRequest.offloadType = SIR_IPV4_ARP_REPLY_OFFLOAD;
+	arp_req->psoc = psoc;
+	arp_req->vdev_id = adapter->sessionId;
+	arp_req->trigger = trigger;
 
-	if (QDF_STATUS_SUCCESS !=
-	    sme_set_host_offload(WLAN_HDD_GET_HAL_CTX(pAdapter),
-				 pAdapter->sessionId, &offLoadRequest)) {
-		hdd_err("Failure to disable host offload feature");
-		return QDF_STATUS_E_FAILURE;
+	ifa = hdd_get_ipv4_local_interface(adapter);
+	if (ifa && ifa->ifa_local) {
+		arp_req->ipv4_addr = (uint32_t)ifa->ifa_local;
+	status = pmo_ucfg_cache_arp_offload_req(arp_req);
+	if (status == QDF_STATUS_SUCCESS) {
+		status = pmo_ucfg_enable_arp_offload_in_fwr(
+				adapter->hdd_vdev, trigger);
+		if (status == QDF_STATUS_SUCCESS)
+			hdd_wlan_offload_event(
+				PMO_IPV4_ARP_REPLY_OFFLOAD,
+				PMO_OFFLOAD_ENABLE);
+		else
+			hdd_info("fail to enable arp offload in fwr");
+	} else
+		hdd_info("fail to cache arp offload request");
+	} else {
+		hdd_notice("IP Address is not assigned");
+		status = QDF_STATUS_NOT_INITIALIZED;
+	}
+out:
+	if (arp_req)
+		qdf_mem_free(arp_req);
+	EXIT();
+
+}
+
+void hdd_disable_arp_offload(hdd_adapter_t *adapter,
+		enum pmo_offload_trigger trigger)
+{
+	QDF_STATUS status;
+
+	ENTER();
+	status = pmo_ucfg_flush_arp_offload_req(adapter->hdd_vdev);
+	if (status != QDF_STATUS_SUCCESS) {
+		hdd_err("Failed to flush arp Offload");
+		goto out;
 	}
 
-	return QDF_STATUS_SUCCESS;
+	status = pmo_ucfg_disable_arp_offload_in_fwr(adapter->hdd_vdev, trigger);
+	if (status == QDF_STATUS_SUCCESS)
+		hdd_wlan_offload_event(PMO_IPV4_ARP_REPLY_OFFLOAD,
+			PMO_OFFLOAD_DISABLE);
+	else
+		hdd_info("fail to disable arp offload");
+out:
+	EXIT();
+
 }
 
 #ifdef WLAN_FEATURE_PACKET_FILTERING
@@ -1175,7 +1078,7 @@
 
 	hdd_notice("send wlan resume indication");
 	/* Disable supported OffLoads */
-	hdd_conf_hostoffload(pAdapter, false);
+	hdd_disable_host_offloads(pAdapter, pmo_apps_resume);
 }
 
 /**
@@ -1216,7 +1119,6 @@
 	hdd_adapter_t *pAdapter = NULL;
 	hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
 	uint32_t conn_state_mask = 0;
-
 	hdd_info("WLAN being suspended by OS");
 
 	pHddCtx = cds_get_context(QDF_MODULE_ID_HDD);
@@ -1241,8 +1143,7 @@
 					   WLAN_CONTROL_PATH);
 
 		/* Configure supported OffLoads */
-		hdd_conf_hostoffload(pAdapter, true);
-
+		hdd_enable_host_offloads(pAdapter, pmo_apps_suspend);
 		hdd_update_conn_state_mask(pAdapter, &conn_state_mask);
 
 		status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
@@ -2130,7 +2031,6 @@
 {
 	hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
 	hdd_context_t *pHddCtx;
-	QDF_STATUS qdf_status;
 	int status;
 
 	ENTER();
@@ -2169,20 +2069,6 @@
 	}
 	mutex_unlock(&pHddCtx->iface_change_lock);
 
-	if (allow_power_save &&
-	    pHddCtx->hdd_wlan_suspended &&
-	    pHddCtx->config->fhostArpOffload &&
-	    (eConnectionState_Associated ==
-	     (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState)) {
-		hdd_notice("offload: in cfg80211_set_power_mgmt, "
-			"calling arp offload");
-		qdf_status = hdd_conf_arp_offload(pAdapter, true);
-		if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
-			hdd_notice("Failed to enable ARPOFFLOAD Feature %d",
-				qdf_status);
-		}
-	}
-
 	status = wlan_hdd_set_powersave(pAdapter, allow_power_save, timeout);
 
 	allow_power_save ? hdd_stop_dhcp_ind(pAdapter) :
diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c
index 279b0c9..484ed86 100644
--- a/core/hdd/src/wlan_hdd_wext.c
+++ b/core/hdd/src/wlan_hdd_wext.c
@@ -10836,8 +10836,7 @@
 		"Configure broadcast filtering via ini item, 'g_enable_non_arp_bc_hw_filter.'\n"
 		"\tg_enable_non_arp_bc_hw_filter=1 # drop all non-ARP broadcast traffic\n"
 		"\tg_enable_non_arp_bc_hw_filter=0 # allow all broadcast traffic");
-
-	return -EINVAL;
+	 return -EINVAL;
 }
 
 /**