Browse Source

qcacld-3.0: Add vendor attribute to configure ARP/NS offload

In some scenario, it is required to receive every ARP/NS packet even
it is not to solicit address itself. So add this vendor attribute
configuration to enable/disable ARP/NS offload on fly.

On some platform, if target suspend to WoW mode, APF filter will drop
such ARP/NS packet in the front, so prevent runtime suspend happen
if disable ARP/NS offload. System suspend still allow in consideration
of potential power impact.

It only support on STA/P2P-Client mode device, and this configure is
optional, while default behavior is ARP/NS offload enable. It will
restore to default behavior if interface being closed.

Change-Id: Icd49e230024bc1ce51519cd9fafee9bc9f79f382
CRs-Fixed: 3058494
Will Huang 3 years ago
parent
commit
eb218a1c61

+ 1 - 0
Kbuild

@@ -2901,6 +2901,7 @@ cppflags-$(CONFIG_FEATURE_WLAN_SCAN_PNO) += -DFEATURE_WLAN_SCAN_PNO
 cppflags-$(CONFIG_WLAN_FEATURE_PACKET_FILTERING) += -DWLAN_FEATURE_PACKET_FILTERING
 cppflags-$(CONFIG_DHCP_SERVER_OFFLOAD) += -DDHCP_SERVER_OFFLOAD
 cppflags-$(CONFIG_WLAN_NS_OFFLOAD) += -DWLAN_NS_OFFLOAD
+cppflags-$(CONFIG_WLAN_DYNAMIC_ARP_NS_OFFLOAD) += -DFEATURE_WLAN_DYNAMIC_ARP_NS_OFFLOAD
 cppflags-$(CONFIG_WLAN_FEATURE_ICMP_OFFLOAD) += -DWLAN_FEATURE_ICMP_OFFLOAD
 cppflags-$(CONFIG_FEATURE_WLAN_RA_FILTERING) += -DFEATURE_WLAN_RA_FILTERING
 cppflags-$(CONFIG_FEATURE_WLAN_LPHB) += -DFEATURE_WLAN_LPHB

+ 7 - 0
components/pmo/core/inc/wlan_pmo_priv.h

@@ -112,6 +112,9 @@ struct wlan_pmo_ctx {
  * @dyn_listen_interval: dynamically user configured listen interval
  * @restore_dtim_setting: DTIM settings restore flag
  * @pmo_vdev_lock: spin lock for pmo vdev priv ctx
+ * @dyn_arp_ns_offload_disable: true when arp/ns offload is disable
+ * @dyn_arp_ns_offload_rt_lock: wake lock which prevent runtime pm happen if
+ *                              arp/ns offload is disable
  */
 struct pmo_vdev_priv_obj {
 	struct pmo_psoc_priv_obj *pmo_psoc_ctx;
@@ -136,6 +139,10 @@ struct pmo_vdev_priv_obj {
 	uint32_t dyn_listen_interval;
 	bool restore_dtim_setting;
 	qdf_spinlock_t pmo_vdev_lock;
+#ifdef FEATURE_WLAN_DYNAMIC_ARP_NS_OFFLOAD
+	bool dyn_arp_ns_offload_disable;
+	qdf_runtime_lock_t dyn_arp_ns_offload_rt_lock;
+#endif
 };
 
 #endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */

+ 106 - 0
components/pmo/core/inc/wlan_pmo_suspend_resume.h

@@ -179,6 +179,112 @@ bool pmo_core_vdev_get_restore_dtim(struct wlan_objmgr_vdev *vdev)
 	return value;
 }
 
+#ifdef FEATURE_WLAN_DYNAMIC_ARP_NS_OFFLOAD
+/**
+ * pmo_core_dynamic_arp_ns_offload_enable() - Enable vdev arp/ns offload
+ * @vdev: objmgr vdev handle
+ *
+ * Return: QDF_STATUS_E_ALREADY if arp/ns offload already enable
+ */
+static inline QDF_STATUS
+pmo_core_dynamic_arp_ns_offload_enable(struct wlan_objmgr_vdev *vdev)
+{
+	bool value;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	vdev_ctx = pmo_vdev_get_priv(vdev);
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	value = vdev_ctx->dyn_arp_ns_offload_disable;
+	if (!value)
+		status = QDF_STATUS_E_ALREADY;
+	else
+		vdev_ctx->dyn_arp_ns_offload_disable = false;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+
+	return status;
+}
+
+/**
+ * pmo_core_dynamic_arp_ns_offload_disable() - Disable vdev arp/ns offload
+ * @vdev: objmgr vdev handle
+ *
+ * Return: QDF_STATUS_E_ALREADY if arp/ns offload already disable
+ */
+static inline QDF_STATUS
+pmo_core_dynamic_arp_ns_offload_disable(struct wlan_objmgr_vdev *vdev)
+{
+	bool value;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	vdev_ctx = pmo_vdev_get_priv(vdev);
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	value = vdev_ctx->dyn_arp_ns_offload_disable;
+	if (value)
+		status = QDF_STATUS_E_ALREADY;
+	else
+		vdev_ctx->dyn_arp_ns_offload_disable = true;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+
+	return status;
+}
+
+/**
+ * pmo_core_get_dynamic_arp_ns_offload_disable() - Get arp/ns offload state
+ * @vdev: objmgr vdev handle
+ *
+ * Return: true if vdev arp/ns offload is disable
+ */
+static inline bool
+pmo_core_get_dynamic_arp_ns_offload_disable(struct wlan_objmgr_vdev *vdev)
+{
+	bool value;
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	vdev_ctx = pmo_vdev_get_priv(vdev);
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	value = vdev_ctx->dyn_arp_ns_offload_disable;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+
+	return value;
+}
+
+/**
+ * pmo_core_dynamic_arp_ns_offload_runtime_prevent() - Prevent runtime suspend
+ * @vdev: objmgr vdev handle
+ *
+ * API to prevent runtime suspend happen when arp/ns offload is disable
+ *
+ * Return: None
+ */
+static inline void
+pmo_core_dynamic_arp_ns_offload_runtime_prevent(struct wlan_objmgr_vdev *vdev)
+{
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	vdev_ctx = pmo_vdev_get_priv(vdev);
+	qdf_runtime_pm_prevent_suspend(&vdev_ctx->dyn_arp_ns_offload_rt_lock);
+}
+
+/**
+ * pmo_core_dynamic_arp_ns_offload_runtime_allow() - Allow runtime suspend
+ * @vdev: objmgr vdev handle
+ *
+ * API to allow runtime suspend happen when arp/ns offload is enable
+ *
+ * Return: None
+ */
+static inline void
+pmo_core_dynamic_arp_ns_offload_runtime_allow(struct wlan_objmgr_vdev *vdev)
+{
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	vdev_ctx = pmo_vdev_get_priv(vdev);
+	qdf_runtime_pm_allow_suspend(&vdev_ctx->dyn_arp_ns_offload_rt_lock);
+}
+#endif
+
 /**
  * pmo_core_update_power_save_mode() - update power save mode
  * @vdev: objmgr vdev handle

+ 3 - 1
components/pmo/core/src/wlan_pmo_arp.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -128,6 +128,7 @@ pmo_core_do_enable_arp_offload(struct wlan_objmgr_vdev *vdev,
 		status = pmo_tgt_enable_arp_offload_req(vdev, vdev_id);
 		break;
 	case pmo_apps_suspend:
+	case pmo_arp_ns_offload_dynamic_update:
 		/* enable arp when active offload is false (apps suspend) */
 		status = pmo_tgt_enable_arp_offload_req(vdev, vdev_id);
 		break;
@@ -161,6 +162,7 @@ static QDF_STATUS pmo_core_do_disable_arp_offload(struct wlan_objmgr_vdev *vdev,
 
 	switch (trigger) {
 	case pmo_apps_resume:
+	case pmo_arp_ns_offload_dynamic_update:
 		/* disable arp on apps resume when active offload is disable */
 		status = pmo_tgt_disable_arp_offload_req(vdev, vdev_id);
 		break;

+ 2 - 0
components/pmo/core/src/wlan_pmo_ns.c

@@ -169,6 +169,7 @@ static QDF_STATUS pmo_core_do_enable_ns_offload(struct wlan_objmgr_vdev *vdev,
 		status = pmo_tgt_enable_ns_offload_req(vdev, vdev_id);
 		break;
 	case pmo_apps_suspend:
+	case pmo_arp_ns_offload_dynamic_update:
 		/* enable arp when active offload is false (apps suspend) */
 		status = pmo_tgt_enable_ns_offload_req(vdev, vdev_id);
 		break;
@@ -204,6 +205,7 @@ static QDF_STATUS pmo_core_do_disable_ns_offload(struct wlan_objmgr_vdev *vdev,
 		status = pmo_tgt_disable_ns_offload_req(vdev, vdev_id);
 		break;
 	case pmo_apps_resume:
+	case pmo_arp_ns_offload_dynamic_update:
 		status = pmo_tgt_disable_ns_offload_req(vdev, vdev_id);
 		break;
 	default:

+ 2 - 0
components/pmo/dispatcher/inc/wlan_pmo_common_public_struct.h

@@ -220,6 +220,7 @@ typedef QDF_STATUS(*pmo_psoc_resume_handler)
  * @pmo_ns_offload_dynamic_update: enable/disable ns offload on the fly
  * @pmo_peer_disconnect: trigger is peer disconnect
  * @pmo_mcbc_setting_dynamic_update: mcbc value update on the fly
+ * @pmo_arp_ns_offload_dynamic_update: enable/disable arp/ns offload on the fly
  *
  * @pmo_offload_trigger_max: Max trigger value
  */
@@ -234,6 +235,7 @@ enum pmo_offload_trigger {
 	pmo_ns_offload_dynamic_update,
 	pmo_peer_disconnect,
 	pmo_mcbc_setting_dynamic_update,
+	pmo_arp_ns_offload_dynamic_update,
 
 	pmo_offload_trigger_max,
 };

+ 73 - 0
components/pmo/dispatcher/inc/wlan_pmo_ucfg_api.h

@@ -545,6 +545,79 @@ ucfg_pmo_enhanced_mc_filter_disable(struct wlan_objmgr_vdev *vdev)
 	return pmo_core_enhanced_mc_filter_disable(vdev);
 }
 
+#ifdef FEATURE_WLAN_DYNAMIC_ARP_NS_OFFLOAD
+/**
+ * ucfg_pmo_dynamic_arp_ns_offload_enable() - enable arp/ns offload
+ * @vdev: vdev objmgr handle
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+ucfg_pmo_dynamic_arp_ns_offload_enable(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * ucfg_pmo_dynamic_arp_ns_offload_disable() - disable arp/ns offload
+ * @vdev: vdev objmgr handle
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+ucfg_pmo_dynamic_arp_ns_offload_disable(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * ucfg_pmo_get_arp_ns_offload_dynamic_disable() - get arp/ns offload state
+ * @vdev: vdev objmgr handle
+ *
+ * Return: QDF_STATUS
+ */
+bool
+ucfg_pmo_get_arp_ns_offload_dynamic_disable(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * ucfg_pmo_dynamic_arp_ns_offload_runtime_prevent() - prevent runtime suspend
+ * @vdev: vdev objmgr handle
+ *
+ * Return: none
+ */
+void
+ucfg_pmo_dynamic_arp_ns_offload_runtime_prevent(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * ucfg_pmo_dynamic_arp_ns_offload_runtime_allow() - allow runtime suspend
+ * @vdev: vdev objmgr handle
+ *
+ * Return: none
+ */
+void
+ucfg_pmo_dynamic_arp_ns_offload_runtime_allow(struct wlan_objmgr_vdev *vdev);
+#else
+static inline QDF_STATUS
+ucfg_pmo_dynamic_arp_ns_offload_enable(struct wlan_objmgr_vdev *vdev)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline QDF_STATUS
+ucfg_pmo_dynamic_arp_ns_offload_disable(struct wlan_objmgr_vdev *vdev)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline bool
+ucfg_pmo_get_arp_ns_offload_dynamic_disable(struct wlan_objmgr_vdev *vdev)
+{
+	return false;
+}
+
+static inline void
+ucfg_pmo_dynamic_arp_ns_offload_runtime_prevent(struct wlan_objmgr_vdev *vdev)
+{
+}
+
+static inline void
+ucfg_pmo_dynamic_arp_ns_offload_runtime_allow(struct wlan_objmgr_vdev *vdev) {}
+#endif
+
 /**
  * ucfg_pmo_enable_mc_addr_filtering_in_fwr(): Enable cached mc add list in fwr
  * @psoc: objmgr psoc handle

+ 22 - 0
components/pmo/dispatcher/src/wlan_pmo_obj_mgmt_api.c

@@ -227,6 +227,26 @@ out:
 	return status;
 }
 
+#ifdef FEATURE_WLAN_DYNAMIC_ARP_NS_OFFLOAD
+static inline void
+pmo_vdev_dynamic_arp_ns_offload_init(struct pmo_vdev_priv_obj *vdev_ctx)
+{
+	qdf_runtime_lock_init(&vdev_ctx->dyn_arp_ns_offload_rt_lock);
+}
+
+static inline void
+pmo_vdev_dynamic_arp_ns_offload_deinit(struct pmo_vdev_priv_obj *vdev_ctx)
+{
+	qdf_runtime_lock_deinit(&vdev_ctx->dyn_arp_ns_offload_rt_lock);
+}
+#else
+static inline void
+pmo_vdev_dynamic_arp_ns_offload_init(struct pmo_vdev_priv_obj *vdev_ctx) {}
+
+static inline void
+pmo_vdev_dynamic_arp_ns_offload_deinit(struct pmo_vdev_priv_obj *vdev_ctx) {}
+#endif
+
 QDF_STATUS pmo_vdev_object_created_notification(
 		struct wlan_objmgr_vdev *vdev, void *arg)
 {
@@ -263,6 +283,7 @@ QDF_STATUS pmo_vdev_object_created_notification(
 		psoc_ctx->psoc_cfg.ptrn_match_enable_all_vdev;
 	vdev_ctx->pmo_psoc_ctx = psoc_ctx;
 	qdf_atomic_init(&vdev_ctx->gtk_err_enable);
+	pmo_vdev_dynamic_arp_ns_offload_init(vdev_ctx);
 
 out:
 	pmo_exit();
@@ -308,6 +329,7 @@ QDF_STATUS pmo_vdev_object_destroyed_notification(
 		pmo_err("Failed to detach vdev_ctx with vdev");
 
 	qdf_spinlock_destroy(&vdev_ctx->pmo_vdev_lock);
+	pmo_vdev_dynamic_arp_ns_offload_deinit(vdev_ctx);
 	qdf_mem_free(vdev_ctx);
 
 	return status;

+ 32 - 0
components/pmo/dispatcher/src/wlan_pmo_ucfg_api.c

@@ -196,6 +196,38 @@ ucfg_pmo_disable_ns_offload_in_fwr(struct wlan_objmgr_vdev *vdev,
 }
 #endif /* WLAN_NS_OFFLOAD */
 
+#ifdef FEATURE_WLAN_DYNAMIC_ARP_NS_OFFLOAD
+QDF_STATUS
+ucfg_pmo_dynamic_arp_ns_offload_enable(struct wlan_objmgr_vdev *vdev)
+{
+	return pmo_core_dynamic_arp_ns_offload_enable(vdev);
+}
+
+QDF_STATUS
+ucfg_pmo_dynamic_arp_ns_offload_disable(struct wlan_objmgr_vdev *vdev)
+{
+	return pmo_core_dynamic_arp_ns_offload_disable(vdev);
+}
+
+bool
+ucfg_pmo_get_arp_ns_offload_dynamic_disable(struct wlan_objmgr_vdev *vdev)
+{
+	return pmo_core_get_dynamic_arp_ns_offload_disable(vdev);
+}
+
+void
+ucfg_pmo_dynamic_arp_ns_offload_runtime_prevent(struct wlan_objmgr_vdev *vdev)
+{
+	return pmo_core_dynamic_arp_ns_offload_runtime_prevent(vdev);
+}
+
+void
+ucfg_pmo_dynamic_arp_ns_offload_runtime_allow(struct wlan_objmgr_vdev *vdev)
+{
+	return pmo_core_dynamic_arp_ns_offload_runtime_allow(vdev);
+}
+#endif
+
 QDF_STATUS
 ucfg_pmo_get_ns_offload_params(struct wlan_objmgr_vdev *vdev,
 			       struct pmo_ns_offload_params *params)

+ 102 - 0
core/hdd/src/wlan_hdd_cfg80211.c

@@ -7036,6 +7036,7 @@ const struct nla_policy wlan_hdd_wifi_config_policy[
 	[QCA_WLAN_VENDOR_ATTR_CONFIG_CONCURRENT_STA_PRIMARY] = {
 							.type = NLA_U8 },
 	[QCA_WLAN_VENDOR_ATTR_CONFIG_FT_OVER_DS] = {.type = NLA_U8 },
+	[QCA_WLAN_VENDOR_ATTR_CONFIG_ARP_NS_OFFLOAD] = {.type = NLA_U8 },
 };
 
 static const struct nla_policy
@@ -8975,6 +8976,103 @@ static int hdd_set_nss(struct hdd_adapter *adapter,
 	return ret;
 }
 
+#ifdef FEATURE_WLAN_DYNAMIC_ARP_NS_OFFLOAD
+#define DYNAMIC_ARP_NS_ENABLE    1
+#define DYNAMIC_ARP_NS_DISABLE   0
+
+/**
+ * hdd_set_arp_ns_offload() - enable/disable arp/ns offload feature
+ * @adapter: hdd adapter
+ * @attr: pointer to nla attr
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+static int hdd_set_arp_ns_offload(struct hdd_adapter *adapter,
+				  const struct nlattr *attr)
+{
+	uint8_t offload_state;
+	int errno;
+	QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
+	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	struct wlan_objmgr_vdev *vdev;
+
+	errno = wlan_hdd_validate_context(hdd_ctx);
+	if (errno)
+		return errno;
+
+	if (!ucfg_pmo_is_arp_offload_enabled(hdd_ctx->psoc) ||
+	    !ucfg_pmo_is_ns_offloaded(hdd_ctx->psoc)) {
+		hdd_err_rl("ARP/NS Offload is disabled by ini");
+		return -EINVAL;
+	}
+
+	if (!ucfg_pmo_is_active_mode_offloaded(hdd_ctx->psoc)) {
+		hdd_err_rl("active mode offload is disabled by ini");
+		return -EINVAL;
+	}
+
+	if (adapter->device_mode != QDF_STA_MODE &&
+	    adapter->device_mode != QDF_P2P_CLIENT_MODE) {
+		hdd_err_rl("only support on sta/p2p-cli mode");
+		return -EINVAL;
+	}
+
+	vdev = hdd_objmgr_get_vdev_by_user(adapter, WLAN_OSIF_ID);
+	if (!vdev) {
+		hdd_err("vdev is NULL");
+		return -EINVAL;
+	}
+
+	offload_state = nla_get_u8(attr);
+
+	if (offload_state == DYNAMIC_ARP_NS_ENABLE)
+		qdf_status = ucfg_pmo_dynamic_arp_ns_offload_enable(vdev);
+	else if (offload_state == DYNAMIC_ARP_NS_DISABLE)
+		qdf_status = ucfg_pmo_dynamic_arp_ns_offload_disable(vdev);
+
+	if (QDF_IS_STATUS_SUCCESS(qdf_status)) {
+		if (offload_state == DYNAMIC_ARP_NS_ENABLE)
+			ucfg_pmo_dynamic_arp_ns_offload_runtime_allow(vdev);
+		else
+			ucfg_pmo_dynamic_arp_ns_offload_runtime_prevent(vdev);
+	}
+
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+
+	if (QDF_IS_STATUS_ERROR(qdf_status)) {
+		if (qdf_status == QDF_STATUS_E_ALREADY) {
+			hdd_info_rl("already set arp/ns offload %d",
+				    offload_state);
+			return 0;
+		}
+		return qdf_status_to_os_return(qdf_status);
+	}
+
+	if (!hdd_is_vdev_in_conn_state(adapter)) {
+		hdd_info("set not in connect state, updated state %d",
+			 offload_state);
+		return 0;
+	}
+
+	if (offload_state == DYNAMIC_ARP_NS_ENABLE) {
+		hdd_enable_arp_offload(adapter,
+				       pmo_arp_ns_offload_dynamic_update);
+		hdd_enable_ns_offload(adapter,
+				      pmo_arp_ns_offload_dynamic_update);
+	} else if (offload_state == DYNAMIC_ARP_NS_DISABLE) {
+		hdd_disable_arp_offload(adapter,
+					pmo_arp_ns_offload_dynamic_update);
+		hdd_disable_ns_offload(adapter,
+				       pmo_arp_ns_offload_dynamic_update);
+	}
+
+	return 0;
+}
+
+#undef DYNAMIC_ARP_NS_ENABLE
+#undef DYNAMIC_ARP_NS_DISABLE
+#endif
+
 /**
  * typedef independent_setter_fn - independent attribute handler
  * @adapter: The adapter being configured
@@ -9089,6 +9187,10 @@ static const struct independent_setters independent_setters[] = {
 	 hdd_set_primary_interface},
 	{QCA_WLAN_VENDOR_ATTR_CONFIG_FT_OVER_DS,
 	 hdd_set_ft_over_ds},
+#ifdef FEATURE_WLAN_DYNAMIC_ARP_NS_OFFLOAD
+	{QCA_WLAN_VENDOR_ATTR_CONFIG_ARP_NS_OFFLOAD,
+	 hdd_set_arp_ns_offload},
+#endif
 };
 
 #ifdef WLAN_FEATURE_ELNA

+ 24 - 9
core/hdd/src/wlan_hdd_power.c

@@ -571,11 +571,23 @@ void hdd_enable_ns_offload(struct hdd_adapter *adapter,
 	ns_req->trigger = trigger;
 	ns_req->count = 0;
 
+	vdev = hdd_objmgr_get_vdev_by_user(adapter, WLAN_OSIF_POWER_ID);
+	if (!vdev) {
+		hdd_err("vdev is NULL");
+		goto free_req;
+	}
+
 	/* check if offload cache and send is required or not */
 	status = ucfg_pmo_ns_offload_check(psoc, trigger, adapter->vdev_id);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		hdd_debug("NS offload is not required");
-		goto free_req;
+		goto put_vdev;
+	}
+
+	if (ucfg_pmo_get_arp_ns_offload_dynamic_disable(vdev)) {
+		hdd_debug("Dynamic arp ns offload disabled");
+		ucfg_pmo_flush_ns_offload_req(vdev);
+		goto skip_cache_ns;
 	}
 
 	/* Unicast Addresses */
@@ -585,7 +597,7 @@ void hdd_enable_ns_offload(struct hdd_adapter *adapter,
 	if (errno) {
 		hdd_disable_ns_offload(adapter, trigger);
 		hdd_debug("Max supported addresses: disabling NS offload");
-		goto free_req;
+		goto put_vdev;
 	}
 
 	/* Anycast Addresses */
@@ -595,21 +607,17 @@ void hdd_enable_ns_offload(struct hdd_adapter *adapter,
 	if (errno) {
 		hdd_disable_ns_offload(adapter, trigger);
 		hdd_debug("Max supported addresses: disabling NS offload");
-		goto free_req;
+		goto put_vdev;
 	}
 
 	/* cache ns request */
 	status = ucfg_pmo_cache_ns_offload_req(ns_req);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		hdd_debug("Failed to cache ns request; status:%d", status);
-		goto free_req;
+		goto put_vdev;
 	}
 
-	vdev = hdd_objmgr_get_vdev_by_user(adapter, WLAN_OSIF_POWER_ID);
-	if (!vdev) {
-		hdd_err("vdev is NULL");
-		goto free_req;
-	}
+skip_cache_ns:
 	/* enable ns request */
 	status = ucfg_pmo_enable_ns_offload_in_fwr(vdev, trigger);
 	if (QDF_IS_STATUS_ERROR(status)) {
@@ -1313,6 +1321,12 @@ void hdd_enable_arp_offload(struct hdd_adapter *adapter,
 		goto put_vdev;
 	}
 
+	if (ucfg_pmo_get_arp_ns_offload_dynamic_disable(vdev)) {
+		hdd_debug("Dynamic arp ns offload disabled");
+		ucfg_pmo_flush_arp_offload_req(vdev);
+		goto skip_cache_arp;
+	}
+
 	ifa = hdd_get_ipv4_local_interface(adapter);
 	if (!ifa || !ifa->ifa_local) {
 		hdd_info("IP Address is not assigned");
@@ -1328,6 +1342,7 @@ void hdd_enable_arp_offload(struct hdd_adapter *adapter,
 		goto put_vdev;
 	}
 
+skip_cache_arp:
 	status = ucfg_pmo_enable_arp_offload_in_fwr(vdev, trigger);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		hdd_err("failed arp offload config in fw; status:%d", status);