qcacmn: TDLS component: core peer operations

TDLS peer operations: add, delete and update TDLS peer

Change-Id: I7dba1a4b2b3b8597935db811da68ee5ba630bf4d
CRs-Fixed: 2011330
This commit is contained in:
Frank Liu 2017-03-13 21:30:21 +08:00 • committed by Sandeep Puligilla
commit d4b12dbff6
9 changed files with 2923 additions and 83 deletions

File diff suppressed because it is too large Load diff

View file

@ -21,3 +21,177 @@
*
* TDLS north bound commands include file
*/
#ifndef _WLAN_TDLS_CMDS_PROCESS_H_
#define _WLAN_TDLS_CMDS_PROCESS_H_
/**
* enum tdls_add_oper - add peer type
* @TDLS_OPER_NONE: none
* @TDLS_OPER_ADD: add new peer
* @TDLS_OPER_UPDATE: used to update peer
*/
enum tdls_add_oper {
TDLS_OPER_NONE,
TDLS_OPER_ADD,
TDLS_OPER_UPDATE
};
/**
* struct tdls_add_sta_req - TDLS request struct TDLS module --> PE
* same as struct tSirTdlsAddStaReq;
* @message_type: eWNI_SME_TDLS_ADD_STA_REQ
* @length: message length
* @session_id: session id
* @transaction_id: transaction id for cmd
* @bssid: bssid
* @tdls_oper: add peer type
* @peermac: MAC address for TDLS peer
* @capability: mac capability as sSirMacCapabilityInfo
* @extn_capability: extent capability
* @supported_rates_length: rates length
* @supported_rates: supported rates
* @htcap_present: ht capability present
* @ht_cap: ht capability
* @vhtcap_present: vht capability present
* @vht_cap: vht capability
* @uapsd_queues: uapsd queue as sSirMacQosInfoStation
* @max_sp: maximum service period
*/
struct tdls_add_sta_req {
uint16_t message_type;
uint16_t length;
uint8_t session_id;
uint16_t transaction_id;
struct qdf_mac_addr bssid;
enum tdls_add_oper tdls_oper;
struct qdf_mac_addr peermac;
uint16_t capability;
uint8_t extn_capability[WLAN_MAC_MAX_EXTN_CAP];
uint8_t supported_rates_length;
uint8_t supported_rates[WLAN_MAC_MAX_SUPP_RATES];
uint8_t htcap_present;
struct htcap_cmn_ie ht_cap;
uint8_t vhtcap_present;
struct vhtcap vht_cap;
uint8_t uapsd_queues;
uint8_t max_sp;
};
/**
* struct tdls_add_sta_rsp - TDLS Response struct PE --> TDLS module
* same as struct sSirTdlsAddStaRsp
* @message_type: message type eWNI_SME_TDLS_ADD_STA_RSP
* @length: message length
* @status_code: status code as tSirResultCodes
* @peermac: MAC address of the TDLS peer
* @session_id: session id
* @sta_id: sta id
* @sta_type: sta type
* @ucast_sig: unicast signature
* @bcast_sig: broadcast signature
* @tdls_oper: add peer type
* @psoc: soc object
*/
struct tdls_add_sta_rsp {
uint16_t message_type;
uint16_t length;
QDF_STATUS status_code;
struct qdf_mac_addr peermac;
uint8_t session_id;
uint16_t sta_id;
uint16_t sta_type;
uint8_t ucast_sig;
uint8_t bcast_sig;
enum tdls_add_oper tdls_oper;
struct wlan_objmgr_psoc *psoc;
};
/**
* struct tdls_del_sta_req - TDLS Request struct TDLS module --> PE
* same as sSirTdlsDelStaReq
* @message_type: message type eWNI_SME_TDLS_DEL_STA_REQ
* @length: message length
* @session_id: session id
* @transaction_id: transaction id for cmd
* @bssid: bssid
* @peermac: MAC address of the TDLS peer
*/
struct tdls_del_sta_req {
uint16_t message_type;
uint16_t length;
uint8_t session_id;
uint16_t transaction_id;
struct qdf_mac_addr bssid;
struct qdf_mac_addr peermac;
};
/**
* struct tdls_del_sta_rsp - TDLS Response struct PE --> TDLS module
* same as sSirTdlsDelStaRsp
* @message_type: message type eWNI_SME_TDLS_DEL_STA_RSP
* @length: message length
* @session_id: session id
* @status_code: status code as tSirResultCodes
* @peermac: MAC address of the TDLS peer
* @sta_id: sta id
* @psoc: soc object
*/
struct tdls_del_sta_rsp {
uint16_t message_type;
uint16_t length;
uint8_t session_id;
QDF_STATUS status_code;
struct qdf_mac_addr peermac;
uint16_t sta_id;
struct wlan_objmgr_psoc *psoc;
};
/**
* tdls_process_add_peer() - add TDLS peer
* @req: TDLS add peer request
*
* Return: QDF_STATUS_SUCCESS if success; other value if failed
*/
QDF_STATUS tdls_process_add_peer(struct tdls_add_peer_request *req);
/**
* tdls_process_del_peer() - del TDLS peer
* @req: TDLS del peer request
*
* Return: QDF_STATUS_SUCCESS if success; other value if failed
*/
QDF_STATUS tdls_process_del_peer(struct tdls_oper_request *req);
/**
* tdls_process_update_peer() - update TDLS peer
* @req: TDLS update peer request
*
* Return: QDF_STATUS_SUCCESS if success; other value if failed
*/
QDF_STATUS tdls_process_update_peer(struct tdls_update_peer_request *req);
/**
* tdls_pe_del_peer() - send TDLS delete peer request to PE
* @req: TDLS delete peer request
*
* Return: QDF status
*/
QDF_STATUS tdls_pe_del_peer(struct tdls_del_peer_request *req);
/**
* tdls_process_add_peer_rsp() - handle response for add or update TDLS peer
* @rsp: TDLS add peer response
*
* Return: QDF status
*/
QDF_STATUS tdls_process_add_peer_rsp(struct tdls_add_sta_rsp *rsp);
/**
* tdls_process_add_peer_rsp() - handle response for delete TDLS peer
* @rsp: TDLS delete peer response
*
* Return: QDF status
*/
QDF_STATUS tdls_process_del_peer_rsp(struct tdls_del_sta_rsp *rsp);
#endif

View file

@ -23,6 +23,8 @@
*/
#include "wlan_tdls_main.h"
#include "wlan_tdls_cmds_process.h"
#include "wlan_tdls_peer.h"
QDF_STATUS tdls_psoc_obj_create_notification(struct wlan_objmgr_psoc *psoc,
void *arg_list)
@ -31,7 +33,7 @@ QDF_STATUS tdls_psoc_obj_create_notification(struct wlan_objmgr_psoc *psoc,
struct tdls_soc_priv_obj *tdls_soc_obj;
tdls_soc_obj = qdf_mem_malloc(sizeof(*tdls_soc_obj));
if (tdls_soc_obj == NULL) {
if (!tdls_soc_obj) {
tdls_err("Failed to allocate memory for tdls object");
return QDF_STATUS_E_NOMEM;
}
@ -61,7 +63,7 @@ QDF_STATUS tdls_psoc_obj_destroy_notification(struct wlan_objmgr_psoc *psoc,
tdls_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_TDLS);
if (tdls_soc_obj == NULL) {
if (!tdls_soc_obj) {
tdls_err("Failed to get tdls obj in psoc");
return QDF_STATUS_E_FAILURE;
}
@ -78,19 +80,53 @@ QDF_STATUS tdls_psoc_obj_destroy_notification(struct wlan_objmgr_psoc *psoc,
return status;
}
static void tdls_vdev_init(struct tdls_vdev_priv_obj *vdev)
static QDF_STATUS tdls_vdev_init(struct tdls_vdev_priv_obj *vdev_obj)
{
uint8_t i;
struct tdls_config_params *config;
struct tdls_user_config *user_config;
struct tdls_soc_priv_obj *soc_obj;
for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
qdf_list_create(&vdev->peer_list[i],
WLAN_TDLS_PEER_SUB_LIST_SIZE);
soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev);
if (!soc_obj) {
tdls_err("tdls soc obj NULL");
return QDF_STATUS_E_FAILURE;
}
qdf_mc_timer_init(&vdev->peer_update_timer, QDF_TIMER_TYPE_SW,
NULL, vdev);
qdf_mc_timer_init(&vdev->peer_update_timer, QDF_TIMER_TYPE_SW,
NULL, vdev);
config = &vdev_obj->threshold_config;
user_config = &soc_obj->tdls_configs;
config->tx_period_t = user_config->tdls_tx_states_period;
config->tx_packet_n = user_config->tdls_tx_pkt_threshold;
config->discovery_tries_n = user_config->tdls_max_discovery_attempt;
config->idle_timeout_t = user_config->tdls_idle_timeout;
config->idle_packet_n = user_config->tdls_idle_pkt_threshold;
config->rssi_trigger_threshold =
user_config->tdls_rssi_trigger_threshold;
config->rssi_teardown_threshold =
user_config->tdls_rssi_teardown_threshold;
config->rssi_delta = user_config->tdls_rssi_delta;
for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
qdf_list_create(&vdev_obj->peer_list[i],
WLAN_TDLS_PEER_SUB_LIST_SIZE);
}
qdf_mc_timer_init(&vdev_obj->peer_update_timer, QDF_TIMER_TYPE_SW,
NULL, vdev_obj);
qdf_mc_timer_init(&vdev_obj->peer_discovery_timer, QDF_TIMER_TYPE_SW,
NULL, vdev_obj);
return QDF_STATUS_SUCCESS;
}
static void tdls_vdev_deinit(struct tdls_vdev_priv_obj *vdev_obj)
{
qdf_mc_timer_stop(&vdev_obj->peer_update_timer);
qdf_mc_timer_stop(&vdev_obj->peer_discovery_timer);
qdf_mc_timer_destroy(&vdev_obj->peer_update_timer);
qdf_mc_timer_destroy(&vdev_obj->peer_discovery_timer);
tdls_peer_idle_timers_destroy(vdev_obj);
tdls_free_peer_list(vdev_obj);
}
QDF_STATUS tdls_vdev_obj_create_notification(struct wlan_objmgr_vdev *vdev,
@ -107,14 +143,11 @@ QDF_STATUS tdls_vdev_obj_create_notification(struct wlan_objmgr_vdev *vdev,
/* TODO: Add concurrency check */
tdls_vdev_obj = qdf_mem_malloc(sizeof(*tdls_vdev_obj));
if (tdls_vdev_obj == NULL) {
if (!tdls_vdev_obj) {
tdls_err("Failed to allocate memory for tdls vdev object");
return QDF_STATUS_E_NOMEM;
}
tdls_vdev_obj->vdev = vdev;
tdls_vdev_init(tdls_vdev_obj);
status = wlan_objmgr_vdev_component_obj_attach(vdev,
WLAN_UMAC_COMP_TDLS,
(void *)tdls_vdev_obj,
@ -122,10 +155,15 @@ QDF_STATUS tdls_vdev_obj_create_notification(struct wlan_objmgr_vdev *vdev,
if (QDF_IS_STATUS_ERROR(status)) {
tdls_err("Failed to attach vdev tdls component");
qdf_mem_free(tdls_vdev_obj);
goto out;
}
tdls_vdev_obj->vdev = vdev;
status = tdls_vdev_init(tdls_vdev_obj);
if (QDF_IS_STATUS_ERROR(status))
goto out;
tdls_notice("tdls object attach to vdev successfully");
out:
return status;
}
@ -142,7 +180,7 @@ QDF_STATUS tdls_vdev_obj_destroy_notification(struct wlan_objmgr_vdev *vdev,
tdls_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev,
WLAN_UMAC_COMP_TDLS);
if (tdls_vdev_obj == NULL) {
if (!tdls_vdev_obj) {
tdls_err("Failed to get tdls vdev object");
return QDF_STATUS_E_FAILURE;
}
@ -153,7 +191,47 @@ QDF_STATUS tdls_vdev_obj_destroy_notification(struct wlan_objmgr_vdev *vdev,
if (QDF_IS_STATUS_ERROR(status))
tdls_err("Failed to detach vdev tdls component");
tdls_vdev_deinit(tdls_vdev_obj);
qdf_mem_free(tdls_vdev_obj);
return status;
}
QDF_STATUS tdls_process_cmd(struct scheduler_msg *msg)
{
QDF_STATUS status = QDF_STATUS_SUCCESS;
if (!msg || !msg->bodyptr) {
tdls_err("msg: 0x%p, bodyptr: 0x%p", msg, msg->bodyptr);
QDF_ASSERT(0);
return QDF_STATUS_E_NULL_VALUE;
}
switch (msg->type) {
case TDLS_CMD_TX_ACTION:
break;
case TDLS_CMD_ADD_STA:
tdls_process_add_peer(msg->bodyptr);
break;
case TDLS_CMD_CHANGE_STA:
tdls_process_update_peer(msg->bodyptr);
break;
case TDLS_CMD_ENABLE_LINK:
break;
case TDLS_CMD_DISABLE_LINK:
tdls_process_del_peer(msg->bodyptr);
break;
case TDLS_CMD_CONFIG_FORCE_PEER:
break;
case TDLS_CMD_REMOVE_FORCE_PEER:
break;
case TDLS_CMD_STATS_UPDATE:
break;
case TDLS_CMD_CONFIG_UPDATE:
break;
default:
break;
}
return status;
}

View file

@ -39,6 +39,17 @@
#define ENA_TDLS_BUFFER_STA (1 << 1) /* TDLS Buffer STA support */
#define ENA_TDLS_SLEEP_STA (1 << 2) /* TDLS Sleep STA support */
#define BW_20_OFFSET_BIT 0
#define BW_40_OFFSET_BIT 1
#define BW_80_OFFSET_BIT 2
#define BW_160_OFFSET_BIT 3
#define TDLS_SEC_OFFCHAN_OFFSET_0 0
#define TDLS_SEC_OFFCHAN_OFFSET_40PLUS 40
#define TDLS_SEC_OFFCHAN_OFFSET_40MINUS (-40)
#define TDLS_SEC_OFFCHAN_OFFSET_80 80
#define TDLS_SEC_OFFCHAN_OFFSET_160 160
#define tdls_log(level, args...) \
QDF_TRACE(QDF_MODULE_ID_TDLS, level, ## args)
#define tdls_logfl(level, format, args...) \
@ -163,13 +174,20 @@ struct tdls_set_state_info {
* @tx_ack_cnf_cb_data: user data to tdls_tx_cnf_cb
* @tdls_event_cb: tdls event callback
* @tdls_evt_cb_data: tdls event user data
* @tdls_reg_tl_peer: callback to register the TDLS peer with TL
* @tdls_dereg_tl_peer: callback to unregister the TDLS peer
* @tdls_tl_peer_data: userdata for register/deregister TDLS peer
* @tx_q_ack: queue for tx frames waiting for ack
* @tdls_con_cap: tdls concurrency support
* @tdls_send_mgmt_req: store eWNI_SME_TDLS_SEND_MGMT_REQ value
* @tdls_add_sta_req: store eWNI_SME_TDLS_ADD_STA_REQ value
* @tdls_del_sta_req: store eWNI_SME_TDLS_DEL_STA_REQ value
* @tdls_update_peer_state: store WMA_UPDATE_TDLS_PEER_STATE value
*/
struct tdls_soc_priv_obj {
struct wlan_objmgr_psoc *soc;
enum tdls_support_mode tdls_current_mode;
enum tdls_support_mode tdls_user_config_mode;
enum tdls_feature_mode tdls_current_mode;
enum tdls_feature_mode tdls_user_config_mode;
struct tdls_conn_info tdls_conn_info[WLAN_TDLS_STA_MAX_NUM];
struct tdls_user_config tdls_configs;
uint16_t max_num_tdls_sta;
@ -188,8 +206,15 @@ struct tdls_soc_priv_obj {
void *tx_ack_cnf_cb_data;
tdls_evt_callback tdls_event_cb;
void *tdls_evt_cb_data;
tdls_register_tl_peer_callback tdls_reg_tl_peer;
tdls_deregister_tl_peer_callback tdls_dereg_tl_peer;
void *tdls_tl_peer_data;
qdf_list_t tx_q_ack;
enum tdls_conc_cap tdls_con_cap;
uint16_t tdls_send_mgmt_req;
uint16_t tdls_add_sta_req;
uint16_t tdls_del_sta_req;
uint16_t tdls_update_peer_state;
};
/**
@ -225,6 +250,12 @@ struct tdls_vdev_priv_obj {
qdf_list_t tx_queue;
};
/**
* struct tdls_peer_mlme_info - tdls peer mlme info
**/
struct tdls_peer_mlme_info {
};
/**
* struct tdls_peer - tdls peer data
* @node: node
@ -266,7 +297,7 @@ struct tdls_peer {
uint16_t sta_id;
int8_t rssi;
enum tdls_peer_capab tdls_support;
enum tdls_link_status link_status;
enum tdls_link_state link_status;
uint8_t signature;
uint8_t is_responder;
uint8_t discovery_processed;
@ -288,9 +319,10 @@ struct tdls_peer {
qdf_mc_timer_t peer_idle_timer;
bool is_peer_idle_timer_initialised;
uint8_t spatial_streams;
enum tdls_link_reason reason;
enum tdls_link_state_reason reason;
tdls_state_change_callback state_change_notification;
uint8_t qos;
struct tdls_peer_mlme_info *tdls_info;
};
/**
@ -302,12 +334,29 @@ struct tdls_peer {
static inline struct tdls_soc_priv_obj *
wlan_vdev_get_tdls_soc_obj(struct wlan_objmgr_vdev *vdev)
{
struct wlan_objmgr_psoc *psoc =
wlan_pdev_get_psoc(wlan_vdev_get_pdev(vdev));
struct wlan_objmgr_psoc *psoc;
struct tdls_soc_priv_obj *soc_obj;
return (struct tdls_soc_priv_obj *)
if (!vdev) {
tdls_err("NULL vdev");
return NULL;
}
wlan_vdev_obj_lock(vdev);
psoc = wlan_vdev_get_psoc(vdev);
wlan_vdev_obj_unlock(vdev);
if (!psoc) {
tdls_err("can't get psoc");
return NULL;
}
wlan_psoc_obj_lock(psoc);
soc_obj = (struct tdls_soc_priv_obj *)
wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_TDLS);
wlan_psoc_obj_unlock(psoc);
return soc_obj;
}
/**
@ -319,9 +368,18 @@ wlan_vdev_get_tdls_soc_obj(struct wlan_objmgr_vdev *vdev)
static inline struct tdls_soc_priv_obj *
wlan_psoc_get_tdls_soc_obj(struct wlan_objmgr_psoc *psoc)
{
return (struct tdls_soc_priv_obj *)
struct tdls_soc_priv_obj *soc_obj;
if (!psoc) {
tdls_err("NULL psoc");
return NULL;
}
wlan_psoc_obj_lock(psoc);
soc_obj = (struct tdls_soc_priv_obj *)
wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_TDLS);
wlan_psoc_obj_unlock(psoc);
return soc_obj;
}
/**
@ -333,22 +391,33 @@ wlan_psoc_get_tdls_soc_obj(struct wlan_objmgr_psoc *psoc)
static inline struct tdls_vdev_priv_obj *
wlan_vdev_get_tdls_vdev_obj(struct wlan_objmgr_vdev *vdev)
{
return (struct tdls_vdev_priv_obj *)
struct tdls_vdev_priv_obj *vdev_obj;
if (!vdev) {
tdls_err("NULL vdev");
return NULL;
}
wlan_vdev_obj_lock(vdev);
vdev_obj = (struct tdls_vdev_priv_obj *)
wlan_objmgr_vdev_get_comp_private_obj(vdev,
WLAN_UMAC_COMP_TDLS);
wlan_vdev_obj_unlock(vdev);
return vdev_obj;
}
/**
* tdls_set_link_status - tdls set link status
* @vdev: vdev object
* @mac: mac address of tdls peer
* @link_status: tdls link status
* @link_state: tdls link state
* @link_reason: reason
*/
void tdls_set_link_status(struct tdls_vdev_priv_obj *vdev,
const uint8_t *mac,
enum tdls_link_status link_status,
enum tdls_link_reason link_reason);
enum tdls_link_state link_state,
enum tdls_link_state_reason link_reason);
/**
* tdls_psoc_obj_create_notification() - tdls psoc create notification handler
* @psoc: psoc object

View file

@ -0,0 +1,836 @@
/*
* Copyright (c) 2017 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
* 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_tdls_peer.c
*
* TDLS peer basic operations
*/
#include "wlan_tdls_main.h"
#include "wlan_tdls_peer.h"
#include <wlan_reg_services_api.h>
#include <wlan_utility.h>
#include <wlan_policy_mgr_api.h>
static uint8_t calculate_hash_key(const uint8_t *macaddr)
{
uint8_t i, key;
for (i = 0, key = 0; i < 6; i++)
key ^= macaddr[i];
return key % WLAN_TDLS_PEER_LIST_SIZE;
}
struct tdls_peer *tdls_find_peer(struct tdls_vdev_priv_obj *vdev_obj,
const uint8_t *macaddr)
{
uint8_t key;
QDF_STATUS status;
struct tdls_peer *peer;
qdf_list_t *head;
qdf_list_node_t *p_node;
key = calculate_hash_key(macaddr);
head = &vdev_obj->peer_list[key];
status = qdf_list_peek_front(head, &p_node);
while (QDF_IS_STATUS_SUCCESS(status)) {
peer = qdf_container_of(p_node, struct tdls_peer, node);
if (WLAN_ADDR_EQ(&peer->peer_mac, macaddr)
== QDF_STATUS_SUCCESS) {
return peer;
}
status = qdf_list_peek_next(head, p_node, &p_node);
}
tdls_debug("no tdls peer " QDF_MAC_ADDRESS_STR,
QDF_MAC_ADDR_ARRAY(macaddr));
return NULL;
}
/**
* tdls_find_peer_handler() - helper function for tdls_find_all_peer
* @psoc: soc object
* @obj: vdev object
* @arg: used to keep search peer parameters
*
* Return: None.
*/
static void
tdls_find_peer_handler(struct wlan_objmgr_psoc *psoc, void *obj, void *arg)
{
struct wlan_objmgr_vdev *vdev = obj;
struct tdls_search_peer_param *tdls_param = arg;
struct tdls_vdev_priv_obj *vdev_obj;
if (tdls_param->peer)
return;
if (!vdev) {
tdls_err("invalid vdev");
return;
}
if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE &&
wlan_vdev_mlme_get_opmode(vdev) != QDF_P2P_CLIENT_MODE)
return;
vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev,
WLAN_UMAC_COMP_TDLS);
if (!vdev_obj)
return;
tdls_param->peer = tdls_find_peer(vdev_obj, tdls_param->macaddr);
}
struct tdls_peer *
tdls_find_all_peer(struct tdls_soc_priv_obj *soc_obj, const uint8_t *macaddr)
{
struct tdls_search_peer_param tdls_search_param;
struct wlan_objmgr_psoc *psoc;
if (!soc_obj) {
tdls_err("tdls soc object is NULL");
return NULL;
}
psoc = soc_obj->soc;
if (!psoc) {
tdls_err("psoc is NULL");
return NULL;
}
tdls_search_param.macaddr = macaddr;
tdls_search_param.peer = NULL;
wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP,
tdls_find_peer_handler,
&tdls_search_param, 0, WLAN_TDLS_NB_ID);
return tdls_search_param.peer;
}
static uint8_t tdls_find_opclass(struct wlan_objmgr_psoc *psoc, uint8_t channel,
uint8_t bw_offset)
{
char country[REG_ALPHA2_LEN + 1];
QDF_STATUS status;
if (!psoc) {
tdls_err("psoc is NULL");
return 0;
}
status = wlan_reg_read_default_country(psoc, country);
if (QDF_IS_STATUS_ERROR(status))
return 0;
return wlan_reg_dmn_get_opclass_from_channel(country, channel,
bw_offset);
}
/**
* tdls_add_peer() - add TDLS peer in TDLS vdev object
* @vdev_obj: TDLS vdev object
* @macaddr: MAC address of peer
*
* Allocate memory for the new peer, and add it to hash table.
*
* Return: new added TDLS peer, NULL if failed.
*/
static struct tdls_peer *tdls_add_peer(struct tdls_vdev_priv_obj *vdev_obj,
const uint8_t *macaddr)
{
struct tdls_peer *peer;
struct tdls_soc_priv_obj *soc_obj;
uint8_t key = 0;
qdf_list_t *head;
peer = qdf_mem_malloc(sizeof(*peer));
if (!peer) {
tdls_err("add tdls peer malloc memory failed!");
return NULL;
}
soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev);
if (!soc_obj) {
tdls_err("NULL tdls soc object");
return NULL;
}
key = calculate_hash_key(macaddr);
head = &vdev_obj->peer_list[key];
qdf_mem_copy(&peer->peer_mac, macaddr, sizeof(peer->peer_mac));
peer->vdev_priv = vdev_obj;
peer->pref_off_chan_num =
soc_obj->tdls_configs.tdls_pre_off_chan_num;
peer->op_class_for_pref_off_chan =
tdls_find_opclass(soc_obj->soc,
peer->pref_off_chan_num,
soc_obj->tdls_configs.tdls_pre_off_chan_bw);
qdf_list_insert_back(head, &peer->node);
tdls_debug("add tdls peer: " QDF_MAC_ADDRESS_STR,
QDF_MAC_ADDR_ARRAY(macaddr));
return peer;
}
struct tdls_peer *tdls_get_peer(struct tdls_vdev_priv_obj *vdev_obj,
const uint8_t *macaddr)
{
struct tdls_peer *peer;
peer = tdls_find_peer(vdev_obj, macaddr);
if (!peer)
peer = tdls_add_peer(vdev_obj, macaddr);
return peer;
}
static struct tdls_peer *
tdls_find_progress_peer_in_list(qdf_list_t *head,
const uint8_t *macaddr, uint8_t skip_self)
{
QDF_STATUS status;
struct tdls_peer *peer;
qdf_list_node_t *p_node;
status = qdf_list_peek_front(head, &p_node);
while (QDF_IS_STATUS_SUCCESS(status)) {
peer = qdf_container_of(p_node, struct tdls_peer, node);
if (skip_self && macaddr &&
WLAN_ADDR_EQ(&peer->peer_mac, macaddr)
== QDF_STATUS_SUCCESS) {
status = qdf_list_peek_next(head, p_node, &p_node);
continue;
} else if (TDLS_LINK_CONNECTING == peer->link_status) {
tdls_debug(QDF_MAC_ADDRESS_STR " TDLS_LINK_CONNECTING",
QDF_MAC_ADDR_ARRAY(peer->peer_mac.bytes));
return peer;
}
status = qdf_list_peek_next(head, p_node, &p_node);
}
return NULL;
}
/**
* tdls_find_progress_peer() - find the peer with ongoing TDLS progress
* on present vdev
* @vdev_obj: TDLS vdev object
* @macaddr: MAC address of peer, if NULL check for all the peer list
* @skip_self: If true, skip this macaddr. Otherwise, check all the peer list.
* if macaddr is NULL, this argument is ignored, and check for all
* the peer list.
*
* Return: Pointer to tdls_peer if TDLS is ongoing. Otherwise return NULL.
*/
static struct tdls_peer *
tdls_find_progress_peer(struct tdls_vdev_priv_obj *vdev_obj,
const uint8_t *macaddr, uint8_t skip_self)
{
uint8_t i;
struct tdls_peer *peer;
qdf_list_t *head;
if (!vdev_obj) {
tdls_err("invalid tdls vdev object");
return NULL;
}
for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
head = &vdev_obj->peer_list[i];
peer = tdls_find_progress_peer_in_list(head, macaddr,
skip_self);
if (peer)
return peer;
}
return NULL;
}
/**
* tdls_find_progress_peer_handler() - helper function for tdls_is_progress
* @psoc: soc object
* @obj: vdev object
* @arg: used to keep search peer parameters
*
* Return: None.
*/
static void
tdls_find_progress_peer_handler(struct wlan_objmgr_psoc *psoc,
void *obj, void *arg)
{
struct wlan_objmgr_vdev *vdev = obj;
struct tdls_search_progress_param *tdls_progress = arg;
struct tdls_vdev_priv_obj *vdev_obj;
if (tdls_progress->peer)
return;
if (!vdev) {
tdls_err("invalid vdev");
return;
}
if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE &&
wlan_vdev_mlme_get_opmode(vdev) != QDF_P2P_CLIENT_MODE)
return;
vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev,
WLAN_UMAC_COMP_TDLS);
tdls_progress->peer = tdls_find_progress_peer(vdev_obj,
tdls_progress->macaddr,
tdls_progress->skip_self);
}
struct tdls_peer *tdls_is_progress(struct tdls_vdev_priv_obj *vdev_obj,
const uint8_t *macaddr, uint8_t skip_self)
{
struct tdls_search_progress_param tdls_progress;
struct wlan_objmgr_psoc *psoc;
if (!vdev_obj) {
tdls_err("invalid tdls vdev object");
return NULL;
}
wlan_vdev_obj_lock(vdev_obj->vdev);
psoc = wlan_vdev_get_psoc(vdev_obj->vdev);
wlan_vdev_obj_unlock(vdev_obj->vdev);
if (!psoc) {
tdls_err("invalid psoc");
return NULL;
}
tdls_progress.macaddr = macaddr;
tdls_progress.skip_self = skip_self;
tdls_progress.peer = NULL;
wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP,
tdls_find_progress_peer_handler,
&tdls_progress, 0, WLAN_TDLS_NB_ID);
return tdls_progress.peer;
}
struct tdls_peer *
tdls_find_first_connected_peer(struct tdls_vdev_priv_obj *vdev_obj)
{
uint16_t i;
struct tdls_peer *peer;
qdf_list_t *head;
qdf_list_node_t *p_node;
QDF_STATUS status;
if (!vdev_obj) {
tdls_err("invalid tdls vdev object");
return NULL;
}
for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
head = &vdev_obj->peer_list[i];
status = qdf_list_peek_front(head, &p_node);
while (QDF_IS_STATUS_SUCCESS(status)) {
peer = qdf_container_of(p_node, struct tdls_peer, node);
if (peer && TDLS_LINK_CONNECTED == peer->link_status) {
tdls_debug(QDF_MAC_ADDRESS_STR
" TDLS_LINK_CONNECTED",
QDF_MAC_ADDR_ARRAY(
peer->peer_mac.bytes));
return peer;
}
status = qdf_list_peek_next(head, p_node, &p_node);
}
}
return NULL;
}
/**
* tdls_determine_channel_opclass() - determine channel and opclass
* @soc_obj: TDLS soc object
* @vdev_obj: TDLS vdev object
* @peer: TDLS peer
* @channel: pointer to channel
* @opclass: pinter to opclass
*
* Function determines the channel and operating class
*
* Return: None.
*/
static void tdls_determine_channel_opclass(struct tdls_soc_priv_obj *soc_obj,
struct tdls_vdev_priv_obj *vdev_obj,
struct tdls_peer *peer,
uint32_t *channel, uint32_t *opclass)
{
uint32_t vdev_id;
enum tQDF_ADAPTER_MODE opmode;
/*
* If tdls offchannel is not enabled then we provide base channel
* and in that case pass opclass as 0 since opclass is mainly needed
* for offchannel cases.
*/
if (!(TDLS_IS_OFF_CHANNEL_ENABLED(
soc_obj->tdls_configs.tdls_feature_flags)) ||
soc_obj->tdls_fw_off_chan_mode != ENABLE_CHANSWITCH) {
wlan_vdev_obj_lock(vdev_obj->vdev);
vdev_id = wlan_vdev_get_id(vdev_obj->vdev);
opmode = wlan_vdev_mlme_get_opmode(vdev_obj->vdev);
wlan_vdev_obj_unlock(vdev_obj->vdev);
*channel = policy_mgr_get_channel(soc_obj->soc,
opmode, &vdev_id);
*opclass = 0;
} else {
*channel = peer->pref_off_chan_num;
*opclass = peer->op_class_for_pref_off_chan;
}
tdls_debug("channel:%d opclass:%d", *channel, *opclass);
}
/**
* tdls_get_wifi_hal_state() - get TDLS wifi hal state on current peer
* @peer: TDLS peer
* @state: output parameter to store the TDLS wifi hal state
* @reason: output parameter to store the reason of the current peer
*
* Return: None.
*/
static void tdls_get_wifi_hal_state(struct tdls_peer *peer, uint32_t *state,
int32_t *reason)
{
struct wlan_objmgr_vdev *vdev;
struct tdls_soc_priv_obj *soc_obj;
vdev = peer->vdev_priv->vdev;
soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
if (!soc_obj) {
tdls_err("can't get tdls object");
return;
}
*reason = peer->reason;
switch (peer->link_status) {
case TDLS_LINK_IDLE:
case TDLS_LINK_DISCOVERED:
case TDLS_LINK_DISCOVERING:
case TDLS_LINK_CONNECTING:
*state = QCA_WIFI_HAL_TDLS_S_ENABLED;
break;
case TDLS_LINK_CONNECTED:
if ((TDLS_IS_OFF_CHANNEL_ENABLED(
soc_obj->tdls_configs.tdls_feature_flags)) &&
(soc_obj->tdls_fw_off_chan_mode == ENABLE_CHANSWITCH))
*state = QCA_WIFI_HAL_TDLS_S_ESTABLISHED_OFF_CHANNEL;
else
*state = QCA_WIFI_HAL_TDLS_S_ENABLED;
break;
case TDLS_LINK_TEARING:
*state = QCA_WIFI_HAL_TDLS_S_DROPPED;
break;
}
}
/**
* tdls_extract_peer_state_param() - extract peer update params from TDLS peer
* @peer_param: output peer update params
* @peer: TDLS peer
*
* This is used when enable TDLS link
*
* Return: None.
*/
void tdls_extract_peer_state_param(struct tdls_peer_update_state *peer_param,
struct tdls_peer *peer)
{
uint16_t i, num;
struct tdls_vdev_priv_obj *vdev_obj;
struct tdls_soc_priv_obj *soc_obj;
enum channel_state ch_state;
struct wlan_objmgr_pdev *pdev;
uint8_t chan_id;
vdev_obj = peer->vdev_priv;
soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev);
pdev = wlan_vdev_get_pdev(vdev_obj->vdev);
if (!soc_obj || !pdev) {
tdls_err("soc_obj: %p, pdev: %p", soc_obj, pdev);
return;
}
qdf_mem_zero(peer_param, sizeof(*peer_param));
wlan_vdev_obj_lock(vdev_obj->vdev);
peer_param->vdev_id = wlan_vdev_get_id(vdev_obj->vdev);
wlan_vdev_obj_unlock(vdev_obj->vdev);
qdf_mem_copy(peer_param->peer_macaddr,
peer->peer_mac.bytes, QDF_MAC_ADDR_SIZE);
peer_param->peer_state = TDLS_PEER_STATE_CONNCTED;
peer_param->peer_cap.is_peer_responder = peer->is_responder;
peer_param->peer_cap.peer_uapsd_queue = peer->uapsd_queues;
peer_param->peer_cap.peer_max_sp = peer->max_sp;
peer_param->peer_cap.peer_buff_sta_support = peer->buf_sta_capable;
peer_param->peer_cap.peer_off_chan_support =
peer->off_channel_capable;
peer_param->peer_cap.peer_curr_operclass = 0;
peer_param->peer_cap.self_curr_operclass = 0;
peer_param->peer_cap.peer_chanlen = peer->supported_channels_len;
peer_param->peer_cap.pref_off_channum = peer->pref_off_chan_num;
peer_param->peer_cap.pref_off_chan_bandwidth =
soc_obj->tdls_configs.tdls_pre_off_chan_bw;
peer_param->peer_cap.opclass_for_prefoffchan =
peer->op_class_for_pref_off_chan;
if (wlan_reg_is_dfs_ch(pdev, peer_param->peer_cap.pref_off_channum)) {
tdls_err("Resetting TDLS off-channel from %d to %d",
peer_param->peer_cap.pref_off_channum,
WLAN_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEF);
peer_param->peer_cap.pref_off_channum =
WLAN_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEF;
}
num = 0;
for (i = 0; i < peer->supported_channels_len; i++) {
chan_id = peer->supported_channels[i];
ch_state = wlan_reg_get_channel_state(pdev, chan_id);
if (CHANNEL_STATE_INVALID != ch_state &&
CHANNEL_STATE_DFS != ch_state &&
!wlan_is_dsrc_channel(wlan_is_dsrc_channel(chan_id))) {
peer_param->peer_cap.peer_chan[num].chan_id = chan_id;
peer_param->peer_cap.peer_chan[num].pwr =
wlan_reg_get_channel_reg_power(pdev, chan_id);
peer_param->peer_cap.peer_chan[num].dfs_set = false;
num++;
}
}
peer_param->peer_cap.peer_oper_classlen =
peer->supported_oper_classes_len;
for (i = 0; i < peer->supported_oper_classes_len; i++)
peer_param->peer_cap.peer_oper_class[i] =
peer->supported_oper_classes[i];
}
/**
* tdls_set_link_status() - set link statue for TDLS peer
* @vdev_obj: TDLS vdev object
* @mac: MAC address of current TDLS peer
* @link_status: link status
* @link_reason: reason with link status
*
* Return: None.
*/
void tdls_set_link_status(struct tdls_vdev_priv_obj *vdev_obj,
const uint8_t *mac,
enum tdls_link_state link_status,
enum tdls_link_state_reason link_reason)
{
uint32_t state = 0;
int32_t res = 0;
uint32_t op_class = 0;
uint32_t channel = 0;
struct tdls_peer *peer;
struct tdls_soc_priv_obj *soc_obj;
peer = tdls_find_peer(vdev_obj, mac);
if (!peer) {
tdls_err("peer is NULL, can't set link status %d, reason %d",
link_status, link_reason);
return;
}
peer->link_status = link_status;
if (link_status >= TDLS_LINK_DISCOVERED)
peer->discovery_attempt = 0;
if (peer->is_forced_peer && peer->state_change_notification) {
peer->reason = link_reason;
soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev);
if (!soc_obj) {
tdls_err("NULL psoc object");
return;
}
tdls_determine_channel_opclass(soc_obj, vdev_obj,
peer, &channel, &op_class);
tdls_get_wifi_hal_state(peer, &state, &res);
peer->state_change_notification(mac, op_class, channel,
state, res, soc_obj->soc);
}
}
void tdls_set_peer_link_status(struct tdls_peer *peer,
enum tdls_link_state link_status,
enum tdls_link_state_reason link_reason)
{
uint32_t state = 0;
int32_t res = 0;
uint32_t op_class = 0;
uint32_t channel = 0;
struct tdls_soc_priv_obj *soc_obj;
struct tdls_vdev_priv_obj *vdev_obj;
peer->link_status = link_status;
if (link_status >= TDLS_LINK_DISCOVERED)
peer->discovery_attempt = 0;
if (peer->is_forced_peer && peer->state_change_notification) {
peer->reason = link_reason;
vdev_obj = peer->vdev_priv;
soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev);
if (!soc_obj) {
tdls_err("NULL psoc object");
return;
}
tdls_determine_channel_opclass(soc_obj, vdev_obj,
peer, &channel, &op_class);
tdls_get_wifi_hal_state(peer, &state, &res);
peer->state_change_notification(peer->peer_mac.bytes,
op_class, channel, state,
res, soc_obj->soc);
}
}
void tdls_set_peer_caps(struct tdls_vdev_priv_obj *vdev_obj,
const uint8_t *macaddr,
struct tdls_update_peer_params *req_info)
{
uint8_t is_buffer_sta, is_off_channel_supported, is_qos_wmm_sta;
struct tdls_soc_priv_obj *soc_obj;
struct tdls_peer *curr_peer;
uint32_t feature;
soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev);
if (!soc_obj) {
tdls_err("NULL psoc object");
return;
}
curr_peer = tdls_find_peer(vdev_obj, macaddr);
if (!curr_peer) {
tdls_err("NULL tdls peer");
return;
}
feature = soc_obj->tdls_configs.tdls_feature_flags;
if ((1 << 4) & req_info->extn_capability[3])
is_buffer_sta = 1;
if ((1 << 6) & req_info->extn_capability[3])
is_off_channel_supported = 1;
if (TDLS_IS_WMM_ENABLED(feature) && req_info->is_qos_wmm_sta)
is_qos_wmm_sta = true;
curr_peer->uapsd_queues = req_info->uapsd_queues;
curr_peer->max_sp = req_info->max_sp;
curr_peer->buf_sta_capable = is_buffer_sta;
curr_peer->off_channel_capable = is_off_channel_supported;
qdf_mem_copy(curr_peer->supported_channels,
req_info->supported_channels,
req_info->supported_channels_len);
curr_peer->supported_channels_len = req_info->supported_channels_len;
qdf_mem_copy(curr_peer->supported_oper_classes,
req_info->supported_oper_classes,
req_info->supported_oper_classes_len);
curr_peer->supported_oper_classes_len =
req_info->supported_oper_classes_len;
curr_peer->qos = is_qos_wmm_sta;
}
QDF_STATUS tdls_set_sta_id(struct tdls_vdev_priv_obj *vdev_obj,
const uint8_t *macaddr, uint8_t sta_id)
{
struct tdls_peer *peer;
peer = tdls_find_peer(vdev_obj, macaddr);
if (!peer) {
tdls_err("peer is NULL");
return QDF_STATUS_E_FAILURE;
}
peer->sta_id = sta_id;
return QDF_STATUS_SUCCESS;
}
QDF_STATUS tdls_set_signature(struct tdls_vdev_priv_obj *vdev_obj,
const uint8_t *macaddr, uint8_t signature)
{
struct tdls_peer *peer;
peer = tdls_find_peer(vdev_obj, macaddr);
if (!peer) {
tdls_err("peer is NULL");
return QDF_STATUS_E_FAILURE;
}
peer->signature = signature;
return QDF_STATUS_SUCCESS;
}
QDF_STATUS tdls_set_force_peer(struct tdls_vdev_priv_obj *vdev_obj,
const uint8_t *macaddr, bool forcepeer)
{
struct tdls_peer *peer;
peer = tdls_find_peer(vdev_obj, macaddr);
if (!peer) {
tdls_err("peer is NULL");
return QDF_STATUS_E_FAILURE;
}
peer->is_forced_peer = forcepeer;
return QDF_STATUS_SUCCESS;
}
QDF_STATUS tdls_set_callback(struct tdls_peer *peer,
tdls_state_change_callback callback)
{
if (!peer) {
tdls_err("peer is NULL");
return QDF_STATUS_E_FAILURE;
}
peer->state_change_notification = callback;
return QDF_STATUS_SUCCESS;
}
QDF_STATUS tdls_set_extctrl_param(struct tdls_peer *peer, uint32_t chan,
uint32_t max_latency, uint32_t op_class,
uint32_t min_bandwidth)
{
if (!peer) {
tdls_err("peer is NULL");
return QDF_STATUS_E_FAILURE;
}
peer->op_class_for_pref_off_chan = (uint8_t)op_class;
peer->pref_off_chan_num = (uint8_t)chan;
return QDF_STATUS_SUCCESS;
}
QDF_STATUS tdls_reset_peer(struct tdls_vdev_priv_obj *vdev_obj,
const uint8_t *macaddr)
{
struct tdls_soc_priv_obj *soc_obj;
struct tdls_peer *curr_peer;
struct tdls_user_config *config;
soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev);
if (!soc_obj) {
tdls_err("NULL psoc object");
return QDF_STATUS_E_FAILURE;
}
curr_peer = tdls_find_peer(vdev_obj, macaddr);
if (!curr_peer) {
tdls_err("NULL tdls peer");
return QDF_STATUS_E_FAILURE;
}
if (!curr_peer->is_forced_peer) {
config = &soc_obj->tdls_configs;
curr_peer->pref_off_chan_num = config->tdls_pre_off_chan_num;
curr_peer->op_class_for_pref_off_chan =
tdls_find_opclass(soc_obj->soc,
curr_peer->pref_off_chan_num,
config->tdls_pre_off_chan_bw);
}
tdls_set_peer_link_status(curr_peer, TDLS_LINK_IDLE,
TDLS_LINK_UNSPECIFIED);
curr_peer->sta_id = 0;
return QDF_STATUS_SUCCESS;
}
void tdls_peer_idle_timers_destroy(struct tdls_vdev_priv_obj *vdev_obj)
{
uint16_t i;
struct tdls_peer *peer;
qdf_list_t *head;
qdf_list_node_t *p_node;
QDF_STATUS status;
if (!vdev_obj) {
tdls_err("NULL tdls vdev object");
return;
}
for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
head = &vdev_obj->peer_list[i];
status = qdf_list_peek_front(head, &p_node);
while (QDF_IS_STATUS_SUCCESS(status)) {
peer = qdf_container_of(p_node, struct tdls_peer, node);
if (peer && peer->is_peer_idle_timer_initialised) {
tdls_debug(QDF_MAC_ADDRESS_STR
": destroy idle timer ",
QDF_MAC_ADDR_ARRAY(
peer->peer_mac.bytes));
qdf_mc_timer_stop(&peer->peer_idle_timer);
qdf_mc_timer_destroy(&peer->peer_idle_timer);
}
status = qdf_list_peek_next(head, p_node, &p_node);
}
}
}
void tdls_free_peer_list(struct tdls_vdev_priv_obj *vdev_obj)
{
uint16_t i;
struct tdls_peer *peer;
qdf_list_t *head;
qdf_list_node_t *p_node;
if (!vdev_obj) {
tdls_err("NULL tdls vdev object");
return;
}
for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
head = &vdev_obj->peer_list[i];
while (QDF_IS_STATUS_SUCCESS(
qdf_list_remove_front(head, &p_node))) {
peer = qdf_container_of(p_node, struct tdls_peer, node);
qdf_mem_free(peer);
}
qdf_list_destroy(head);
}
}

View file

@ -0,0 +1,245 @@
/*
* Copyright (c) 2017 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
* 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_tdls_peer.h
*
* TDLS peer function declaration
*/
#if !defined(_WLAN_TDLS_PEER_H_)
#define _WLAN_TDLS_PEER_H_
/**
* struct tdls_search_peer_param - used to search TDLS peer
* @macaddr: MAC address of peer
* @peer: pointer to the found peer
*/
struct tdls_search_peer_param {
const uint8_t *macaddr;
struct tdls_peer *peer;
};
/**
* struct tdls_progress_param - used to search progress TDLS peer
* @skip_self: skip self peer
* @macaddr: MAC address of peer
* @peer: pointer to the found peer
*/
struct tdls_search_progress_param {
uint8_t skip_self;
const uint8_t *macaddr;
struct tdls_peer *peer;
};
/**
* tdls_get_peer() - find or add an TDLS peer in TDLS vdev object
* @vdev_obj: TDLS vdev object
* @macaddr: MAC address of peer
*
* Search the TDLS peer in the hash table and create a new one if not found.
*
* Return: Pointer to tdls_peer, NULL if failed.
*/
struct tdls_peer *tdls_get_peer(struct tdls_vdev_priv_obj *vdev_obj,
const uint8_t *macaddr);
/**
* tdls_find_peer() - find TDLS peer in TDLS vdev object
* @vdev_obj: TDLS vdev object
* @macaddr: MAC address of peer
*
* This is in scheduler thread context, no lock required.
*
* Return: If peer is found, then it returns pointer to tdls_peer;
* otherwise, it returns NULL.
*/
struct tdls_peer *tdls_find_peer(struct tdls_vdev_priv_obj *vdev_obj,
const uint8_t *macaddr);
/**
* tdls_find_all_peer() - find peer matching the input MACaddr in soc range
* @soc_obj: TDLS soc object
* @macaddr: MAC address of TDLS peer
*
* This is in scheduler thread context, no lock required.
*
* Return: TDLS peer if a matching is detected; NULL otherwise
*/
struct tdls_peer *
tdls_find_all_peer(struct tdls_soc_priv_obj *soc_obj, const uint8_t *macaddr);
/**
* tdls_find_first_connected_peer() - find the 1st connected tdls peer from vdev
* @vdev_obj: tdls vdev object
*
* This function searches for the 1st connected TDLS peer
*
* Return: The 1st connected TDLS peer if found; NULL otherwise
*/
struct tdls_peer *
tdls_find_first_connected_peer(struct tdls_vdev_priv_obj *vdev_obj);
/**
* tdls_is_progress() - find the peer with ongoing TDLS progress on present psoc
* @vdev_obj: TDLS vdev object
* @macaddr: MAC address of the peer
* @skip_self: if 1, skip checking self. If 0, search include self
*
* This is used in scheduler thread context, no lock required.
*
* Return: TDLS peer if found; NULL otherwise
*/
struct tdls_peer *tdls_is_progress(struct tdls_vdev_priv_obj *vdev_obj,
const uint8_t *macaddr, uint8_t skip_self);
/**
* tdls_extract_peer_state_param() - extract peer update params from TDL peer
* @peer_param: output peer update params
* @peer: TDLS peer
*
* This is used when enable TDLS link
*
* Return: None.
*/
void tdls_extract_peer_state_param(struct tdls_peer_update_state *peer_param,
struct tdls_peer *peer);
/**
* tdls_set_link_status() - set link statue for TDLS peer
* @peer: TDLS peer
* @link_state: link state
* @link_reason: reason with link status
*
* This is in scheduler thread context, no lock required.
*
* Return: None.
*/
void tdls_set_peer_link_status(struct tdls_peer *peer,
enum tdls_link_state link_state,
enum tdls_link_state_reason link_reason);
/**
* tdls_set_peer_caps() - set capability for TDLS peer
* @vdev_obj: TDLS vdev object
* @macaddr: MAC address for the TDLS peer
* @req_info: parameters to update peer capability
*
* This is in scheduler thread context, no lock required.
*
* Return: None.
*/
void tdls_set_peer_caps(struct tdls_vdev_priv_obj *vdev_obj,
const uint8_t *macaddr,
struct tdls_update_peer_params *req_info);
/**
* tdls_set_sta_id() - set station ID on a TDLS peer
* @vdev_obj: TDLS vdev object
* @macaddr: MAC address of the TDLS peer
* @sta_id: station ID
*
* Return: QDF_STATUS_SUCCESS if success; other values if failed
*/
QDF_STATUS tdls_set_sta_id(struct tdls_vdev_priv_obj *vdev_obj,
const uint8_t *macaddr, uint8_t sta_id);
/**
* tdls_set_signature() - set TDLS peer's signature
* @vdev_obj: TDLS vdev object
* @macaddr: MAC address of the TDLS peer
* @signature: signature value
*
* This is used in scheduler thread context, no lock required.
*
* Return: QDF_STATUS_SUCCESS if success; other values if failed
*/
QDF_STATUS tdls_set_signature(struct tdls_vdev_priv_obj *vdev_obj,
const uint8_t *macaddr, uint8_t signature);
/**
* tdls_set_force_peer() - set/clear is_forced_peer flag on peer
* @vdev_obj: TDLS vdev object
* @macaddr: MAC address of TDLS peer
* @forcepeer: value used to set is_forced_peer flag
*
* This is used in scheduler thread context, no lock required.
*
* Return: QDF_STATUS_SUCCESS if success; other values if failed
*/
QDF_STATUS tdls_set_force_peer(struct tdls_vdev_priv_obj *vdev_obj,
const uint8_t *macaddr, bool forcepeer);
/**
* tdls_set_callback() - set state change callback on current TDLS peer
* @peer: TDLS peer
* @callback: state change callback
*
* This is used in scheduler thread context, no lock required.
*
* Return: QDF_STATUS_SUCCESS if success; other values if failed
*/
QDF_STATUS tdls_set_callback(struct tdls_peer *peer,
tdls_state_change_callback callback);
/**
* tdls_set_extctrl_param() - set external control parameter on TDLS peer
* @peer: TDLS peer
* @chan: channel
* @max_latency: maximum latency
* @op_class: operation class
* @min_bandwidth: minimal bandwidth
*
* This is used in scheduler thread context, no lock required.
*
* Return: QDF_STATUS_SUCCESS if success; other values if failed
*/
QDF_STATUS tdls_set_extctrl_param(struct tdls_peer *peer, uint32_t chan,
uint32_t max_latency, uint32_t op_class,
uint32_t min_bandwidth);
/**
* tdls_reset_peer() - reset TDLS peer identified by MAC address
* @vdev_obj: TDLS vdev object
* @mac: MAC address of the peer
*
* Return: QDF_STATUS_SUCCESS if success; other values if failed
*/
QDF_STATUS tdls_reset_peer(struct tdls_vdev_priv_obj *vdev_obj,
const uint8_t *mac);
/**
* tdls_peer_idle_timers_destroy() - destroy peer idle timers
* @vdev_obj: TDLS vdev object
*
* Loop through the idle peer list and destroy their timers
*
* Return: None
*/
void tdls_peer_idle_timers_destroy(struct tdls_vdev_priv_obj *vdev_obj);
/**
* tdls_free_peer_list() - free TDLS peer list
* @vdev_obj: TDLS vdev object
*
* Free all the tdls peers
*
* Return: None
*/
void tdls_free_peer_list(struct tdls_vdev_priv_obj *vdev_obj);
#endif

View file

@ -30,15 +30,36 @@
#include <wlan_cmn.h>
#include <wlan_cmn_ieee80211.h>
#define WLAN_TDLS_STA_MAX_NUM 8
#define WLAN_TDLS_PEER_LIST_SIZE 256
#define WLAN_TDLS_CT_TABLE_SIZE 8
#define WLAN_TDLS_PEER_SUB_LIST_SIZE 10
#define WLAN_MAC_MAX_EXTN_CAP 8
#define WLAN_MAC_MAX_SUPP_CHANNELS 100
#define WLAN_MAX_SUPP_OPER_CLASSES 32
#define WLAN_MAC_MAX_SUPP_RATES 32
#define ENABLE_CHANSWITCH 1
#define WLAN_TDLS_STA_MAX_NUM 8
#define WLAN_TDLS_STA_P_UAPSD_OFFCHAN_MAX_NUM 1
#define WLAN_TDLS_PEER_LIST_SIZE 16
#define WLAN_TDLS_CT_TABLE_SIZE 8
#define WLAN_TDLS_PEER_SUB_LIST_SIZE 10
#define WLAN_MAC_MAX_EXTN_CAP 8
#define WLAN_MAC_MAX_SUPP_CHANNELS 100
#define WLAN_MAX_SUPP_OPER_CLASSES 32
#define WLAN_MAC_MAX_SUPP_RATES 32
#define WLAN_CHANNEL_14 14
#define ENABLE_CHANSWITCH 1
#define DISABLE_CHANSWITCH 2
#define WLAN_TDLS_PREFERRED_OFF_CHANNEL_NUM_MIN 1
#define WLAN_TDLS_PREFERRED_OFF_CHANNEL_NUM_MAX 165
#define WLAN_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEF 36
/** Maximum time(ms) to wait for tdls add sta to complete **/
#define WAIT_TIME_TDLS_ADD_STA 1500
/** Maximum time(ms) to wait for tdls del sta to complete **/
#define WAIT_TIME_TDLS_DEL_STA 1500
/** Maximum time(ms) to wait for Link Establish Req to complete **/
#define WAIT_TIME_TDLS_LINK_ESTABLISH_REQ 1500
/** Maximum time(ms) to wait for tdls mgmt to complete **/
#define WAIT_TIME_TDLS_MGMT 11000
#define TDLS_TEARDOWN_PEER_UNREACHABLE 25
#define TDLS_TEARDOWN_PEER_UNSPEC_REASON 26
#define TDLS_STA_INDEX_CHECK(sta_id) \
(((sta_id) >= 1) && ((sta_id) < 0xFF))
@ -65,7 +86,23 @@ enum tdls_peer_capab {
};
/**
* enum tdls_link_status - tdls link status
* enum tdls_peer_state - tdls peer state
* @TDLS_PEER_STATE_PEERING: tdls connection in progress
* @TDLS_PEER_STATE_CONNCTED: tdls peer is connected
* @TDLS_PEER_STATE_TEARDOWN: tdls peer is tear down
* @TDLS_PEER_ADD_MAC_ADDR: add peer mac into connection table
* @TDLS_PEER_REMOVE_MAC_ADDR: remove peer mac from connection table
*/
enum tdls_peer_state {
TDLS_PEER_STATE_PEERING,
TDLS_PEER_STATE_CONNCTED,
TDLS_PEER_STATE_TEARDOWN,
TDLS_PEER_ADD_MAC_ADDR,
TDLS_PEER_REMOVE_MAC_ADDR
};
/**
* enum tdls_link_state - tdls link state
* @TDLS_LINK_IDLE: tdls link idle
* @TDLS_LINK_DISCOVERING: tdls link discovering
* @TDLS_LINK_DISCOVERED: tdls link discovered
@ -73,7 +110,7 @@ enum tdls_peer_capab {
* @TDLS_LINK_CONNECTED: tdls link connected
* @TDLS_LINK_TEARING: tdls link tearing
*/
enum tdls_link_status {
enum tdls_link_state {
TDLS_LINK_IDLE = 0,
TDLS_LINK_DISCOVERING,
TDLS_LINK_DISCOVERED,
@ -83,7 +120,7 @@ enum tdls_link_status {
};
/**
* enum tdls_link_reason - tdls link reason
* enum tdls_link_state_reason - tdls link reason
* @TDLS_LINK_SUCCESS: Success
* @TDLS_LINK_UNSPECIFIED: Unspecified reason
* @TDLS_LINK_NOT_SUPPORTED: Remote side doesn't support TDLS
@ -91,7 +128,7 @@ enum tdls_link_status {
* @TDLS_LINK_NOT_BENEFICIAL: Going to AP is better than direct
* @TDLS_LINK_DROPPED_BY_REMOTE: Remote side doesn't want it anymore
*/
enum tdls_link_reason {
enum tdls_link_state_reason {
TDLS_LINK_SUCCESS,
TDLS_LINK_UNSPECIFIED = -1,
TDLS_LINK_NOT_SUPPORTED = -2,
@ -101,7 +138,7 @@ enum tdls_link_reason {
};
/**
* enum tdls_support_mode - TDLS support mode
* enum tdls_feature_mode - TDLS support mode
* @TDLS_SUPPORT_DISABLED: Disabled in ini or FW
* @TDLS_SUPPORT_SUSPENDED: TDLS supported by ini and FW, but disabled
* temporarily due to off-channel operations or due to other reasons
@ -109,7 +146,7 @@ enum tdls_link_reason {
* @TDLS_SUPPORT_IMP_MODE: Implicit mode
* @TDLS_SUPPORT_EXT_CONTROL: External control mode
*/
enum tdls_support_mode {
enum tdls_feature_mode {
TDLS_SUPPORT_DISABLED = 0,
TDLS_SUPPORT_SUSPENDED,
TDLS_SUPPORT_EXP_TRIG_ONLY,
@ -124,6 +161,9 @@ enum tdls_support_mode {
* @TDLS_EVENT_RX_MGMT: rx discovery response frame
* @TDLS_EVENT_ADD_PEER: add peer or update peer
* @TDLS_EVENT_DEL_PEER: delete peer
* @TDLS_EVENT_DISCOVERY_REQ: dicovery request
* @TDLS_EVENT_TEARDOWN_REQ: teardown request
* @TDLS_EVENT_SETUP_REQ: setup request
*/
enum tdls_event_type {
TDLS_EVENT_VDEV_STATE_CHANGE = 0,
@ -131,11 +171,13 @@ enum tdls_event_type {
TDLS_EVENT_RX_MGMT,
TDLS_EVENT_ADD_PEER,
TDLS_EVENT_DEL_PEER,
TDLS_EVENT_DISCOVERY_REQ,
TDLS_EVENT_TEARDOWN_REQ,
TDLS_EVENT_SETUP_REQ,
};
/**
* enum tdls_state_t - tdls state
*
* @QCA_WIFI_HAL_TDLS_DISABLED: TDLS is not enabled, or is disabled now
* @QCA_WIFI_HAL_TDLS_ENABLED: TDLS is enabled, but not yet tried
* @QCA_WIFI_HAL_TDLS_ESTABLISHED: Direct link is established
@ -152,12 +194,25 @@ enum tdls_state_t {
QCA_WIFI_HAL_TDLS_S_FAILED,
};
/**
* enum tdls_off_chan_mode - mode for WMI_TDLS_SET_OFFCHAN_MODE_CMDID
* @TDLS_ENABLE_OFFCHANNEL: enable off channel
* @TDLS_DISABLE_OFFCHANNEL: disable off channel
*/
enum tdls_off_chan_mode {
TDLS_ENABLE_OFFCHANNEL,
TDLS_DISABLE_OFFCHANNEL
};
/**
* enum tdls_event_msg_type - TDLS event message type
* @TDLS_SHOULD_DISCOVER: should do discover
* @TDLS_SHOULD_TEARDOWN: notify teardown the link
* @TDLS_SHOULD_DISCOVER: should do discover for peer (based on tx bytes per
* second > tx_discover threshold)
* @TDLS_SHOULD_TEARDOWN: recommend teardown the link for peer due to tx bytes
* per second below tx_teardown_threshold
* @TDLS_PEER_DISCONNECTED: tdls peer disconnected
* @TDLS_CONNECTION_TRACKER_NOTIFY: connection tracker notify
* @TDLS_CONNECTION_TRACKER_NOTIFY: TDLS/BT role change notification for
* connection tracker
*/
enum tdls_event_msg_type {
TDLS_SHOULD_DISCOVER = 0,
@ -168,19 +223,25 @@ enum tdls_event_msg_type {
/**
* enum tdls_event_reason - TDLS event reason
* @TDLS_TEARDOWN_TX:
* @TDLS_TEARDOWN_RSSI:
* @TDLS_TEARDOWN_SCAN:
* @TDLS_TEARDOWN_PTR_TIMEOUT:
* @TDLS_TEARDOWN_BAD_PTR:
* @TDLS_TEARDOWN_NO_RSP:
* @TDLS_DISCONNECTED_PEER_DELETE:
* @TDLS_PEER_ENTER_BUF_STA:
* @TDLS_PEER_EXIT_BUF_STA:
* @TDLS_ENTER_BT_BUSY:
* @TDLS_EXIT_BT_BUSY:
* @DLS_SCAN_STARTED:
* @TDLS_SCAN_COMPLETED:
* @TDLS_TEARDOWN_TX: tdls teardown recommended due to low transmits
* @TDLS_TEARDOWN_RSSI: tdls link tear down recommended due to poor RSSI
* @TDLS_TEARDOWN_SCAN: tdls link tear down recommended due to offchannel scan
* @TDLS_TEARDOWN_PTR_TIMEOUT: tdls peer disconnected due to PTR timeout
* @TDLS_TEARDOWN_BAD_PTR: tdls peer disconnected due wrong PTR format
* @TDLS_TEARDOWN_NO_RSP: tdls peer not responding
* @TDLS_DISCONNECTED_PEER_DELETE: tdls peer disconnected due to peer deletion
* @TDLS_PEER_ENTER_BUF_STA: tdls entered buffer STA role, TDLS connection
* tracker needs to handle this
* @TDLS_PEER_EXIT_BUF_STA: tdls exited buffer STA role, TDLS connection tracker
* needs to handle this
* @TDLS_ENTER_BT_BUSY: BT entered busy mode, TDLS connection tracker needs to
* handle this
* @TDLS_EXIT_BT_BUSY: BT exited busy mode, TDLS connection tracker needs to
* handle this
* @DLS_SCAN_STARTED: TDLS module received a scan start event, TDLS connection
* tracker needs to handle this
* @TDLS_SCAN_COMPLETED: TDLS module received a scan complete event, TDLS
* connection tracker needs to handle this
*/
enum tdls_event_reason {
TDLS_TEARDOWN_TX,
@ -198,6 +259,19 @@ enum tdls_event_reason {
TDLS_SCAN_COMPLETED,
};
/**
* struct tdls_osif_indication - tdls indication to os if layer
* @vdev: vdev object
* @reason: used with teardown indication
* @peer_mac: MAC address of the TDLS peer
*/
struct tdls_osif_indication {
struct wlan_objmgr_vdev *vdev;
uint16_t reason;
uint8_t peer_mac[QDF_MAC_ADDR_SIZE];
QDF_STATUS status;
};
/**
* struct tx_frame - tx frame
* @buf: frame buffer
@ -268,13 +342,14 @@ enum tdls_feature_bit {
* @tdls_pre_off_chan_num: tdls off channel number
* @tdls_pre_off_chan_bw: tdls off channel bandwidth
* @tdls_peer_kickout_threshold: sta kickout threshold for tdls peer
* @delayed_trig_framint: delayed trigger frame interval
*/
struct tdls_user_config {
uint32_t tdls_tx_states_period;
uint32_t tdls_tx_pkt_threshold;
uint32_t tdls_rx_pkt_threshold;
uint32_t tdls_max_discovery_attempt;
uint32_t tdls_idle_timeoute;
uint32_t tdls_idle_timeout;
uint32_t tdls_idle_pkt_threshold;
uint32_t tdls_rssi_trigger_threshold;
uint32_t tdls_rssi_teardown_threshold;
@ -287,6 +362,7 @@ struct tdls_user_config {
uint32_t tdls_pre_off_chan_num;
uint32_t tdls_pre_off_chan_bw;
uint32_t tdls_peer_kickout_threshold;
uint32_t delayed_trig_framint;
};
/**
@ -331,32 +407,60 @@ struct tdls_tx_cnf {
/* This callback is used to report state change of peer to wpa_supplicant */
typedef int (*tdls_state_change_callback)(const uint8_t *mac,
uint32_t opclass,
uint32_t channel,
uint32_t state,
int32_t reason, void *ctx);
uint32_t opclass,
uint32_t channel,
uint32_t state,
int32_t reason, void *ctx);
/* This callback is used to report events to os_if layer */
typedef QDF_STATUS (*tdls_evt_callback) (void *data,
enum tdls_event_type ev_type,
void *event);
typedef void (*tdls_evt_callback) (void *data,
enum tdls_event_type ev_type,
struct tdls_osif_indication *event);
/* prototype of callback registered by hdd to receive the ack cnf */
typedef int (*tdls_tx_ack_cnf_callback)(void *user_data,
struct tdls_tx_cnf *tx_ack_cnf_cb_data);
struct tdls_tx_cnf *tx_ack_cnf_cb_data);
/* This callback is used to register TDLS peer with TL */
typedef QDF_STATUS (*tdls_register_tl_peer_callback)(void *userdata,
uint32_t vdev_id,
const uint8_t *mac,
uint16_t stat_id,
uint8_t ucastsig,
uint8_t qos);
/* This callback is used to deregister TDLS peer */
typedef QDF_STATUS (*tdls_deregister_tl_peer_callback)(void *userdata,
uint32_t vdev_id,
uint8_t sta_id);
/**
* struct tdls_start_params - tdls start params
* @config: tdls user config
* @tdls_send_mgmt_req: pass eWNI_SME_TDLS_SEND_MGMT_REQ value
* @tdls_add_sta_req: pass eWNI_SME_TDLS_ADD_STA_REQ value
* @tdls_del_sta_req: pass eWNI_SME_TDLS_DEL_STA_REQ value
* @tdls_update_peer_state: pass WMA_UPDATE_TDLS_PEER_STATE value
* @tdls_event_cb: tdls event callback
* @tdls_evt_cb_data: tdls event data
* @ack_cnf_cb: tdls tx ack callback to indicate the tx status
* @tx_ack_cnf_cb_data: tdls tx ack user data
* @tdls_reg_tl_peer: tdls register tdls peer
* @tdls_dereg_tl_peer: tdls deregister tdls peer
* @tdls_tl_peer_data: userdata for register/deregister TDLS peer
*/
struct tdls_start_params {
struct tdls_user_config config;
uint16_t tdls_send_mgmt_req;
uint16_t tdls_add_sta_req;
uint16_t tdls_del_sta_req;
uint16_t tdls_update_peer_state;
tdls_evt_callback tdls_event_cb;
void *tdls_evt_cb_data;
tdls_tx_ack_cnf_callback ack_cnf_cb;
void *tx_ack_cnf_cb_data;
tdls_register_tl_peer_callback tdls_reg_tl_peer;
tdls_deregister_tl_peer_callback tdls_dereg_tl_peer;
void *tdls_tl_peer_data;
};
/**
@ -366,7 +470,7 @@ struct tdls_start_params {
* @vdev_id: vdev id
*/
struct tdls_add_peer_params {
const uint8_t *peer_addr;
uint8_t peer_addr[QDF_MAC_ADDR_SIZE];
uint32_t peer_type;
uint32_t vdev_id;
};
@ -437,7 +541,7 @@ struct vhtcap {
};
struct tdls_update_peer_params {
const uint8_t *peer_addr;
uint8_t peer_addr[QDF_MAC_ADDR_SIZE];
uint32_t peer_type;
uint32_t vdev_id;
uint16_t capability;
@ -454,6 +558,7 @@ struct tdls_update_peer_params {
uint8_t supported_channels[WLAN_MAC_MAX_SUPP_CHANNELS];
uint8_t supported_oper_classes_len;
uint8_t supported_oper_classes[WLAN_MAX_SUPP_OPER_CLASSES];
bool is_qos_wmm_sta;
};
struct tdls_update_peer_request {
@ -461,6 +566,36 @@ struct tdls_update_peer_request {
struct tdls_update_peer_params update_peer_req;
};
/**
* struct tdls_oper_request - tdls operation request
* @vdev: vdev object
* @peer_addr: MAC address of the TDLS peer
*/
struct tdls_oper_request {
struct wlan_objmgr_vdev *vdev;
uint8_t peer_addr[QDF_MAC_ADDR_SIZE];
};
/**
* struct tdls_oper_config_force_peer_request - tdls enable force peer request
* @vdev: vdev object
* @peer_addr: MAC address of the TDLS peer
* @chan: channel
* @max_latency: maximum latency
* @op_class: operation class
* @min_bandwidth: minimal bandwidth
* @callback: state change callback
*/
struct tdls_oper_config_force_peer_request {
struct wlan_objmgr_vdev *vdev;
uint8_t peer_addr[QDF_MAC_ADDR_SIZE];
uint32_t chan;
uint32_t max_latency;
uint32_t op_class;
uint32_t min_bandwidth;
tdls_state_change_callback callback;
};
/**
* struct tdls_info - tdls info
*
@ -550,20 +685,22 @@ struct tdls_peer_params {
};
/**
* struct tdls_peer_update_params - TDLS peer state parameters
* struct tdls_peer_update_state - TDLS peer state parameters
* @vdev_id: vdev id
* @peer_macaddr: peer mac address
* @peer_cap: peer capabality
* @resp_reqd: response needed
*/
struct tdls_peer_update_params {
struct tdls_peer_update_state {
uint32_t vdev_id;
uint8_t peer_macaddr[QDF_MAC_ADDR_SIZE];
uint32_t peer_state;
struct tdls_peer_params peer_cap;
bool resp_reqd;
};
/**
* struct tdls_chan_switch_params - channel switch parameter structure
* struct tdls_channel_switch_params - channel switch parameter structure
* @vdev_id: vdev ID
* @peer_mac_addr: Peer mac address
* @tdls_off_ch_bw_offset: Target off-channel bandwitdh offset
@ -571,7 +708,7 @@ struct tdls_peer_update_params {
* @oper_class: Operating class for target channel
* @is_responder: Responder or initiator
*/
struct tdls_chan_switch_params {
struct tdls_channel_switch_params {
uint32_t vdev_id;
uint8_t peer_mac_addr[QDF_MAC_ADDR_SIZE];
uint16_t tdls_off_ch_bw_offset;

View file

@ -28,6 +28,9 @@
#include <scheduler_api.h>
#include <wlan_tdls_public_structs.h>
#include <wlan_objmgr_cmn.h>
#include <wlan_objmgr_psoc_obj.h>
#include <wlan_objmgr_pdev_obj.h>
#include <wlan_objmgr_vdev_obj.h>
/**
* ucfg_tdls_init() - TDLS module initialization API
@ -66,8 +69,9 @@ QDF_STATUS ucfg_tdls_psoc_close(struct wlan_objmgr_psoc *psoc);
*
* Return: QDF_STATUS
*/
QDF_STATUS ucfg_tdls_psoc_start(struct wlan_objmgr_psoc *psoc,
struct tdls_start_params *req);
QDF_STATUS ucfg_tdls_update_config(struct wlan_objmgr_psoc *psoc,
struct tdls_start_params *req);
/**
* ucfg_tdls_psoc_stop() - TDLS module stop
* @psoc: psoc object
@ -75,4 +79,24 @@ QDF_STATUS ucfg_tdls_psoc_start(struct wlan_objmgr_psoc *psoc,
* Return: QDF_STATUS
*/
QDF_STATUS ucfg_tdls_psoc_stop(struct wlan_objmgr_psoc *psoc);
/**
* ucfg_tdls_add_peer() - handle TDLS add peer
* @vdev: vdev object
* @add_peer_req: add peer request parameters
*
* Return: QDF_STATUS
*/
QDF_STATUS ucfg_tdls_add_peer(struct wlan_objmgr_vdev *vdev,
struct tdls_add_peer_params *add_peer_req);
/**
* ucfg_tdls_update_peer() - handle TDLS update peer
* @vdev: vdev object
* @update_peer: update TDLS request parameters
*
* Return: QDF_STATUS
*/
QDF_STATUS ucfg_tdls_update_peer(struct wlan_objmgr_vdev *vdev,
struct tdls_update_peer_params *update_peer);
#endif

View file

@ -24,6 +24,7 @@
#include <wlan_tdls_ucfg_api.h>
#include "../../core/src/wlan_tdls_main.h"
#include "../../core/src/wlan_tdls_cmds_process.h"
#include <wlan_objmgr_global_obj.h>
#include <wlan_objmgr_cmn.h>
@ -113,6 +114,7 @@ QDF_STATUS ucfg_tdls_deinit(void)
static QDF_STATUS tdls_global_init(struct tdls_soc_priv_obj *soc_obj)
{
uint8_t sta_idx;
uint32_t feature;
soc_obj->connected_peer_count = 0;
soc_obj->tdls_nss_switch_in_progress = false;
@ -120,7 +122,16 @@ static QDF_STATUS tdls_global_init(struct tdls_soc_priv_obj *soc_obj)
soc_obj->tdls_nss_teardown_complete = false;
soc_obj->tdls_nss_transition_mode = TDLS_NSS_TRANSITION_S_UNKNOWN;
soc_obj->tdls_user_config_mode = TDLS_SUPPORT_DISABLED;
soc_obj->max_num_tdls_sta = WLAN_TDLS_STA_MAX_NUM;
feature = soc_obj->tdls_configs.tdls_feature_flags;
if (TDLS_IS_BUFFER_STA_ENABLED(feature) ||
TDLS_IS_SLEEP_STA_ENABLED(feature) ||
TDLS_IS_OFF_CHANNEL_ENABLED(feature))
soc_obj->max_num_tdls_sta =
WLAN_TDLS_STA_P_UAPSD_OFFCHAN_MAX_NUM;
else
soc_obj->max_num_tdls_sta = WLAN_TDLS_STA_MAX_NUM;
for (sta_idx = 0; sta_idx < soc_obj->max_num_tdls_sta; sta_idx++) {
soc_obj->tdls_conn_info[sta_idx].sta_id = 0;
@ -142,7 +153,7 @@ QDF_STATUS ucfg_tdls_psoc_open(struct wlan_objmgr_psoc *psoc)
tdls_notice("tdls psoc open");
soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_TDLS);
if (soc_obj == NULL) {
if (!soc_obj) {
tdls_err("Failed to get tdls psoc component");
return QDF_STATUS_E_FAILURE;
}
@ -152,15 +163,21 @@ QDF_STATUS ucfg_tdls_psoc_open(struct wlan_objmgr_psoc *psoc)
return status;
}
QDF_STATUS ucfg_tdls_psoc_start(struct wlan_objmgr_psoc *psoc,
struct tdls_start_params *req)
QDF_STATUS ucfg_tdls_update_config(struct wlan_objmgr_psoc *psoc,
struct tdls_start_params *req)
{
struct tdls_soc_priv_obj *soc_obj;
uint32_t tdls_feature_flags;
tdls_notice("tdls update config ");
if (!psoc || !req) {
tdls_err("psoc: 0x%p, req: 0x%p", psoc, req);
return QDF_STATUS_E_FAILURE;
}
tdls_notice("tdls psoc start");
soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_TDLS);
if (soc_obj == NULL) {
if (!soc_obj) {
tdls_err("Failed to get tdls psoc component");
return QDF_STATUS_E_FAILURE;
}
@ -171,6 +188,28 @@ QDF_STATUS ucfg_tdls_psoc_start(struct wlan_objmgr_psoc *psoc,
soc_obj->tdls_tx_cnf_cb = req->ack_cnf_cb;
soc_obj->tx_ack_cnf_cb_data = req->tx_ack_cnf_cb_data;
/* Save callbacks to register/deregister TDLS sta with TL */
soc_obj->tdls_reg_tl_peer = req->tdls_reg_tl_peer;
soc_obj->tdls_dereg_tl_peer = req->tdls_dereg_tl_peer;
soc_obj->tdls_tl_peer_data = req->tdls_tl_peer_data;
/* Save legacy PE/WMA commands in TDLS soc object */
soc_obj->tdls_send_mgmt_req = req->tdls_send_mgmt_req;
soc_obj->tdls_add_sta_req = req->tdls_add_sta_req;
soc_obj->tdls_del_sta_req = req->tdls_del_sta_req;
soc_obj->tdls_update_peer_state = req->tdls_update_peer_state;
/* Update TDLS user config */
qdf_mem_copy(&soc_obj->tdls_configs, &req->config, sizeof(req->config));
tdls_feature_flags = soc_obj->tdls_configs.tdls_feature_flags;
if (!TDLS_IS_IMPLICIT_TRIG_ENABLED(tdls_feature_flags))
soc_obj->tdls_current_mode = TDLS_SUPPORT_EXP_TRIG_ONLY;
else if (TDLS_IS_EXTERNAL_CONTROL_ENABLED(tdls_feature_flags))
soc_obj->tdls_current_mode = TDLS_SUPPORT_EXT_CONTROL;
else
soc_obj->tdls_current_mode = TDLS_SUPPORT_IMP_MODE;
return QDF_STATUS_SUCCESS;
}
@ -181,7 +220,7 @@ QDF_STATUS ucfg_tdls_psoc_stop(struct wlan_objmgr_psoc *psoc)
tdls_notice("tdls psoc stop");
soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_TDLS);
if (soc_obj == NULL) {
if (!soc_obj) {
tdls_err("Failed to get tdls psoc component");
return QDF_STATUS_E_FAILURE;
}
@ -203,3 +242,93 @@ QDF_STATUS ucfg_tdls_psoc_close(struct wlan_objmgr_psoc *psoc)
return status;
}
QDF_STATUS ucfg_tdls_add_peer(struct wlan_objmgr_vdev *vdev,
struct tdls_add_peer_params *add_peer_req)
{
struct scheduler_msg msg = {0, };
struct tdls_add_peer_request *req;
QDF_STATUS status;
if (!vdev || !add_peer_req) {
tdls_err("vdev: %p, req %p", vdev, add_peer_req);
return QDF_STATUS_E_NULL_VALUE;
}
tdls_debug("vdevid: %d, peertype: %d",
add_peer_req->vdev_id, add_peer_req->peer_type);
status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID);
if (QDF_IS_STATUS_ERROR(status)) {
tdls_err("can't get vdev");
return status;
}
req = qdf_mem_malloc(sizeof(*req));
if (!req) {
tdls_err("mem allocate fail");
status = QDF_STATUS_E_NOMEM;
goto dec_ref;
}
qdf_mem_copy(&req->add_peer_req, add_peer_req, sizeof(*add_peer_req));
req->vdev = vdev;
msg.bodyptr = req;
msg.callback = tdls_process_cmd;
msg.type = TDLS_CMD_ADD_STA;
status = scheduler_post_msg(QDF_MODULE_ID_OS_IF, &msg);
if (QDF_IS_STATUS_ERROR(status)) {
tdls_err("post add peer msg fail");
qdf_mem_free(req);
goto dec_ref;
}
return status;
dec_ref:
wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
return status;
}
QDF_STATUS ucfg_tdls_update_peer(struct wlan_objmgr_vdev *vdev,
struct tdls_update_peer_params *update_peer)
{
struct scheduler_msg msg = {0,};
struct tdls_update_peer_request *req;
QDF_STATUS status;
if (!vdev || !update_peer) {
tdls_err("vdev: %p, update_peer: %p", vdev, update_peer);
return QDF_STATUS_E_NULL_VALUE;
}
tdls_debug("vdev_id: %d, peertype: %d",
update_peer->vdev_id, update_peer->peer_type);
status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID);
if (QDF_IS_STATUS_ERROR(status)) {
tdls_err("can't get vdev");
return status;
}
req = qdf_mem_malloc(sizeof(*req));
if (!req) {
tdls_err("mem allocate fail");
status = QDF_STATUS_E_NOMEM;
goto dec_ref;
}
qdf_mem_copy(&req->update_peer_req, update_peer, sizeof(*update_peer));
req->vdev = vdev;
msg.bodyptr = req;
msg.callback = tdls_process_cmd;
msg.type = TDLS_CMD_CHANGE_STA;
status = scheduler_post_msg(QDF_MODULE_ID_OS_IF, &msg);
if (QDF_IS_STATUS_ERROR(status)) {
tdls_err("post update peer msg fail");
qdf_mem_free(req);
goto dec_ref;
}
return status;
dec_ref:
wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
return status;
}