diff --git a/Kbuild b/Kbuild index 961ee9505e..350017374b 100755 --- a/Kbuild +++ b/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 diff --git a/components/pmo/core/inc/wlan_pmo_arp.h b/components/pmo/core/inc/wlan_pmo_arp.h index 976cf02604..d577cd2b8d 100644 --- a/components/pmo/core/inc/wlan_pmo_arp.h +++ b/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_ */ diff --git a/components/pmo/core/inc/wlan_pmo_mc_addr_filtering.h b/components/pmo/core/inc/wlan_pmo_mc_addr_filtering.h index 8fb2888442..fd0cca9fba 100644 --- a/components/pmo/core/inc/wlan_pmo_mc_addr_filtering.h +++ b/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_ */ diff --git a/components/pmo/core/inc/wlan_pmo_ns.h b/components/pmo/core/inc/wlan_pmo_ns.h index fa1e0d43f8..26662dd749 100644 --- a/components/pmo/core/inc/wlan_pmo_ns.h +++ b/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_ */ diff --git a/components/pmo/core/src/wlan_pmo_arp.c b/components/pmo/core/src/wlan_pmo_arp.c index c0b67fe365..cbc54c9a6d 100644 --- a/components/pmo/core/src/wlan_pmo_arp.c +++ b/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; +} diff --git a/components/pmo/core/src/wlan_pmo_mc_addr_filtering.c b/components/pmo/core/src/wlan_pmo_mc_addr_filtering.c index 75c4f5981f..2198ade661 100644 --- a/components/pmo/core/src/wlan_pmo_mc_addr_filtering.c +++ b/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; +} diff --git a/components/pmo/core/src/wlan_pmo_ns.c b/components/pmo/core/src/wlan_pmo_ns.c index 01645be211..73fc024481 100644 --- a/components/pmo/core/src/wlan_pmo_ns.c +++ b/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; +} diff --git a/components/pmo/dispatcher/inc/wlan_pmo_arp_public_struct.h b/components/pmo/dispatcher/inc/wlan_pmo_arp_public_struct.h index 23c2463cf6..4a789213aa 100644 --- a/components/pmo/dispatcher/inc/wlan_pmo_arp_public_struct.h +++ b/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_ */ diff --git a/components/pmo/dispatcher/inc/wlan_pmo_ns_public_struct.h b/components/pmo/dispatcher/inc/wlan_pmo_ns_public_struct.h index 8d94bcfa3f..7aa44d419f 100644 --- a/components/pmo/dispatcher/inc/wlan_pmo_ns_public_struct.h +++ b/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_ */ diff --git a/components/pmo/dispatcher/inc/wlan_pmo_ucfg_api.h b/components/pmo/dispatcher/inc/wlan_pmo_ucfg_api.h index 581740ef7c..0cd3f1e21a 100644 --- a/components/pmo/dispatcher/inc/wlan_pmo_ucfg_api.h +++ b/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, diff --git a/components/pmo/dispatcher/src/wlan_pmo_tgt_arp.c b/components/pmo/dispatcher/src/wlan_pmo_tgt_arp.c index 838af73702..50734d91be 100644 --- a/components/pmo/dispatcher/src/wlan_pmo_tgt_arp.c +++ b/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); diff --git a/components/pmo/dispatcher/src/wlan_pmo_tgt_ns.c b/components/pmo/dispatcher/src/wlan_pmo_tgt_ns.c index abb80fb489..6d7b9cad57 100644 --- a/components/pmo/dispatcher/src/wlan_pmo_tgt_ns.c +++ b/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); diff --git a/components/pmo/dispatcher/src/wlan_pmo_ucfg_api.c b/components/pmo/dispatcher/src/wlan_pmo_ucfg_api.c index c750655385..22a82110a7 100644 --- a/components/pmo/dispatcher/src/wlan_pmo_ucfg_api.c +++ b/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) { diff --git a/core/hdd/inc/wlan_hdd_debugfs_csr.h b/core/hdd/inc/wlan_hdd_debugfs_csr.h index 9d58f65fdf..d1b561f8cd 100644 --- a/core/hdd/inc/wlan_hdd_debugfs_csr.h +++ b/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 */ diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index c02df39ae3..b14d294ffa 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/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 diff --git a/core/hdd/src/wlan_hdd_apf.c b/core/hdd/src/wlan_hdd_apf.c index 35111447ef..0e16fdf3c1 100644 --- a/core/hdd/src/wlan_hdd_apf.c +++ b/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; } diff --git a/core/hdd/src/wlan_hdd_debugfs_csr.c b/core/hdd/src/wlan_hdd_debugfs_csr.c index 9dfc2f45cb..79208dadcf 100644 --- a/core/hdd/src/wlan_hdd_debugfs_csr.c +++ b/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) diff --git a/core/hdd/src/wlan_hdd_debugfs_offload.c b/core/hdd/src/wlan_hdd_debugfs_offload.c new file mode 100644 index 0000000000..8c4bfaa794 --- /dev/null +++ b/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 +#include +#include +#include +#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; +} diff --git a/core/hdd/src/wlan_hdd_power.c b/core/hdd/src/wlan_hdd_power.c index 839a5f7b52..4966207ded 100644 --- a/core/hdd/src/wlan_hdd_power.c +++ b/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");