From f690e5c12ac6f28da4114b2d351dcda37c54bd3a Mon Sep 17 00:00:00 2001 From: Bapiraju Alla Date: Tue, 9 Nov 2021 18:54:12 +0530 Subject: [PATCH] qcacld-3.0: Derive NDP peer multicast address from peer MAC address Currently, driver is depending on NS frame to be received to configure peer multicast address for an NDP session. If there is a delay in NS frame reception, peer multicast address list will be configured to the FW without actual peer multicast address. Because of this, FW will drop the NS frame from NDP peer. To address this, derive peer multicast address from peer MAC address and include it in multicast address list that is configured to the FW. Change-Id: I92a575352d592b4001dc4f061e31eb7f592f8445 CRs-Fixed: 3066990 --- components/nan/core/src/nan_main_i.h | 5 + components/nan/dispatcher/inc/nan_ucfg_api.h | 40 +++++++ components/nan/dispatcher/src/nan_ucfg_api.c | 104 +++++++++++++++++++ core/hdd/src/wlan_hdd_main.c | 53 ++++++++++ core/hdd/src/wlan_hdd_nan_datapath.c | 2 + core/mac/src/pe/nan/nan_datapath.c | 2 + 6 files changed, 206 insertions(+) diff --git a/components/nan/core/src/nan_main_i.h b/components/nan/core/src/nan_main_i.h index 4e0b76fc8bc4..63e1ef12183b 100644 --- a/components/nan/core/src/nan_main_i.h +++ b/components/nan/core/src/nan_main_i.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. 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 @@ -150,6 +151,8 @@ struct nan_psoc_priv_obj { * @disable_context: Disable all NDP's operation context * @ndp_init_done: Flag to indicate NDP initialization complete after first peer * connection. + * @peer_mc_addr_list: Peer multicast address list + * @num_peer_mc_addr: Number of entries in peer multicast list */ struct nan_vdev_priv_obj { qdf_spinlock_t lock; @@ -162,6 +165,8 @@ struct nan_vdev_priv_obj { struct qdf_mac_addr primary_peer_mac; void *disable_context; bool ndp_init_done; + struct qdf_mac_addr *peer_mc_addr_list; + uint8_t num_peer_mc_addr; }; /** diff --git a/components/nan/dispatcher/inc/nan_ucfg_api.h b/components/nan/dispatcher/inc/nan_ucfg_api.h index b7e872dcec01..c1949f4f4ce7 100644 --- a/components/nan/dispatcher/inc/nan_ucfg_api.h +++ b/components/nan/dispatcher/inc/nan_ucfg_api.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. 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 @@ -92,6 +93,39 @@ QDF_STATUS ucfg_nan_set_active_peers(struct wlan_objmgr_vdev *vdev, */ uint32_t ucfg_nan_get_active_peers(struct wlan_objmgr_vdev *vdev); +/** + * ucfg_nan_set_peer_mc_list: API to derive peer multicast address and add it + * to the list + * @vdev: pointer to vdev object + * @peer_mac_addr: Peer MAC address + * + * Return: None + */ +void ucfg_nan_set_peer_mc_list(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr peer_mac_addr); + +/** + * ucfg_nan_get_peer_mc_list: API to get peer multicast address list + * @vdev: pointer to vdev object + * @peer_mc_addr_list: Out pointer to the peer multicast address list + * + * Return: None + */ +void ucfg_nan_get_peer_mc_list(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr **peer_mc_addr_list); + +/** + * ucfg_nan_clear_peer_mc_list: Clear peer multicast address list + * @psoc: pointer to psoc object + * @vdev: pointer to vdev object + * @peer_mac_addr: Pointer to peer MAC address + * + * Return: None + */ +void ucfg_nan_clear_peer_mc_list(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *peer_mac_addr); + /** * ucfg_nan_set_ndp_create_transaction_id: set ndp create transaction id * @vdev: pointer to vdev object @@ -624,5 +658,11 @@ static inline bool ucfg_get_disable_6g_nan(struct wlan_objmgr_psoc *psoc) { return true; } + +static inline void +ucfg_nan_get_peer_mc_list(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr **peer_mc_addr_list) +{ +} #endif /* WLAN_FEATURE_NAN */ #endif /* _NAN_UCFG_API_H_ */ diff --git a/components/nan/dispatcher/src/nan_ucfg_api.c b/components/nan/dispatcher/src/nan_ucfg_api.c index 5c7c314336fe..ad3b4bf4b12c 100644 --- a/components/nan/dispatcher/src/nan_ucfg_api.c +++ b/components/nan/dispatcher/src/nan_ucfg_api.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. 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 @@ -33,6 +34,7 @@ #include "cfg_ucfg_api.h" #include "cfg_nan.h" #include "wlan_mlme_api.h" +#include "cfg_nan_api.h" struct wlan_objmgr_psoc; struct wlan_objmgr_vdev; @@ -183,6 +185,108 @@ inline QDF_STATUS ucfg_nan_set_active_peers(struct wlan_objmgr_vdev *vdev, return QDF_STATUS_SUCCESS; } +inline void ucfg_nan_set_peer_mc_list(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr peer_mac_addr) +{ + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + uint32_t max_ndp_sessions = 0; + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); + int i, list_idx = 0; + + if (!priv_obj) { + nan_err("priv_obj is null"); + return; + } + + if (!psoc) { + nan_err("psoc is null"); + return; + } + + qdf_spin_lock_bh(&priv_obj->lock); + if (!priv_obj->peer_mc_addr_list) { + cfg_nan_get_ndp_max_sessions(psoc, &max_ndp_sessions); + + priv_obj->peer_mc_addr_list = + qdf_mem_malloc(max_ndp_sessions * + sizeof(struct qdf_mac_addr)); + if (!priv_obj->peer_mc_addr_list) { + nan_err("Failed to allocate multicast address list"); + goto end; + } + priv_obj->num_peer_mc_addr = 0; + } else { + for (i = 0; i < max_ndp_sessions; i++) { + if (qdf_is_macaddr_zero( + &priv_obj->peer_mc_addr_list[i])) { + list_idx = i; + break; + } + } + if (list_idx == max_ndp_sessions) { + nan_err("Peer multicast address list is full"); + goto end; + } + } + /* Derive peer multicast addr */ + peer_mac_addr.bytes[0] = 0x33; + peer_mac_addr.bytes[1] = 0x33; + peer_mac_addr.bytes[2] = 0xff; + priv_obj->peer_mc_addr_list[list_idx] = peer_mac_addr; + priv_obj->num_peer_mc_addr++; + +end: + qdf_spin_unlock_bh(&priv_obj->lock); +} + +inline void ucfg_nan_get_peer_mc_list( + struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr **peer_mc_addr_list) +{ + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return; + } + + *peer_mc_addr_list = priv_obj->peer_mc_addr_list; +} + +inline void ucfg_nan_clear_peer_mc_list(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *peer_mac_addr) +{ + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + int i; + uint32_t max_ndp_sessions = 0; + + if (!priv_obj) { + nan_err("priv_obj is null"); + return; + } + + qdf_spin_lock_bh(&priv_obj->lock); + if (priv_obj->peer_mc_addr_list) { + cfg_nan_get_ndp_max_sessions(psoc, &max_ndp_sessions); + for (i = 0; i < max_ndp_sessions; i++) { + if (qdf_is_macaddr_equal( + &priv_obj->peer_mc_addr_list[i], + peer_mac_addr)) { + qdf_zero_macaddr( + &priv_obj->peer_mc_addr_list[i]); + priv_obj->num_peer_mc_addr--; + break; + } + } + if (priv_obj->num_peer_mc_addr == 0) { + qdf_mem_free(priv_obj->peer_mc_addr_list); + priv_obj->peer_mc_addr_list = NULL; + } + } + qdf_spin_unlock_bh(&priv_obj->lock); +} + inline uint32_t ucfg_nan_get_active_peers(struct wlan_objmgr_vdev *vdev) { uint32_t val; diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index f2e1ad0987d5..44873ffca6ef 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -4892,6 +4892,54 @@ void wlan_hdd_release_intf_addr(struct hdd_context *hdd_ctx, QDF_MAC_ADDR_REF(releaseAddr)); } +/** + * hdd_set_derived_multicast_list(): Add derived peer multicast address list in + * multicast list request to the FW + * @psoc: Pointer to psoc + * @adapter: Pointer to hdd adapter + * @mc_list_request: Multicast list request to the FW + * @mc_count: number of multicast addresses received from the kernel + * + * Return: None + */ +static void +hdd_set_derived_multicast_list(struct wlan_objmgr_psoc *psoc, + struct hdd_adapter *adapter, + struct pmo_mc_addr_list_params *mc_list_request, + int *mc_count) +{ + int i = 0, j = 0, list_count = *mc_count; + struct qdf_mac_addr *peer_mc_addr_list = NULL; + uint8_t driver_mc_cnt = 0; + uint32_t max_ndp_sessions = 0; + + cfg_nan_get_ndp_max_sessions(psoc, &max_ndp_sessions); + + ucfg_nan_get_peer_mc_list(adapter->vdev, &peer_mc_addr_list); + + for (j = 0; j < max_ndp_sessions; j++) { + for (i = 0; i < list_count; i++) { + if (qdf_is_macaddr_zero(&peer_mc_addr_list[j]) || + qdf_is_macaddr_equal(&mc_list_request->mc_addr[i], + &peer_mc_addr_list[j])) + break; + } + if (i == list_count) { + qdf_mem_copy( + &(mc_list_request->mc_addr[list_count + + driver_mc_cnt].bytes), + peer_mc_addr_list[j].bytes, ETH_ALEN); + hdd_debug("mlist[%d] = " QDF_MAC_ADDR_FMT, + list_count + driver_mc_cnt, + QDF_MAC_ADDR_REF( + mc_list_request->mc_addr[list_count + + driver_mc_cnt].bytes)); + driver_mc_cnt++; + } + } + *mc_count += driver_mc_cnt; +} + /** * __hdd_set_multicast_list() - set the multicast address list * @dev: Pointer to the WLAN device. @@ -4967,6 +5015,11 @@ static void __hdd_set_multicast_list(struct net_device *dev) QDF_MAC_ADDR_REF(mc_list_request->mc_addr[i].bytes)); i++; } + + if (adapter->device_mode == QDF_NDI_MODE) + hdd_set_derived_multicast_list(psoc, adapter, + mc_list_request, + &mc_count); } adapter->mc_addr_list.mc_cnt = mc_count; diff --git a/core/hdd/src/wlan_hdd_nan_datapath.c b/core/hdd/src/wlan_hdd_nan_datapath.c index 3bddacd15109..95d4278fee54 100644 --- a/core/hdd/src/wlan_hdd_nan_datapath.c +++ b/core/hdd/src/wlan_hdd_nan_datapath.c @@ -1047,6 +1047,8 @@ void hdd_ndp_peer_departed_handler(uint8_t vdev_id, uint16_t sta_id, if (last_peer) { hdd_debug("No more ndp peers."); + ucfg_nan_clear_peer_mc_list(hdd_ctx->psoc, adapter->vdev, + peer_mac_addr); hdd_cleanup_ndi(hdd_ctx, adapter); qdf_event_set(&adapter->peer_cleanup_done); /* diff --git a/core/mac/src/pe/nan/nan_datapath.c b/core/mac/src/pe/nan/nan_datapath.c index f20e53801460..07375fcb07f1 100644 --- a/core/mac/src/pe/nan/nan_datapath.c +++ b/core/mac/src/pe/nan/nan_datapath.c @@ -74,6 +74,8 @@ static QDF_STATUS lim_add_ndi_peer(struct mac_context *mac_ctx, pe_info("Need to create NDI Peer :" QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(peer_mac_addr.bytes)); + ucfg_nan_set_peer_mc_list(session->vdev, peer_mac_addr); + peer_idx = lim_assign_peer_idx(mac_ctx, session); if (!peer_idx) { pe_err("Invalid peer_idx: %d", peer_idx);