mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-11-10 12:52:37 -05:00
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
This commit is contained in:
parent
152c87421e
commit
3abaf942a0
4 changed files with 347 additions and 4 deletions
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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_ */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue