Browse Source

qcacld-3.0: Add debugfs support for offload info

Add debugfs entry to get offload info (mc addr list, arp, ns etc.,)
for STA interface.

Change-Id: I8bf4491929b5ef04ed5ce19f4b0030945f0eb0c0
CRs-Fixed: 2203786
Rajeev Kumar Sirasanagandla 7 years ago
parent
commit
85f8b02175

+ 1 - 0
Kbuild

@@ -72,6 +72,7 @@ ifeq ($(CONFIG_WLAN_FEATURE_LINK_LAYER_STATS), y)
 HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_llstat.o
 HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_csr.o
 HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_connect.o
+HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_offload.o
 endif
 endif
 

+ 11 - 0
components/pmo/core/inc/wlan_pmo_arp.h

@@ -70,6 +70,17 @@ QDF_STATUS pmo_core_enable_arp_offload_in_fwr(struct wlan_objmgr_vdev *vdev,
 QDF_STATUS pmo_core_disable_arp_offload_in_fwr(struct wlan_objmgr_vdev *vdev,
 		enum pmo_offload_trigger trigger);
 
+/**
+ * pmo_core_get_arp_offload_params() - API to get arp offload params
+ * @vdev: objmgr vdev
+ * @params: output pointer to hold offload params
+ *
+ * Return: QDF_STATUS_SUCCESS in case of success else return error
+ */
+QDF_STATUS
+pmo_core_get_arp_offload_params(struct wlan_objmgr_vdev *vdev,
+				struct pmo_arp_offload_params *params);
+
 #endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */
 
 #endif /* end  of _WLAN_PMO_ARP_H_ */

+ 13 - 0
components/pmo/core/inc/wlan_pmo_mc_addr_filtering.h

@@ -144,6 +144,19 @@ int pmo_core_get_mc_addr_list_count(struct wlan_objmgr_psoc *psoc,
  */
 uint8_t pmo_core_max_mc_addr_supported(struct wlan_objmgr_psoc *psoc);
 
+/**
+ * pmo_core_get_mc_addr_list() - Get mc addr list configured
+ * @psoc: objmgr psoc
+ * @vdev_id: vdev identifier
+ * @mc_list_req: output pointer to hold mc addr list params
+ *
+ * Return: QDF_STATUS_SUCCESS in case of success else return error
+ */
+QDF_STATUS
+pmo_core_get_mc_addr_list(struct wlan_objmgr_psoc *psoc,
+			  uint8_t vdev_id,
+			  struct pmo_mc_addr_list *mc_list_req);
+
 #endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */
 
 #endif /* end  of _WLAN_PMO_MC_ADDR_FILTERING_H_ */

+ 11 - 0
components/pmo/core/inc/wlan_pmo_ns.h

@@ -71,6 +71,17 @@ QDF_STATUS pmo_core_enable_ns_offload_in_fwr(struct wlan_objmgr_vdev *vdev,
 QDF_STATUS pmo_core_disable_ns_offload_in_fwr(struct wlan_objmgr_vdev *vdev,
 		enum pmo_offload_trigger trigger);
 
+/**
+ * pmo_core_get_ns_offload_params() - API to get ns offload params
+ * @vdev: objmgr vdev
+ * @params: output pointer to hold offload params
+ *
+ * Return: QDF_STATUS_SUCCESS in case of success else return error
+ */
+QDF_STATUS
+pmo_core_get_ns_offload_params(struct wlan_objmgr_vdev *vdev,
+			       struct pmo_ns_offload_params *params);
+
 #endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */
 
 #endif /* end  of _WLAN_PMO_NS_H_ */

+ 44 - 0
components/pmo/core/src/wlan_pmo_arp.c

@@ -56,6 +56,7 @@ static QDF_STATUS pmo_core_cache_arp_in_vdev_priv(
 		peer_bssid.bytes);
 
 	request->enable = PMO_OFFLOAD_ENABLE;
+	request->is_offload_applied = false;
 	/* converting u32 to IPV4 address */
 	for (index = 0; index < PMO_IPV4_ADDR_LEN; index++)
 		request->host_ipv4_addr[index] =
@@ -93,6 +94,7 @@ static QDF_STATUS pmo_core_flush_arp_from_vdev_priv(
 	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
 	qdf_mem_zero(&vdev_ctx->vdev_arp_req, sizeof(vdev_ctx->vdev_arp_req));
 	vdev_ctx->vdev_arp_req.enable = PMO_OFFLOAD_DISABLE;
+	vdev_ctx->vdev_arp_req.is_offload_applied = false;
 	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
 
 	pmo_exit();
@@ -366,3 +368,45 @@ out:
 	return status;
 }
 
+QDF_STATUS
+pmo_core_get_arp_offload_params(struct wlan_objmgr_vdev *vdev,
+				struct pmo_arp_offload_params *params)
+{
+	QDF_STATUS status;
+	struct pmo_vdev_priv_obj *vdev_ctx;
+	uint8_t vdev_id;
+
+	pmo_enter();
+
+	if (!params)
+		return QDF_STATUS_E_INVAL;
+
+	qdf_mem_zero(params, sizeof(*params));
+
+	if (!vdev) {
+		pmo_err("vdev is NULL");
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto out;
+	}
+
+	status = pmo_vdev_get_ref(vdev);
+	if (status != QDF_STATUS_SUCCESS)
+		goto out;
+
+	status = pmo_core_arp_offload_sanity(vdev);
+	if (status != QDF_STATUS_SUCCESS)
+		goto put_ref;
+
+	vdev_id = pmo_vdev_get_id(vdev);
+	vdev_ctx = pmo_vdev_get_priv(vdev);
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	*params = vdev_ctx->vdev_arp_req;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+
+put_ref:
+	pmo_vdev_put_ref(vdev);
+out:
+	pmo_exit();
+
+	return status;
+}

+ 51 - 0
components/pmo/core/src/wlan_pmo_mc_addr_filtering.c

@@ -634,3 +634,54 @@ out:
 	return status;
 }
 
+QDF_STATUS
+pmo_core_get_mc_addr_list(struct wlan_objmgr_psoc *psoc,
+			  uint8_t vdev_id,
+			  struct pmo_mc_addr_list *mc_list_req)
+{
+	QDF_STATUS status;
+	struct wlan_objmgr_vdev *vdev;
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	pmo_enter();
+
+	if (!mc_list_req)
+		return QDF_STATUS_E_INVAL;
+
+	qdf_mem_zero(mc_list_req, sizeof(*mc_list_req));
+
+	status = pmo_psoc_get_ref(psoc);
+	if (QDF_IS_STATUS_ERROR(status))
+		goto exit_with_status;
+
+	vdev = pmo_psoc_get_vdev(psoc, vdev_id);
+	if (!vdev) {
+		pmo_err("vdev is NULL");
+		status = QDF_STATUS_E_INVAL;
+		goto put_psoc;
+	}
+
+	status = pmo_vdev_get_ref(vdev);
+	if (QDF_IS_STATUS_ERROR(status))
+		goto put_psoc;
+
+	status = pmo_core_mc_addr_flitering_sanity(vdev);
+	if (status != QDF_STATUS_SUCCESS)
+		goto put_vdev;
+
+	vdev_ctx = pmo_vdev_get_priv(vdev);
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	*mc_list_req = vdev_ctx->vdev_mc_list_req;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+
+put_vdev:
+	pmo_vdev_put_ref(vdev);
+
+put_psoc:
+	pmo_psoc_put_ref(psoc);
+
+exit_with_status:
+	pmo_exit();
+
+	return status;
+}

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

@@ -61,6 +61,8 @@ static void pmo_core_fill_ns_addr(struct pmo_ns_offload_params *request,
 		request->target_ipv6_addr_ac_type[i] =
 			ns_req->ipv6_addr_type[i];
 
+		request->scope[i] = ns_req->scope[i];
+
 		pmo_debug("NSoffload solicitIp: %pI6 targetIp: %pI6 Index: %d",
 			&request->self_ipv6_addr[i],
 			&request->target_ipv6_addr[i], i);
@@ -84,6 +86,7 @@ static QDF_STATUS pmo_core_cache_ns_in_vdev_priv(
 	pmo_core_fill_ns_addr(&request, ns_req);
 
 	request.enable = PMO_OFFLOAD_ENABLE;
+	request.is_offload_applied = false;
 	qdf_mem_copy(&request.self_macaddr.bytes,
 			  wlan_vdev_mlme_get_macaddr(vdev),
 			  QDF_MAC_ADDR_SIZE);
@@ -128,6 +131,7 @@ static QDF_STATUS pmo_core_flush_ns_from_vdev_priv(
 	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
 	qdf_mem_zero(&vdev_ctx->vdev_ns_req, sizeof(vdev_ctx->vdev_ns_req));
 	vdev_ctx->vdev_ns_req.enable = PMO_OFFLOAD_DISABLE;
+	vdev_ctx->vdev_ns_req.is_offload_applied = false;
 	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
 
 	pmo_exit();
@@ -453,3 +457,44 @@ out:
 	return status;
 }
 
+QDF_STATUS
+pmo_core_get_ns_offload_params(struct wlan_objmgr_vdev *vdev,
+			       struct pmo_ns_offload_params *params)
+{
+	QDF_STATUS status;
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	pmo_enter();
+
+	if (!params)
+		return QDF_STATUS_E_INVAL;
+
+	qdf_mem_zero(params, sizeof(*params));
+
+	if (!vdev) {
+		pmo_err("vdev is NULL");
+		status = QDF_STATUS_E_INVAL;
+		goto out;
+	}
+
+	status = pmo_vdev_get_ref(vdev);
+	if (status != QDF_STATUS_SUCCESS)
+		goto out;
+
+	vdev_ctx = pmo_vdev_get_priv(vdev);
+
+	status = pmo_core_ns_offload_sanity(vdev);
+	if (status != QDF_STATUS_SUCCESS)
+		goto dec_ref;
+
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	*params = vdev_ctx->vdev_ns_req;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+
+dec_ref:
+	pmo_vdev_put_ref(vdev);
+out:
+	pmo_exit();
+
+	return status;
+}

+ 1 - 0
components/pmo/dispatcher/inc/wlan_pmo_arp_public_struct.h

@@ -52,6 +52,7 @@ struct pmo_arp_offload_params {
 	uint8_t enable;
 	uint8_t host_ipv4_addr[PMO_IPV4_ADDR_LEN];
 	struct qdf_mac_addr bssid;
+	bool is_offload_applied;
 };
 
 #endif /* end  of _WLAN_PMO_ARP_PUBLIC_STRUCT_H_ */

+ 22 - 1
components/pmo/dispatcher/inc/wlan_pmo_ns_public_struct.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018 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
@@ -28,6 +28,24 @@
 
 #include "wlan_pmo_common_public_struct.h"
 
+/**
+ * enum pmo_ns_addr_scope - Internal identification of IPv6 addr scope
+ * @PMO_NS_ADDR_SCOPE_INVALID: invalid scope
+ * @PMO_NS_ADDR_SCOPE_NODELOCAL: node local scope
+ * @PMO_NS_ADDR_SCOPE_LINKLOCAL: link local scope
+ * @PMO_NS_ADDR_SCOPE_SITELOCAL: site local scope
+ * @PMO_NS_ADDR_SCOPE_ORGLOCAL: org local scope
+ * @PMO_NS_ADDR_SCOPE_GLOBAL: global scope
+ */
+enum pmo_ns_addr_scope {
+	PMO_NS_ADDR_SCOPE_INVALID = 0,
+	PMO_NS_ADDR_SCOPE_NODELOCAL = 1,
+	PMO_NS_ADDR_SCOPE_LINKLOCAL = 2,
+	PMO_NS_ADDR_SCOPE_SITELOCAL = 3,
+	PMO_NS_ADDR_SCOPE_ORGLOCAL = 4,
+	PMO_NS_ADDR_SCOPE_GLOBAL = 5
+};
+
 /**
  * struct pmo_ns_offload_params - pmo ns offload parameters
  * @enable: true when ns offload enable
@@ -55,6 +73,8 @@ struct pmo_ns_offload_params {
 	uint8_t target_ipv6_addr_ac_type[PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA];
 	uint8_t slot_idx;
 	struct qdf_mac_addr bssid;
+	enum pmo_ns_addr_scope scope[PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA];
+	bool is_offload_applied;
 };
 
 /**
@@ -74,5 +94,6 @@ struct pmo_ns_req {
 	uint8_t ipv6_addr[PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA]
 				[PMO_MAC_IPV6_ADDR_LEN];
 	uint8_t ipv6_addr_type[PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA];
+	enum pmo_ns_addr_scope scope[PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA];
 };
 #endif /* end  of _WLAN_PMO_NS_PUBLIC_STRUCT_H_ */

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

@@ -173,6 +173,17 @@ QDF_STATUS pmo_ucfg_enable_arp_offload_in_fwr(struct wlan_objmgr_vdev *vdev,
 QDF_STATUS pmo_ucfg_disable_arp_offload_in_fwr(struct wlan_objmgr_vdev *vdev,
 		enum pmo_offload_trigger trigger);
 
+/**
+ * pmo_ucfg_get_arp_offload_params() - API to get arp offload params
+ * @vdev: objmgr vdev
+ * @params: output pointer to hold offload params
+ *
+ * Return: QDF_STATUS_SUCCESS in case of success else return error
+ */
+QDF_STATUS
+pmo_ucfg_get_arp_offload_params(struct wlan_objmgr_vdev *vdev,
+				struct pmo_arp_offload_params *params);
+
 /**
  * pmo_ucfg_cache_ns_offload_req(): API to cache ns req in pmo vdev priv ctx
  * @ns_req: pmo ns req param
@@ -213,6 +224,27 @@ QDF_STATUS pmo_ucfg_enable_ns_offload_in_fwr(struct wlan_objmgr_vdev *vdev,
 QDF_STATUS pmo_ucfg_disable_ns_offload_in_fwr(struct wlan_objmgr_vdev *vdev,
 		enum pmo_offload_trigger trigger);
 
+/**
+ * pmo_ucfg_get_ns_offload_params() - API to get ns offload params
+ * @vdev: objmgr vdev
+ * @params: output pointer to hold offload params
+ *
+ * Return: QDF_STATUS_SUCCESS in case of success else return error
+ */
+QDF_STATUS
+pmo_ucfg_get_ns_offload_params(struct wlan_objmgr_vdev *vdev,
+			       struct pmo_ns_offload_params *params);
+
+/**
+ * pmo_ucfg_ns_addr_scope() - Convert linux specific IPv6 addr scope to
+ *			      WLAN driver specific value
+ * @scope: linux specific IPv6 addr scope
+ *
+ * Return: PMO identifier of linux IPv6 addr scope
+ */
+enum pmo_ns_addr_scope
+pmo_ucfg_ns_addr_scope(uint32_t ipv6_scope);
+
 /**
  * pmo_ucfg_enable_hw_filter_in_fwr() - enable previously configured hw filter
  * @vdev: objmgr vdev to configure
@@ -314,6 +346,19 @@ QDF_STATUS pmo_ucfg_disable_mc_addr_filtering_in_fwr(
 		uint8_t vdev_id,
 		enum pmo_offload_trigger trigger);
 
+/**
+ * pmo_ucfg_get_mc_addr_list() - API to get mc addr list configured
+ * @psoc: objmgr psoc
+ * @vdev_id: vdev identifier
+ * @mc_list_req: output pointer to hold mc addr list params
+ *
+ * Return: QDF_STATUS_SUCCESS in case of success else return error
+ */
+QDF_STATUS
+pmo_ucfg_get_mc_addr_list(struct wlan_objmgr_psoc *psoc,
+			  uint8_t vdev_id,
+			  struct pmo_mc_addr_list *mc_list_req);
+
 /**
  * pmo_ucfg_cache_gtk_offload_req(): API to cache gtk req in pmo vdev priv obj
  * @vdev: objmgr vdev handle
@@ -765,6 +810,13 @@ pmo_ucfg_disable_arp_offload_in_fwr(
 	return QDF_STATUS_SUCCESS;
 }
 
+static inline QDF_STATUS
+pmo_ucfg_get_arp_offload_params(struct wlan_objmgr_vdev *vdev,
+				struct pmo_arp_offload_params *params)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
 static inline QDF_STATUS
 pmo_ucfg_cache_ns_offload_req(struct pmo_ns_req *ns_req)
 {
@@ -793,6 +845,19 @@ pmo_ucfg_disable_ns_offload_in_fwr(
 	return QDF_STATUS_SUCCESS;
 }
 
+static inline QDF_STATUS
+pmo_ucfg_get_ns_offload_params(struct wlan_objmgr_vdev *vdev,
+			       struct pmo_ns_offload_params *params)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline enum pmo_ns_addr_scope
+pmo_ucfg_ns_addr_scope(uint32_t ipv6_scope)
+{
+	return PMO_NS_ADDR_SCOPE_INVALID;
+}
+
 static inline QDF_STATUS
 pmo_ucfg_cache_mc_addr_list(
 		struct pmo_mc_addr_list_params *mc_list_config)
@@ -832,6 +897,14 @@ pmo_ucfg_max_mc_addr_supported(struct wlan_objmgr_psoc *psoc)
 	return 0;
 }
 
+static inline QDF_STATUS
+pmo_ucfg_get_mc_addr_list(struct wlan_objmgr_psoc *psoc,
+			  uint8_t vdev_id,
+			  struct pmo_mc_addr_list *mc_list_req)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
 static inline QDF_STATUS
 pmo_ucfg_cache_gtk_offload_req(
 		struct wlan_objmgr_vdev *vdev,

+ 16 - 1
components/pmo/dispatcher/src/wlan_pmo_tgt_arp.c

@@ -79,8 +79,18 @@ QDF_STATUS pmo_tgt_enable_arp_offload_req(struct wlan_objmgr_vdev *vdev,
 	}
 	status = pmo_tx_ops.send_arp_offload_req(
 			vdev, arp_offload_req, ns_offload_req);
-	if (status != QDF_STATUS_SUCCESS)
+	if (status != QDF_STATUS_SUCCESS) {
 		pmo_err("Failed to send ARP offload");
+		goto out;
+	}
+
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	if (vdev_ctx->vdev_arp_req.enable)
+		vdev_ctx->vdev_arp_req.is_offload_applied = true;
+	if (vdev_ctx->vdev_ns_req.enable)
+		vdev_ctx->vdev_ns_req.is_offload_applied = true;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+
 out:
 	if (arp_offload_req)
 		qdf_mem_free(arp_offload_req);
@@ -147,6 +157,11 @@ QDF_STATUS pmo_tgt_disable_arp_offload_req(struct wlan_objmgr_vdev *vdev,
 	if (status != QDF_STATUS_SUCCESS)
 		pmo_err("Failed to send ARP offload");
 
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	vdev_ctx->vdev_arp_req.is_offload_applied = false;
+	vdev_ctx->vdev_ns_req.is_offload_applied = false;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+
 out:
 	if (arp_offload_req)
 		qdf_mem_free(arp_offload_req);

+ 15 - 1
components/pmo/dispatcher/src/wlan_pmo_tgt_ns.c

@@ -79,8 +79,17 @@ QDF_STATUS pmo_tgt_enable_ns_offload_req(struct wlan_objmgr_vdev *vdev,
 	}
 	status = pmo_tx_ops.send_ns_offload_req(
 			vdev, arp_offload_req, ns_offload_req);
-	if (status != QDF_STATUS_SUCCESS)
+	if (status != QDF_STATUS_SUCCESS) {
 		pmo_err("Failed to send NS offload");
+		goto out;
+	}
+
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	if (vdev_ctx->vdev_arp_req.enable)
+		vdev_ctx->vdev_arp_req.is_offload_applied = true;
+	if (vdev_ctx->vdev_ns_req.enable)
+		vdev_ctx->vdev_ns_req.is_offload_applied = true;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
 
 out:
 	if (arp_offload_req)
@@ -148,6 +157,11 @@ QDF_STATUS pmo_tgt_disable_ns_offload_req(struct wlan_objmgr_vdev *vdev,
 	if (status != QDF_STATUS_SUCCESS)
 		pmo_err("Failed to send NS offload");
 
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	vdev_ctx->vdev_arp_req.is_offload_applied = false;
+	vdev_ctx->vdev_ns_req.is_offload_applied = false;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+
 out:
 	if (arp_offload_req)
 		qdf_mem_free(arp_offload_req);

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

@@ -128,6 +128,13 @@ QDF_STATUS pmo_ucfg_disable_arp_offload_in_fwr(struct wlan_objmgr_vdev *vdev,
 	return pmo_core_disable_arp_offload_in_fwr(vdev, trigger);
 }
 
+QDF_STATUS
+pmo_ucfg_get_arp_offload_params(struct wlan_objmgr_vdev *vdev,
+				struct pmo_arp_offload_params *params)
+{
+	return pmo_core_get_arp_offload_params(vdev, params);
+}
+
 #ifdef WLAN_NS_OFFLOAD
 QDF_STATUS pmo_ucfg_cache_ns_offload_req(struct pmo_ns_req *ns_req)
 {
@@ -152,6 +159,32 @@ QDF_STATUS pmo_ucfg_disable_ns_offload_in_fwr(struct wlan_objmgr_vdev *vdev,
 }
 #endif /* WLAN_NS_OFFLOAD */
 
+QDF_STATUS
+pmo_ucfg_get_ns_offload_params(struct wlan_objmgr_vdev *vdev,
+			       struct pmo_ns_offload_params *params)
+{
+	return pmo_core_get_ns_offload_params(vdev, params);
+}
+
+enum pmo_ns_addr_scope
+pmo_ucfg_ns_addr_scope(uint32_t ipv6_scope)
+{
+	switch (ipv6_scope) {
+	case IPV6_ADDR_SCOPE_NODELOCAL:
+		return PMO_NS_ADDR_SCOPE_NODELOCAL;
+	case IPV6_ADDR_SCOPE_LINKLOCAL:
+		return PMO_NS_ADDR_SCOPE_LINKLOCAL;
+	case IPV6_ADDR_SCOPE_SITELOCAL:
+		return PMO_NS_ADDR_SCOPE_SITELOCAL;
+	case IPV6_ADDR_SCOPE_ORGLOCAL:
+		return PMO_NS_ADDR_SCOPE_ORGLOCAL;
+	case IPV6_ADDR_SCOPE_GLOBAL:
+		return PMO_NS_ADDR_SCOPE_GLOBAL;
+	}
+
+	return PMO_NS_ADDR_SCOPE_INVALID;
+}
+
 QDF_STATUS pmo_ucfg_cache_mc_addr_list(
 		struct pmo_mc_addr_list_params *mc_list_config)
 {
@@ -187,6 +220,14 @@ uint8_t pmo_ucfg_max_mc_addr_supported(struct wlan_objmgr_psoc *psoc)
 	return pmo_core_max_mc_addr_supported(psoc);
 }
 
+QDF_STATUS
+pmo_ucfg_get_mc_addr_list(struct wlan_objmgr_psoc *psoc,
+			  uint8_t vdev_id,
+			  struct pmo_mc_addr_list *mc_list_req)
+{
+	return pmo_core_get_mc_addr_list(psoc, vdev_id, mc_list_req);
+}
+
 QDF_STATUS pmo_ucfg_cache_gtk_offload_req(struct wlan_objmgr_vdev *vdev,
 		struct pmo_gtk_req *gtk_req)
 {

+ 30 - 0
core/hdd/inc/wlan_hdd_debugfs_csr.h

@@ -40,6 +40,7 @@
 #ifdef WLAN_DEBUGFS
 
 #define DEBUGFS_CONNECT_INFO_BUF_SIZE    (4 * 1024)
+#define DEBUGFS_OFFLOAD_INFO_BUF_SIZE    (4 * 1024)
 
 /**
  * struct wlan_hdd_debugfs_buffer_info - Debugfs buffer info
@@ -99,6 +100,19 @@ wlan_hdd_debugfs_update_connect_info(struct hdd_context *hdd_ctx,
 				     struct hdd_adapter *adapter,
 				     uint8_t *buf, ssize_t buf_avail_len);
 
+/**
+ * wlan_hdd_debugfs_update_filters_info() - API to get offload info
+ * into user buffer
+ * @buf: output buffer to hold offload info
+ * @buf_avail_len: available buffer length
+ *
+ * Return: No.of bytes copied
+ */
+ssize_t
+wlan_hdd_debugfs_update_filters_info(struct hdd_context *hdd_ctx,
+				     struct hdd_adapter *adapter,
+				     uint8_t *buf, ssize_t buf_avail_len);
+
 #else
 /**
  * wlan_hdd_debugfs_csr_init() - Create wifi diagnostic debugfs files
@@ -149,6 +163,22 @@ wlan_hdd_debugfs_update_connect_info(struct hdd_context *hdd_ctx,
 	return 0;
 }
 
+/**
+ * wlan_hdd_debugfs_update_filters_info() - API to get offload info
+ * into user buffer
+ * @buf: output buffer to hold offload info
+ * @buf_avail_len: available buffer length
+ *
+ * Return: No.of bytes copied
+ */
+static inline ssize_t
+wlan_hdd_debugfs_update_filters_info(struct hdd_context *hdd_ctx,
+				     struct hdd_adapter *adapter,
+				     uint8_t *buf, ssize_t buf_avail_len)
+{
+	return 0;
+}
+
 #endif
 
 #endif /* _WLAN_HDD_DEBUGFS_CSR_H */

+ 1 - 0
core/hdd/inc/wlan_hdd_main.h

@@ -1973,6 +1973,7 @@ struct hdd_context {
 #ifdef FEATURE_WLAN_APF
 	bool apf_supported;
 	uint32_t apf_version;
+	bool apf_enabled_v2;
 #endif
 
 #ifdef DISABLE_CHANNEL_LIST

+ 4 - 0
core/hdd/src/wlan_hdd_apf.c

@@ -312,6 +312,10 @@ fail:
 	if (apf_set_offload->current_length)
 		qdf_mem_free(apf_set_offload->program);
 	qdf_mem_free(apf_set_offload);
+
+	if (!ret)
+		hdd_ctx->apf_enabled_v2 = true;
+
 	return ret;
 }
 

+ 14 - 0
core/hdd/src/wlan_hdd_debugfs_csr.c

@@ -84,6 +84,8 @@ wlan_hdd_debugfs_update_csr(struct hdd_context *hdd_ctx,
 		break;
 	case HDD_DEBUFS_FILE_ID_OFFLOAD_INFO:
 		/* populate offload info */
+		len = wlan_hdd_debugfs_update_filters_info(hdd_ctx, adapter,
+							   buf, buf_avail_len);
 		break;
 	default:
 		hdd_err("Failed to fetch stats, unknown stats type");
@@ -339,6 +341,18 @@ void wlan_hdd_debugfs_csr_init(struct hdd_adapter *adapter)
 			hdd_err("Failed to create debugfs file: %s",
 				csr->name);
 	}
+
+	csr = &adapter->csr_file[HDD_DEBUFS_FILE_ID_OFFLOAD_INFO];
+	if (!csr->entry) {
+		strlcpy(csr->name, "offload_info", max_len);
+		csr->id = HDD_DEBUFS_FILE_ID_OFFLOAD_INFO;
+		csr->buf_max_size = DEBUGFS_OFFLOAD_INFO_BUF_SIZE;
+		csr->entry = debugfs_create_file(csr->name, 0444,
+						 adapter->debugfs_phy,
+						 csr, &fops_csr_debugfs);
+		if (!csr->entry)
+			hdd_err("Failed to create generic_info debugfs file");
+	}
 }
 
 void wlan_hdd_debugfs_csr_deinit(struct hdd_adapter *adapter)

+ 423 - 0
core/hdd/src/wlan_hdd_debugfs_offload.c

@@ -0,0 +1,423 @@
+
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_hdd_debugfs_offload.c
+ *
+ * WLAN Host Device Driver implementation to update
+ * debugfs with offload information
+ */
+
+#include <wlan_hdd_debugfs_csr.h>
+#include <wlan_hdd_main.h>
+#include <cds_sched.h>
+#include <wma_api.h>
+#include "qwlan_version.h"
+#include "wmi_unified_param.h"
+#include "wlan_pmo_common_public_struct.h"
+#include "wlan_pmo_ns_public_struct.h"
+#include "wlan_pmo_mc_addr_filtering_public_struct.h"
+#include "wlan_pmo_ucfg_api.h"
+
+/* IPv6 address string */
+#define IPV6_MAC_ADDRESS_STR_LEN 47  /* Including null terminator */
+
+/**
+ * wlan_hdd_mc_addr_list_info_debugfs() - Populate mc addr list info
+ * @hdd_ctx: pointer to hdd context
+ * @adapter: pointer to adapter
+ * @buf: output buffer to hold mc addr list info
+ * @buf_avail_len: available buffer length
+ *
+ * Return: No.of bytes populated by this function in buffer
+ */
+static ssize_t
+wlan_hdd_mc_addr_list_info_debugfs(struct hdd_context *hdd_ctx,
+				   struct hdd_adapter *adapter, uint8_t *buf,
+				   ssize_t buf_avail_len)
+{
+	ssize_t length = 0;
+	int ret;
+	uint8_t i;
+	struct pmo_mc_addr_list mc_addr_list = {0};
+	QDF_STATUS status;
+
+	if (!hdd_ctx->config->fEnableMCAddrList) {
+		ret = scnprintf(buf, buf_avail_len,
+				"\nMC addr ini is disabled\n");
+		if (ret > 0)
+			length = ret;
+		return length;
+	}
+
+	status = pmo_ucfg_get_mc_addr_list(hdd_ctx->hdd_psoc,
+					   adapter->session_id,
+					   &mc_addr_list);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		ret = scnprintf(buf, buf_avail_len,
+				"\nMC addr list query is failed\n");
+		if (ret > 0)
+			length = ret;
+		return length;
+	}
+
+	if (mc_addr_list.mc_cnt == 0) {
+		ret = scnprintf(buf, buf_avail_len,
+				"\nMC addr list is empty\n");
+		if (ret > 0)
+			length = ret;
+		return length;
+	}
+
+	ret = scnprintf(buf, buf_avail_len,
+			"\nMC ADDR LIST DETAILS (mc_cnt = %u)\n",
+			mc_addr_list.mc_cnt);
+	if (ret <= 0)
+		return length;
+	length += ret;
+
+	for (i = 0; i < mc_addr_list.mc_cnt; i++) {
+		if (length >= buf_avail_len) {
+			hdd_err("No sufficient buf_avail_len");
+			return buf_avail_len;
+		}
+
+		ret = scnprintf(buf + length, buf_avail_len - length,
+				MAC_ADDRESS_STR "\n",
+				MAC_ADDR_ARRAY(mc_addr_list.mc_addr[i].bytes));
+		if (ret <= 0)
+			return length;
+		length += ret;
+	}
+
+	if (length >= buf_avail_len) {
+		hdd_err("No sufficient buf_avail_len");
+		return buf_avail_len;
+	}
+	ret = scnprintf(buf + length, buf_avail_len - length,
+			"mc_filter_applied = %u\n",
+			mc_addr_list.is_filter_applied);
+	if (ret <= 0)
+		return length;
+
+	length += ret;
+	return length;
+}
+
+/**
+ * wlan_hdd_arp_offload_info_debugfs() - Populate arp offload info
+ * @hdd_ctx: pointer to hdd context
+ * @adapter: pointer to adapter
+ * @buf: output buffer to hold arp offload info
+ * @buf_avail_len: available buffer length
+ *
+ * Return: No.of bytes populated by this function in buffer
+ */
+static ssize_t
+wlan_hdd_arp_offload_info_debugfs(struct hdd_context *hdd_ctx,
+				  struct hdd_adapter *adapter, uint8_t *buf,
+				  ssize_t buf_avail_len)
+{
+	ssize_t length = 0;
+	int ret_val;
+	struct pmo_arp_offload_params info = {0};
+	QDF_STATUS status;
+
+	status = pmo_ucfg_get_arp_offload_params(adapter->hdd_vdev,
+						 &info);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		ret_val = scnprintf(buf, buf_avail_len,
+				    "\nARP OFFLOAD QUERY FAILED\n");
+		goto len_adj;
+	}
+
+	if (!info.is_offload_applied)
+		ret_val = scnprintf(buf, buf_avail_len,
+				    "\nARP OFFLOAD: DISABLED\n");
+	else
+		ret_val = scnprintf(buf, buf_avail_len,
+				    "\nARP OFFLOAD: ENABLED (%u.%u.%u.%u)\n",
+				    info.host_ipv4_addr[0],
+				    info.host_ipv4_addr[1],
+				    info.host_ipv4_addr[2],
+				    info.host_ipv4_addr[3]);
+len_adj:
+	if (ret_val <= 0)
+		return length;
+	length = ret_val;
+
+	return length;
+}
+
+#ifdef WLAN_NS_OFFLOAD
+/**
+ * ipv6_addr_string() - Get IPv6 addr string from array of octets
+ * @buffer: output buffer to hold string, caller should ensure size of
+ *          buffer is atleast IPV6_MAC_ADDRESS_STR_LEN
+ * @ipv6_addr: IPv6 address array
+ *
+ * Return: None
+ */
+static void ipv6_addr_string(uint8_t *buffer, uint8_t *ipv6_addr)
+{
+	uint8_t *a = ipv6_addr;
+
+	scnprintf(buffer, IPV6_MAC_ADDRESS_STR_LEN,
+		  "%02x%02x::%02x%02x::%02x%02x::%02x%02x::%02x%02x::%02x%02x::%02x%02x::%02x%02x",
+		  (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5], (a)[6],
+		  (a)[7], (a)[8], (a)[9], (a)[10], (a)[11], (a)[12], (a)[13],
+		  (a)[14], (a)[15]);
+}
+
+/**
+ * hdd_ipv6_scope_str() - Get string for PMO NS (IPv6) Addr scope
+ * @scope: scope id from enum pmo_ns_addr_scope
+ *
+ * Return: Meaningful string for enum pmo_ns_addr_scope
+ */
+static uint8_t *hdd_ipv6_scope_str(enum pmo_ns_addr_scope scope)
+{
+	switch (scope) {
+	case PMO_NS_ADDR_SCOPE_NODELOCAL:
+		return "Node Local";
+	case PMO_NS_ADDR_SCOPE_LINKLOCAL:
+		return "Link Local";
+	case PMO_NS_ADDR_SCOPE_SITELOCAL:
+		return "Site Local";
+	case PMO_NS_ADDR_SCOPE_ORGLOCAL:
+		return "Org Local";
+	case PMO_NS_ADDR_SCOPE_GLOBAL:
+		return "Global";
+	default:
+		return "Invalid";
+	}
+}
+
+/**
+ * wlan_hdd_ns_offload_info_debugfs() - Populate ns offload info
+ * @hdd_ctx: pointer to hdd context
+ * @adapter: pointer to adapter
+ * @buf: output buffer to hold ns offload info
+ * @buf_avail_len: available buffer length
+ *
+ * Return: No.of bytes populated by this function in buffer
+ */
+static ssize_t
+wlan_hdd_ns_offload_info_debugfs(struct hdd_context *hdd_ctx,
+				 struct hdd_adapter *adapter, uint8_t *buf,
+				 ssize_t buf_avail_len)
+{
+	ssize_t length = 0;
+	int ret;
+	struct pmo_ns_offload_params info = {0};
+	QDF_STATUS status;
+	uint32_t i;
+
+	status = pmo_ucfg_get_ns_offload_params(adapter->hdd_vdev,
+						&info);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		ret = scnprintf(buf, buf_avail_len,
+				"\nNS OFFLOAD QUERY FAILED\n");
+		if (ret <= 0)
+			return length;
+		length += ret;
+
+		return length;
+	}
+
+	ret = scnprintf(buf, buf_avail_len,
+			"\nNS OFFLOAD DETAILS\n");
+	if (ret <= 0)
+		return length;
+	length += ret;
+
+	if (length >= buf_avail_len) {
+		hdd_err("No sufficient buf_avail_len");
+		return buf_avail_len;
+	}
+
+	if (!info.is_offload_applied) {
+		ret = scnprintf(buf + length, buf_avail_len - length,
+				"NS offload is not enabled\n");
+		if (ret <= 0)
+			return length;
+		length += ret;
+
+		return length;
+	}
+
+	ret = scnprintf(buf + length, buf_avail_len - length,
+			"NS offload enabled, %u ns addresses offloaded\n",
+			info.num_ns_offload_count);
+	if (ret <= 0)
+		return length;
+	length += ret;
+
+	for (i = 0; i < info.num_ns_offload_count; i++) {
+		uint8_t ipv6_str[IPV6_MAC_ADDRESS_STR_LEN];
+		uint8_t cast_string[12];
+		uint8_t *scope_string;
+
+		if (length >= buf_avail_len) {
+			hdd_err("No sufficient buf_avail_len");
+			return buf_avail_len;
+		}
+
+		ipv6_addr_string(ipv6_str, info.target_ipv6_addr[i]);
+		scope_string = hdd_ipv6_scope_str(info.scope[i]);
+
+		if (info.target_ipv6_addr_ac_type[i] ==
+		    PMO_IPV6_ADDR_AC_TYPE)
+			strlcpy(cast_string, "(ANY CAST)", 12);
+		else
+			strlcpy(cast_string, "(UNI CAST)", 12);
+
+		ret = scnprintf(buf + length, buf_avail_len - length,
+				"%u. %s %s and scope is: %s\n",
+				(i + 1), ipv6_str, cast_string,
+				scope_string);
+		if (ret <= 0)
+			return length;
+		length += ret;
+	}
+
+	return length;
+}
+#else
+/**
+ * wlan_hdd_ns_offload_info_debugfs() - Populate ns offload info
+ * @hdd_ctx: pointer to hdd context
+ * @adapter: pointer to adapter
+ * @buf: output buffer to hold ns offload info
+ * @buf_avail_len: available buffer length
+ *
+ * Return: No.of bytes populated by this function in buffer
+ */
+static ssize_t
+wlan_hdd_ns_offload_info_debugfs(struct hdd_context *hdd_ctx,
+				 struct hdd_adapter *adapter, uint8_t *buf,
+				 ssize_t buf_avail_len)
+{
+	return 0;
+}
+#endif
+
+/**
+ * wlan_hdd_apf_info_debugfs() - Populate apf offload info
+ * @hdd_ctx: pointer to hdd context
+ * @adapter: pointer to adapter
+ * @buf: output buffer to hold apf offload info
+ * @buf_avail_len: available buffer length
+ *
+ * Return: No.of bytes populated by this function in buffer
+ */
+static ssize_t
+wlan_hdd_apf_info_debugfs(struct hdd_context *hdd_ctx,
+			  struct hdd_adapter *adapter, uint8_t *buf,
+			  ssize_t buf_avail_len)
+{
+	ssize_t length = 0;
+	int ret_val;
+	bool apf_enabled;
+
+	if (hdd_ctx->apf_version > 2)
+		apf_enabled = adapter->apf_context.apf_enabled;
+	else
+		apf_enabled = hdd_ctx->apf_enabled_v2;
+
+	ret_val = scnprintf(buf, buf_avail_len,
+			    "\nAPF OFFLOAD DETAILS, offload_applied: %u\n\n",
+			    apf_enabled);
+	if (ret_val <= 0)
+		return length;
+	length = ret_val;
+
+	return length;
+}
+
+ssize_t
+wlan_hdd_debugfs_update_filters_info(struct hdd_context *hdd_ctx,
+				     struct hdd_adapter *adapter,
+				     uint8_t *buf, ssize_t buf_avail_len)
+{
+	ssize_t len;
+	int ret_val;
+	struct hdd_station_ctx *hdd_sta_ctx;
+
+	hdd_enter();
+
+	len = wlan_hdd_current_time_info_debugfs(buf, buf_avail_len);
+
+	if (len >= buf_avail_len) {
+		hdd_err("No sufficient buf_avail_len");
+		return buf_avail_len;
+	}
+
+	if (adapter->device_mode != QDF_STA_MODE) {
+		ret_val = scnprintf(buf + len, buf_avail_len - len,
+				    "Interface is not operating in STA mode\n");
+		if (ret_val <= 0)
+			return len;
+
+		len += ret_val;
+		return len;
+	}
+
+	hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
+	if (hdd_sta_ctx->conn_info.connState != eConnectionState_Associated) {
+		ret_val = scnprintf(buf + len, buf_avail_len - len,
+				    "\nSTA is not connected\n");
+		if (ret_val <= 0)
+			return len;
+
+		len += ret_val;
+		return len;
+	}
+
+	len += wlan_hdd_mc_addr_list_info_debugfs(hdd_ctx, adapter, buf + len,
+						  buf_avail_len - len);
+
+	if (len >= buf_avail_len) {
+		hdd_err("No sufficient buf_avail_len");
+		return buf_avail_len;
+	}
+	len += wlan_hdd_arp_offload_info_debugfs(hdd_ctx, adapter, buf + len,
+						 buf_avail_len - len);
+
+	if (len >= buf_avail_len) {
+		hdd_err("No sufficient buf_avail_len");
+		return buf_avail_len;
+	}
+	len += wlan_hdd_ns_offload_info_debugfs(hdd_ctx, adapter, buf + len,
+						buf_avail_len - len);
+
+	if (len >= buf_avail_len) {
+		hdd_err("No sufficient buf_avail_len");
+		return buf_avail_len;
+	}
+	len += wlan_hdd_apf_info_debugfs(hdd_ctx, adapter, buf + len,
+					 buf_avail_len - len);
+
+	hdd_exit();
+
+	return len;
+}

+ 14 - 4
core/hdd/src/wlan_hdd_power.c

@@ -245,6 +245,7 @@ int wlan_hdd_ipv6_changed(struct notifier_block *nb,
  * @idev: pointer to net device
  * @ipv6addr: destination array to fill IPv6 addresses
  * @ipv6addr_type: IPv6 Address type
+ * @scope_array: scope of ipv6 addr
  * @count: number of IPv6 addresses
  *
  * This is the IPv6 utility function to populate unicast addresses.
@@ -253,7 +254,9 @@ int wlan_hdd_ipv6_changed(struct notifier_block *nb,
  */
 static int hdd_fill_ipv6_uc_addr(struct inet6_dev *idev,
 				uint8_t ipv6_uc_addr[][SIR_MAC_IPV6_ADDR_LEN],
-				uint8_t *ipv6addr_type, uint32_t *count)
+				uint8_t *ipv6addr_type,
+				enum pmo_ns_addr_scope *scope_array,
+				uint32_t *count)
 {
 	struct inet6_ifaddr *ifa;
 	struct list_head *p;
@@ -275,6 +278,7 @@ static int hdd_fill_ipv6_uc_addr(struct inet6_dev *idev,
 			qdf_mem_copy(ipv6_uc_addr[*count], &ifa->addr.s6_addr,
 				sizeof(ifa->addr.s6_addr));
 			ipv6addr_type[*count] = PMO_IPV6_ADDR_UC_TYPE;
+			scope_array[*count] = pmo_ucfg_ns_addr_scope(scope);
 			hdd_debug("Index %d scope = %s UC-Address: %pI6",
 				*count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ?
 				"LINK LOCAL" : "GLOBAL", ipv6_uc_addr[*count]);
@@ -294,6 +298,7 @@ static int hdd_fill_ipv6_uc_addr(struct inet6_dev *idev,
  * @idev: pointer to net device
  * @ipv6addr: destination array to fill IPv6 addresses
  * @ipv6addr_type: IPv6 Address type
+ * @scope_array: scope of ipv6 addr
  * @count: number of IPv6 addresses
  *
  * This is the IPv6 utility function to populate anycast addresses.
@@ -302,7 +307,9 @@ static int hdd_fill_ipv6_uc_addr(struct inet6_dev *idev,
  */
 static int hdd_fill_ipv6_ac_addr(struct inet6_dev *idev,
 				uint8_t ipv6_ac_addr[][SIR_MAC_IPV6_ADDR_LEN],
-				uint8_t *ipv6addr_type, uint32_t *count)
+				uint8_t *ipv6addr_type,
+				enum pmo_ns_addr_scope *scope_array,
+				uint32_t *count)
 {
 	struct ifacaddr6 *ifaca;
 	uint32_t scope;
@@ -321,6 +328,7 @@ static int hdd_fill_ipv6_ac_addr(struct inet6_dev *idev,
 			qdf_mem_copy(ipv6_ac_addr[*count], &ifaca->aca_addr,
 				sizeof(ifaca->aca_addr));
 			ipv6addr_type[*count] = PMO_IPV6_ADDR_AC_TYPE;
+			scope_array[*count] = pmo_ucfg_ns_addr_scope(scope);
 			hdd_debug("Index %d scope = %s AC-Address: %pI6",
 				*count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ?
 				"LINK LOCAL" : "GLOBAL", ipv6_ac_addr[*count]);
@@ -371,7 +379,8 @@ void hdd_enable_ns_offload(struct hdd_adapter *adapter,
 
 	/* Unicast Addresses */
 	errno = hdd_fill_ipv6_uc_addr(in6_dev, ns_req->ipv6_addr,
-				      ns_req->ipv6_addr_type, &ns_req->count);
+				      ns_req->ipv6_addr_type, ns_req->scope,
+				      &ns_req->count);
 	if (errno) {
 		hdd_disable_ns_offload(adapter, trigger);
 		hdd_debug("Max supported addresses: disabling NS offload");
@@ -380,7 +389,8 @@ void hdd_enable_ns_offload(struct hdd_adapter *adapter,
 
 	/* Anycast Addresses */
 	errno = hdd_fill_ipv6_ac_addr(in6_dev, ns_req->ipv6_addr,
-				      ns_req->ipv6_addr_type, &ns_req->count);
+				      ns_req->ipv6_addr_type, ns_req->scope,
+				      &ns_req->count);
 	if (errno) {
 		hdd_disable_ns_offload(adapter, trigger);
 		hdd_debug("Max supported addresses: disabling NS offload");