From 4475ff297c6bfdfa03b80591fe0e27998d0c87dc Mon Sep 17 00:00:00 2001 From: Rachit Kankane Date: Wed, 19 Apr 2017 11:49:18 +0530 Subject: [PATCH] qcacmn: P2P protocol changes to Disable/Enable NOA P2P-GO whenever goes offchannel, issues NOA. With this behavior, we have issue whenever legacy STA connects to P2P-GO since legacy STA does not understand NOA. To handle this case, changes are done in p2p protocol component and the revised behavior will be: 1. By default no change in NOA. 2. Whenever first legacy STA connects to GO, p2p protocol component disables NOA (i.e. P2P-GO will issue Self-CTS whenever it goes off-channel). 3. Whenever last legacy STA disconnects from GO, p2p protocol component enables NOA (i.e. P2P-GO will issue NOA whenever it goes off-channel). Change-Id: I113950ac3fa99ca68fcafcfe4c6095cf4b2def43 CRs-Fixed: 2035609 --- target_if/p2p/inc/target_if_p2p.h | 13 + target_if/p2p/src/target_if_p2p.c | 21 ++ umac/cmn_services/inc/wlan_cmn.h | 14 +- .../obj_mgr/src/wlan_objmgr_peer_obj.c | 3 +- .../obj_mgr/src/wlan_objmgr_vdev_obj.c | 6 +- .../lmac_if/inc/wlan_lmac_if_def.h | 3 + umac/p2p/core/src/wlan_p2p_main.c | 241 ++++++++++++++++++ umac/p2p/core/src/wlan_p2p_main.h | 12 +- umac/p2p/dispatcher/inc/wlan_p2p_ucfg_api.h | 25 ++ umac/p2p/dispatcher/src/wlan_p2p_ucfg_api.c | 73 ++++++ 10 files changed, 399 insertions(+), 12 deletions(-) diff --git a/target_if/p2p/inc/target_if_p2p.h b/target_if/p2p/inc/target_if_p2p.h index 9d3c33583a53..dcb46b9519e9 100644 --- a/target_if/p2p/inc/target_if_p2p.h +++ b/target_if/p2p/inc/target_if_p2p.h @@ -121,4 +121,17 @@ QDF_STATUS target_if_p2p_lo_start(struct wlan_objmgr_psoc *psoc, QDF_STATUS target_if_p2p_lo_stop(struct wlan_objmgr_psoc *psoc, uint32_t vdev_id); +/** + * target_if_p2p_set_noa() - Disable / Enable NOA + * @psoc: soc object + * @vdev_id: vdev id + * @disable_noa: TRUE - Disable NoA, FALSE - Enable NoA + * + * Target interface API to Disable / Enable P2P NOA. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS target_if_p2p_set_noa(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, bool disable_noa); + #endif /* _TARGET_IF_P2P_H_ */ diff --git a/target_if/p2p/src/target_if_p2p.c b/target_if/p2p/src/target_if_p2p.c index c19fea4605cb..70680ecab1be 100644 --- a/target_if/p2p/src/target_if_p2p.c +++ b/target_if/p2p/src/target_if_p2p.c @@ -326,6 +326,26 @@ QDF_STATUS target_if_p2p_lo_stop(struct wlan_objmgr_psoc *psoc, (uint8_t)vdev_id); } +QDF_STATUS target_if_p2p_set_noa(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, bool disable_noa) +{ + struct vdev_set_params param; + wmi_unified_t wmi_handle = wlan_psoc_get_tgt_if_handle(psoc); + + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + target_if_debug("psoc:%p, vdev_id:%d disable_noa:%d", + psoc, vdev_id, disable_noa); + param.if_id = vdev_id; + param.param_id = WMI_VDEV_PARAM_DISABLE_NOA_P2P_GO; + param.param_value = (uint32_t)disable_noa; + + return wmi_unified_vdev_set_param_send(wmi_handle, ¶m); +} + void target_if_p2p_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) { struct wlan_lmac_if_p2p_tx_ops *p2p_tx_ops; @@ -339,6 +359,7 @@ void target_if_p2p_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) p2p_tx_ops->set_ps = target_if_p2p_set_ps; p2p_tx_ops->lo_start = target_if_p2p_lo_start; p2p_tx_ops->lo_stop = target_if_p2p_lo_stop; + p2p_tx_ops->set_noa = target_if_p2p_set_noa; p2p_tx_ops->reg_lo_ev_handler = target_if_p2p_register_lo_event_handler; p2p_tx_ops->reg_noa_ev_handler = diff --git a/umac/cmn_services/inc/wlan_cmn.h b/umac/cmn_services/inc/wlan_cmn.h index e5484f1c5933..9f771b60bfc3 100644 --- a/umac/cmn_services/inc/wlan_cmn.h +++ b/umac/cmn_services/inc/wlan_cmn.h @@ -198,7 +198,9 @@ enum wlan_phymode { * enum wlan_peer_type - peer type * @WLAN_PEER_SELF: for AP mode, SELF PEER or AP PEER are same * @WLAN_PEER_AP: BSS peer for STA mode, Self peer for AP mode + * @WLAN_PEER_P2P_GO: BSS peer for P2P CLI mode, Self peer for P2P GO mode * @WLAN_PEER_STA: Self Peer for STA mode, STA peer for AP mode + * @WLAN_PEER_P2P_CLI: Self peer for P2P CLI mode, P2P CLI peer for P2P GO mode * @WLAN_PEER_TDLS: TDLS Peer * @WLAN_PEER_NAWDS: NAWDS Peer * @WLAN_PEER_STA_TEMP: STA Peer Temp (its host only node) @@ -207,11 +209,13 @@ enum wlan_phymode { enum wlan_peer_type { WLAN_PEER_SELF = 1, WLAN_PEER_AP = 2, - WLAN_PEER_STA = 3, - WLAN_PEER_TDLS = 4, - WLAN_PEER_NAWDS = 5, - WLAN_PEER_STA_TEMP = 6, - WLAN_PEER_IBSS = 7, + WLAN_PEER_P2P_GO = 3, + WLAN_PEER_STA = 4, + WLAN_PEER_P2P_CLI = 5, + WLAN_PEER_TDLS = 6, + WLAN_PEER_NAWDS = 7, + WLAN_PEER_STA_TEMP = 8, + WLAN_PEER_IBSS = 9, }; /** diff --git a/umac/cmn_services/obj_mgr/src/wlan_objmgr_peer_obj.c b/umac/cmn_services/obj_mgr/src/wlan_objmgr_peer_obj.c index bc130c09d7a5..7eb5692dd337 100644 --- a/umac/cmn_services/obj_mgr/src/wlan_objmgr_peer_obj.c +++ b/umac/cmn_services/obj_mgr/src/wlan_objmgr_peer_obj.c @@ -164,7 +164,8 @@ struct wlan_objmgr_peer *wlan_objmgr_peer_obj_create( qdf_spinlock_create(&peer->peer_lock); wlan_objmgr_peer_get_ref(peer, WLAN_OBJMGR_ID); /* Increment ref count for BSS peer, so that BSS peer deletes last*/ - if ((type == WLAN_PEER_STA) || (type == WLAN_PEER_STA_TEMP)) + if ((type == WLAN_PEER_STA) || (type == WLAN_PEER_STA_TEMP) + || (type == WLAN_PEER_P2P_CLI)) wlan_objmgr_peer_get_ref(wlan_vdev_get_bsspeer(vdev), WLAN_OBJMGR_ID); /* TODO init other parameters */ diff --git a/umac/cmn_services/obj_mgr/src/wlan_objmgr_vdev_obj.c b/umac/cmn_services/obj_mgr/src/wlan_objmgr_vdev_obj.c index fe6732e51a04..510610a42c93 100644 --- a/umac/cmn_services/obj_mgr/src/wlan_objmgr_vdev_obj.c +++ b/umac/cmn_services/obj_mgr/src/wlan_objmgr_vdev_obj.c @@ -580,7 +580,8 @@ QDF_STATUS wlan_objmgr_vdev_peer_attach(struct wlan_objmgr_vdev *vdev, wlan_obj_vdev_peerlist_add_tail(&objmgr->wlan_peer_list, peer); objmgr->wlan_peer_count++; - if (wlan_peer_get_peer_type(peer) == WLAN_PEER_AP) { + if ((wlan_peer_get_peer_type(peer) == WLAN_PEER_AP) || + (wlan_peer_get_peer_type(peer) == WLAN_PEER_P2P_GO)) { if (WLAN_ADDR_EQ(wlan_peer_get_macaddr(peer), wlan_vdev_mlme_get_macaddr(vdev)) == QDF_STATUS_SUCCESS) { @@ -615,7 +616,8 @@ QDF_STATUS wlan_objmgr_vdev_peer_detach(struct wlan_objmgr_vdev *vdev, return QDF_STATUS_E_FAILURE; } - if (wlan_peer_get_peer_type(peer) == WLAN_PEER_AP) { + if ((wlan_peer_get_peer_type(peer) == WLAN_PEER_AP) || + (wlan_peer_get_peer_type(peer) == WLAN_PEER_P2P_GO)) { if (wlan_vdev_get_selfpeer(vdev) == peer) { /* * There might be instances where new node is created diff --git a/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h b/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h index 1070ad09ed8f..0955c3b46acb 100644 --- a/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h +++ b/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h @@ -253,6 +253,7 @@ struct p2p_lo_start; * @set_ps: function pointer to set power save * @lo_start: function pointer to start listen offload * @lo_stop: function pointer to stop listen offload + * @set_noa: function pointer to disable/enable NOA * @reg_lo_ev_handler: function pointer to register lo event handler * @reg_noa_ev_handler: function pointer to register noa event handler * @unreg_lo_ev_handler: function pointer to unregister lo event handler @@ -265,6 +266,8 @@ struct wlan_lmac_if_p2p_tx_ops { struct p2p_lo_start *lo_start); QDF_STATUS (*lo_stop)(struct wlan_objmgr_psoc *psoc, uint32_t vdev_id); + QDF_STATUS (*set_noa)(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, bool disable_noa); QDF_STATUS (*reg_lo_ev_handler)(struct wlan_objmgr_psoc *psoc, void *arg); QDF_STATUS (*reg_noa_ev_handler)(struct wlan_objmgr_psoc *psoc, diff --git a/umac/p2p/core/src/wlan_p2p_main.c b/umac/p2p/core/src/wlan_p2p_main.c index bc613c69b657..9084c75bf2a5 100644 --- a/umac/p2p/core/src/wlan_p2p_main.c +++ b/umac/p2p/core/src/wlan_p2p_main.c @@ -211,6 +211,8 @@ static QDF_STATUS p2p_vdev_obj_create_notification( } p2p_vdev_obj->vdev = vdev; + p2p_vdev_obj->noa_status = true; + p2p_vdev_obj->non_p2p_peer_count = 0; status = wlan_objmgr_vdev_component_obj_attach(vdev, WLAN_UMAC_COMP_P2P, p2p_vdev_obj, @@ -285,6 +287,127 @@ static QDF_STATUS p2p_vdev_obj_destroy_notification( return QDF_STATUS_SUCCESS; } +/** + * p2p_peer_obj_create_notification() - manages peer details per vdev + * @peer: peer object + * @arg: Pointer to private argument - NULL + * + * This function gets called from object manager when peer is being + * created. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_peer_obj_create_notification( + struct wlan_objmgr_peer *peer, void *arg) +{ + struct wlan_objmgr_vdev *vdev; + struct p2p_vdev_priv_obj *p2p_vdev_obj; + enum tQDF_ADAPTER_MODE mode; + enum wlan_peer_type peer_type; + + if (!peer) { + p2p_err("peer context passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + wlan_peer_obj_lock(peer); + vdev = wlan_peer_get_vdev(peer); + wlan_peer_obj_unlock(peer); + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_P2P); + wlan_peer_obj_lock(peer); + peer_type = wlan_peer_get_peer_type(peer); + wlan_peer_obj_unlock(peer); + if ((peer_type == WLAN_PEER_STA) && p2p_vdev_obj) { + + wlan_vdev_obj_lock(vdev); + mode = wlan_vdev_mlme_get_opmode(vdev); + wlan_vdev_obj_unlock(vdev); + if (mode == QDF_P2P_GO_MODE) { + p2p_vdev_obj->non_p2p_peer_count++; + p2p_debug("Non P2P peer count: %d", + p2p_vdev_obj->non_p2p_peer_count); + } + } + p2p_debug("p2p peer object create successful"); + + return QDF_STATUS_SUCCESS; +} + +/** + * p2p_peer_obj_destroy_notification() - clears peer details per vdev + * @peer: peer object + * @arg: Pointer to private argument - NULL + * + * This function gets called from object manager when peer is being + * destroyed. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_peer_obj_destroy_notification( + struct wlan_objmgr_peer *peer, void *arg) +{ + struct wlan_objmgr_vdev *vdev; + struct p2p_vdev_priv_obj *p2p_vdev_obj; + struct wlan_objmgr_psoc *psoc; + enum tQDF_ADAPTER_MODE mode; + enum wlan_peer_type peer_type; + uint8_t vdev_id; + + if (!peer) { + p2p_err("peer context passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + wlan_peer_obj_lock(peer); + vdev = wlan_peer_get_vdev(peer); + wlan_peer_obj_unlock(peer); + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_P2P); + wlan_vdev_obj_lock(vdev); + psoc = wlan_vdev_get_psoc(vdev); + wlan_vdev_obj_unlock(vdev); + if (!p2p_vdev_obj || !psoc) { + p2p_err("p2p_vdev_obj:%p psoc:%p", p2p_vdev_obj, psoc); + return QDF_STATUS_E_INVAL; + } + + wlan_vdev_obj_lock(vdev); + mode = wlan_vdev_mlme_get_opmode(vdev); + wlan_vdev_obj_unlock(vdev); + + wlan_peer_obj_lock(peer); + peer_type = wlan_peer_get_peer_type(peer); + wlan_peer_obj_unlock(peer); + + if ((peer_type == WLAN_PEER_STA) && (mode == QDF_P2P_GO_MODE)) { + + p2p_vdev_obj->non_p2p_peer_count--; + + if (!p2p_vdev_obj->non_p2p_peer_count && + (p2p_vdev_obj->noa_status == false)) { + + wlan_vdev_obj_lock(vdev); + vdev_id = wlan_vdev_get_id(vdev); + wlan_vdev_obj_unlock(vdev); + + if (ucfg_p2p_set_noa(psoc, vdev_id, + false) == QDF_STATUS_SUCCESS) + p2p_vdev_obj->noa_status = true; + else + p2p_vdev_obj->noa_status = false; + + p2p_debug("Non p2p peer disconnected from GO,NOA status: %d.", + p2p_vdev_obj->noa_status); + } + p2p_debug("Non P2P peer count: %d", + p2p_vdev_obj->non_p2p_peer_count); + } + p2p_debug("p2p peer object destroy successful"); + + return QDF_STATUS_SUCCESS; +} + /** * p2p_send_noa_to_pe() - send noa information to pe * @noa_info: vdev context @@ -348,6 +471,68 @@ static QDF_STATUS p2p_send_noa_to_pe(struct p2p_noa_info *noa_info) return QDF_STATUS_SUCCESS; } +/** + * process_peer_for_noa() - disable NoA + * @vdev: vdev object + * @psoc: soc object + * @peer: peer object + * + * This function disables NoA + * + * + * Return: QDF_STATUS + */ +static QDF_STATUS process_peer_for_noa(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_peer *peer) +{ + struct p2p_vdev_priv_obj *p2p_vdev_obj = NULL; + enum tQDF_ADAPTER_MODE mode; + enum wlan_peer_type peer_type; + bool disable_noa; + uint8_t vdev_id; + + if (!vdev || !psoc || !peer) { + p2p_err("vdev:%p psoc:%p peer:%p", vdev, psoc, peer); + return QDF_STATUS_E_INVAL; + } + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_P2P); + if (!p2p_vdev_obj) { + p2p_err("p2p_vdev_obj:%p", p2p_vdev_obj); + return QDF_STATUS_E_INVAL; + } + wlan_vdev_obj_lock(vdev); + mode = wlan_vdev_mlme_get_opmode(vdev); + wlan_vdev_obj_unlock(vdev); + + wlan_peer_obj_lock(peer); + peer_type = wlan_peer_get_peer_type(peer); + wlan_peer_obj_unlock(peer); + + disable_noa = ((mode == QDF_P2P_GO_MODE) + && p2p_vdev_obj->non_p2p_peer_count + && p2p_vdev_obj->noa_status); + + if (disable_noa && (peer_type == WLAN_PEER_STA)) { + + wlan_vdev_obj_lock(vdev); + vdev_id = wlan_vdev_get_id(vdev); + wlan_vdev_obj_unlock(vdev); + + if (ucfg_p2p_set_noa(psoc, vdev_id, + true) == QDF_STATUS_SUCCESS) { + p2p_vdev_obj->noa_status = false; + } else { + p2p_vdev_obj->noa_status = true; + } + p2p_debug("NoA status: %d", p2p_vdev_obj->noa_status); + } + p2p_debug("process_peer_for_noa"); + + return QDF_STATUS_SUCCESS; +} + QDF_STATUS p2p_component_init(void) { QDF_STATUS status; @@ -388,9 +573,33 @@ QDF_STATUS p2p_component_init(void) goto err_reg_vdev_delete; } + status = wlan_objmgr_register_peer_create_handler( + WLAN_UMAC_COMP_P2P, + p2p_peer_obj_create_notification, + NULL); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("Failed to register p2p peer create handler"); + goto err_reg_peer_create; + } + + status = wlan_objmgr_register_peer_destroy_handler( + WLAN_UMAC_COMP_P2P, + p2p_peer_obj_destroy_notification, + NULL); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("Failed to register p2p peer destroy handler"); + goto err_reg_peer_destroy; + } + p2p_debug("Register p2p obj handler successful"); return QDF_STATUS_SUCCESS; +err_reg_peer_destroy: + wlan_objmgr_unregister_peer_create_handler(WLAN_UMAC_COMP_P2P, + p2p_peer_obj_create_notification, NULL); +err_reg_peer_create: + wlan_objmgr_unregister_vdev_destroy_handler(WLAN_UMAC_COMP_P2P, + p2p_vdev_obj_destroy_notification, NULL); err_reg_vdev_delete: wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_P2P, p2p_vdev_obj_create_notification, NULL); @@ -810,3 +1019,35 @@ fail: return status; } + +void p2p_peer_authorized(struct wlan_objmgr_vdev *vdev, uint8_t *mac_addr) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_peer *peer; + + if (!vdev) { + p2p_err("vdev:%p", vdev); + return; + } + wlan_vdev_obj_lock(vdev); + psoc = wlan_vdev_get_psoc(vdev); + wlan_vdev_obj_unlock(vdev); + if (!psoc) { + p2p_err("psoc:%p", psoc); + return; + } + peer = wlan_objmgr_get_peer(psoc, mac_addr, WLAN_P2P_ID); + if (!peer) { + p2p_debug("peer info not found"); + return; + } + status = process_peer_for_noa(vdev, psoc, peer); + wlan_objmgr_peer_release_ref(peer, WLAN_P2P_ID); + + if (status != QDF_STATUS_SUCCESS) { + p2p_err("status:%u", status); + return; + } + p2p_debug("peer is authorized"); +} diff --git a/umac/p2p/core/src/wlan_p2p_main.h b/umac/p2p/core/src/wlan_p2p_main.h index c13068c805d2..9aabc6a5448d 100644 --- a/umac/p2p/core/src/wlan_p2p_main.h +++ b/umac/p2p/core/src/wlan_p2p_main.h @@ -154,12 +154,16 @@ struct p2p_soc_priv_obj { /** * struct p2p_vdev_priv_obj - Per vdev p2p private object - * @vdev: Pointer to vdev context - * @noa_info: NoA information + * @vdev: Pointer to vdev context + * @noa_info: NoA information + * @noa_status: NoA status i.e. Enabled / Disabled (TRUE/FALSE) + * @non_p2p_peer_count: Number of legacy stations connected to this GO */ struct p2p_vdev_priv_obj { - struct wlan_objmgr_vdev *vdev; - struct p2p_noa_info *noa_info; + struct wlan_objmgr_vdev *vdev; + struct p2p_noa_info *noa_info; + bool noa_status; + uint16_t non_p2p_peer_count; }; /** diff --git a/umac/p2p/dispatcher/inc/wlan_p2p_ucfg_api.h b/umac/p2p/dispatcher/inc/wlan_p2p_ucfg_api.h index 185d9491c077..6e861307f89c 100644 --- a/umac/p2p/dispatcher/inc/wlan_p2p_ucfg_api.h +++ b/umac/p2p/dispatcher/inc/wlan_p2p_ucfg_api.h @@ -262,4 +262,29 @@ QDF_STATUS ucfg_p2p_lo_start(struct wlan_objmgr_psoc *soc, QDF_STATUS ucfg_p2p_lo_stop(struct wlan_objmgr_psoc *soc, uint32_t vdev_id); +/** + * p2p_peer_authorized() - Process peer authorized event + * @vdev: vdev structure to which peer is associated + * @mac_addr: peer mac address + * + * This function handles disables noa whenever a legacy station + * complete 4-way handshake after association. + * + * Return: void + */ +void p2p_peer_authorized(struct wlan_objmgr_vdev *vdev, uint8_t *mac_addr); + +/** + * ucfg_p2p_set_noa() - Disable/Enable NOA + * @soc: soc context + * @vdev_id: vdev id + * @disable_noa: TRUE - Disable NoA, FALSE - Enable NoA + * + * This function send wmi command to enable / disable NoA. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_p2p_set_noa(struct wlan_objmgr_psoc *soc, + uint32_t vdev_id, bool disable_noa); + #endif /* _WLAN_P2P_UCFG_API_H_ */ diff --git a/umac/p2p/dispatcher/src/wlan_p2p_ucfg_api.c b/umac/p2p/dispatcher/src/wlan_p2p_ucfg_api.c index 543ef5417f8d..4278d8cb783e 100644 --- a/umac/p2p/dispatcher/src/wlan_p2p_ucfg_api.c +++ b/umac/p2p/dispatcher/src/wlan_p2p_ucfg_api.c @@ -35,6 +35,48 @@ ucfg_p2p_psoc_get_tx_ops(struct wlan_objmgr_psoc *psoc) return &(psoc->soc_cb.tx_ops.p2p); } +/** + * is_p2p_ps_allowed() - If P2P power save is allowed or not + * @vdev: vdev object + * @id: umac component id + * + * This function returns TRUE if P2P power-save is allowed + * else returns FALSE. + * + * Return: bool + */ +static bool is_p2p_ps_allowed(struct wlan_objmgr_vdev *vdev, + enum wlan_umac_comp_id id) +{ + struct p2p_vdev_priv_obj *p2p_vdev_obj; + uint8_t is_p2pgo = 0; + + if (!vdev) { + p2p_err("vdev:%p", vdev); + return true; + } + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_P2P); + + if (wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_GO_MODE) + is_p2pgo = 1; + + if (!p2p_vdev_obj || !is_p2pgo) { + p2p_err("p2p_vdev_obj:%p is_p2pgo:%u", + p2p_vdev_obj, is_p2pgo); + return false; + } + if (p2p_vdev_obj->non_p2p_peer_count && + p2p_vdev_obj->noa_status == false) { + p2p_debug("non_p2p_peer_count: %u, noa_status: %d", + p2p_vdev_obj->non_p2p_peer_count, + p2p_vdev_obj->noa_status); + return false; + } + + return true; +} + QDF_STATUS ucfg_p2p_init(void) { return p2p_component_init(); @@ -249,6 +291,8 @@ QDF_STATUS ucfg_p2p_set_ps(struct wlan_objmgr_psoc *soc, { struct wlan_lmac_if_p2p_tx_ops *p2p_ops; QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint16_t obj_id; + struct wlan_objmgr_vdev *vdev; p2p_debug("soc:%p, vdev_id:%d, opp_ps:%d, ct_window:%d, count:%d, duration:%d, duration:%d, ps_selection:%d", soc, ps_config->vdev_id, ps_config->opp_ps, @@ -261,6 +305,20 @@ QDF_STATUS ucfg_p2p_set_ps(struct wlan_objmgr_psoc *soc, return QDF_STATUS_E_INVAL; } + for (obj_id = 0; obj_id < WLAN_UMAC_PSOC_MAX_VDEVS; obj_id++) { + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(soc, obj_id, + WLAN_P2P_ID); + if (vdev) { + if (is_p2p_ps_allowed(vdev, + WLAN_UMAC_COMP_P2P) == false) { + p2p_debug("p2p set ps, NoA is disabled as legacy STA is connected to GO."); + return QDF_STATUS_E_BUSY; + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + } + } + p2p_ops = ucfg_p2p_psoc_get_tx_ops(soc); if (p2p_ops->set_ps) { status = p2p_ops->set_ps(soc, ps_config); @@ -318,3 +376,18 @@ QDF_STATUS ucfg_p2p_lo_stop(struct wlan_objmgr_psoc *soc, return status; } + +QDF_STATUS ucfg_p2p_set_noa(struct wlan_objmgr_psoc *soc, + uint32_t vdev_id, bool disable_noa) +{ + struct wlan_lmac_if_p2p_tx_ops *p2p_ops; + QDF_STATUS status = QDF_STATUS_E_INVAL; + + p2p_ops = ucfg_p2p_psoc_get_tx_ops(soc); + if (p2p_ops->set_noa) { + status = p2p_ops->set_noa(soc, vdev_id, disable_noa); + p2p_debug("p2p set noa, status:%d", status); + } + + return status; +}