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:
Rachit Kankane 2017-04-19 11:49:18 +05:30 • committed by snandini
commit 4475ff297c
10 changed files with 399 additions and 12 deletions

View file

@ -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_ */

View file

@ -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, &param);
}
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 =

View file

@ -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,
};
/**

View file

@ -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 */

View file

@ -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

View file

@ -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,

View file

@ -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");
}

View file

@ -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;
};
/**

View file

@ -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_ */

View file

@ -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;
}