diff --git a/os_if/linux/tdls/inc/wlan_cfg80211_tdls.h b/os_if/linux/tdls/inc/wlan_cfg80211_tdls.h index 42eab3865b16..c4efaadb3ec2 100644 --- a/os_if/linux/tdls/inc/wlan_cfg80211_tdls.h +++ b/os_if/linux/tdls/inc/wlan_cfg80211_tdls.h @@ -33,6 +33,9 @@ #include #include + +#define TDLS_VDEV_MAGIC 0x54444c53 /* "TDLS" */ + /** * struct osif_tdls_vdev - OS tdls vdev private structure * @tdls_add_peer_comp: Completion to add tdls peer @@ -52,6 +55,26 @@ struct osif_tdls_vdev { uint32_t mgmt_tx_completion_status; }; +/** + * enum qca_wlan_vendor_tdls_trigger_mode_vdev_map: Maps the user space TDLS + * trigger mode in the host driver. + * @WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT: TDLS Connection and + * disconnection handled by user space. + * @WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT: TDLS connection and + * disconnection controlled by host driver based on data traffic. + * @WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL: TDLS connection and + * disconnection jointly controlled by user space and host driver. + */ +enum qca_wlan_vendor_tdls_trigger_mode_vdev_map { + WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT = + QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT, + WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT = + QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT, + WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL = + ((QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT | + QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT) << 1), +}; + /** * wlan_cfg80211_tdls_priv_init() - API to initialize tdls os private * @osif_priv: vdev os private @@ -96,6 +119,17 @@ int wlan_cfg80211_tdls_update_peer(struct wlan_objmgr_pdev *pdev, struct net_device *dev, const uint8_t *mac, struct station_parameters *params); + +/** + * wlan_cfg80211_tdls_configure_mode() - configure tdls mode + * @vdev: vdev obj manager + * @trigger_mode: tdls trgger mode + * + * Return: 0 for success; negative errno otherwise + */ +int wlan_cfg80211_tdls_configure_mode(struct wlan_objmgr_vdev *vdev, + uint32_t trigger_mode); + /** * wlan_cfg80211_tdls_oper() - process cfg80211 operation on an TDLS peer * @pdev: pdev object @@ -110,6 +144,27 @@ int wlan_cfg80211_tdls_oper(struct wlan_objmgr_pdev *pdev, const uint8_t *peer, enum nl80211_tdls_operation oper); +/** + * wlan_cfg80211_tdls_mgmt() - process tdls management frames from the supplicant + * @pdev: pdev object + * @dev: net device + * @peer: MAC address of the TDLS peer + * @action_code: type of TDLS mgmt frame to be sent + * @dialog_token: dialog token used in the frame + * @status_code: status to be incuded in the frame + * @peer_capability: peer capability information + * @buf: additional IEs to be included + * @len: lenght of additional Ies + * @oper: cfg80211 TDLS operation + * + * Return: 0 on success; negative errno otherwise + */ +int wlan_cfg80211_tdls_mgmt(struct wlan_objmgr_pdev *pdev, + struct net_device *dev, const uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + const uint8_t *buf, size_t len); + /** * wlan_cfg80211_tdls_event_callback() - callback for tdls module * @userdata: user data @@ -123,4 +178,17 @@ int wlan_cfg80211_tdls_oper(struct wlan_objmgr_pdev *pdev, void wlan_cfg80211_tdls_event_callback(void *userdata, enum tdls_event_type type, struct tdls_osif_indication *param); + +/** + * wlan_cfg80211_tdls_rx_callback() - Callback for rx mgmt frame + * @user_data: pointer to soc object + * @rx_frame: RX mgmt frame information + * + * This callback will be used to rx frames in os interface. + * + * Return: None + */ +void wlan_cfg80211_tdls_rx_callback(void *user_data, + struct tdls_rx_mgmt_frame *rx_frame); + #endif diff --git a/os_if/linux/tdls/src/wlan_cfg80211_tdls.c b/os_if/linux/tdls/src/wlan_cfg80211_tdls.c index cee276852202..714b5f594b02 100644 --- a/os_if/linux/tdls/src/wlan_cfg80211_tdls.c +++ b/os_if/linux/tdls/src/wlan_cfg80211_tdls.c @@ -36,6 +36,9 @@ #define MAX_CHANNEL (NUM_24GHZ_CHANNELS + NUM_5GHZ_CHANNELS) + +#define TDLS_MAX_NO_OF_2_4_CHANNELS 14 + QDF_STATUS wlan_cfg80211_tdls_priv_init(struct vdev_osif_priv *osif_priv) { struct osif_tdls_vdev *tdls_priv; @@ -370,6 +373,41 @@ static enum tdls_command_type tdls_oper_to_cmd(enum nl80211_tdls_operation oper) return 0; } +int wlan_cfg80211_tdls_configure_mode(struct wlan_objmgr_vdev *vdev, + uint32_t trigger_mode) +{ + enum tdls_feature_mode tdls_mode; + struct tdls_set_mode_params set_mode_params; + int status; + + if (!vdev) + return -EINVAL; + + switch (trigger_mode) { + case WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT: + tdls_mode = TDLS_SUPPORT_IMP_MODE; + break; + case WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL: + tdls_mode = TDLS_SUPPORT_EXT_CONTROL; + break; + case WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT: + tdls_mode = TDLS_SUPPORT_IMP_MODE; + break; + default: + cfg80211_err("Invalid TDLS trigger mode"); + return -EINVAL; + } + + cfg80211_notice("cfg80211 tdls trigger mode %d", trigger_mode); + set_mode_params.source = TDLS_SET_MODE_SOURCE_USER; + set_mode_params.tdls_mode = tdls_mode; + set_mode_params.update_last = false; + set_mode_params.vdev = vdev; + + status = ucfg_tdls_set_operating_mode(&set_mode_params); + return status; +} + int wlan_cfg80211_tdls_oper(struct wlan_objmgr_pdev *pdev, struct net_device *dev, const uint8_t *peer, @@ -442,6 +480,196 @@ error: return status; } +void wlan_cfg80211_tdls_rx_callback(void *user_data, + struct tdls_rx_mgmt_frame *rx_frame) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_vdev *vdev; + struct vdev_osif_priv *osif_priv; + struct wireless_dev *wdev; + uint16_t freq; + + cfg80211_debug("user data:%p, vdev id:%d, rssi:%d, buf:%p, len:%d", + user_data, rx_frame->vdev_id, rx_frame->rx_rssi, + rx_frame->buf, rx_frame->frame_len); + + psoc = user_data; + if (!psoc) { + cfg80211_err("psoc is null"); + return; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + rx_frame->vdev_id, WLAN_TDLS_NB_ID); + if (!vdev) { + cfg80211_err("vdev is null"); + return; + } + + wlan_vdev_obj_lock(vdev); + osif_priv = wlan_vdev_get_ospriv(vdev); + wlan_vdev_obj_unlock(vdev); + if (!osif_priv) { + cfg80211_err("osif_priv is null"); + goto fail; + } + + wdev = osif_priv->wdev; + if (!wdev) { + cfg80211_err("wdev is null"); + goto fail; + } + + if (rx_frame->rx_chan <= TDLS_MAX_NO_OF_2_4_CHANNELS) + freq = ieee80211_channel_to_frequency( + rx_frame->rx_chan, NL80211_BAND_2GHZ); + else + freq = ieee80211_channel_to_frequency( + rx_frame->rx_chan, NL80211_BAND_5GHZ); + + cfg80211_notice("Indicate frame over nl80211, vdev id:%d, idx:%d", + rx_frame->vdev_id, wdev->netdev->ifindex); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) + cfg80211_rx_mgmt(wdev, freq, rx_frame->rx_rssi * 100, + rx_frame->buf, rx_frame->frame_len, + NL80211_RXMGMT_FLAG_ANSWERED); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) + cfg80211_rx_mgmt(wdev, freq, rx_frame->rx_rssi * 100, + rx_frame->buf, rx_frame->frame_len, + NL80211_RXMGMT_FLAG_ANSWERED, GFP_ATOMIC); +#else + cfg80211_rx_mgmt(wdev, freq, rx_frame->rx_rssi * 100, + rx_frame->buf, rx_frame->frame_len, GFP_ATOMIC); +#endif /* LINUX_VERSION_CODE */ +fail: + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); +} + +int wlan_cfg80211_tdls_mgmt(struct wlan_objmgr_pdev *pdev, + struct net_device *dev, const uint8_t *peer_mac, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + const uint8_t *buf, size_t len) +{ + struct wlan_objmgr_vdev *vdev; + struct tdls_action_frame_request mgmt_req; + struct vdev_osif_priv *osif_priv; + struct osif_tdls_vdev *tdls_priv; + int status; + unsigned long rc; + int max_sta_failed = 0; + struct tdls_validate_action_req chk_frame; + struct tdls_set_responder_req set_responder; + + vdev = wlan_objmgr_get_vdev_by_macaddr_from_pdev(pdev, + dev->dev_addr, + WLAN_OSIF_ID); + if (vdev == NULL) { + cfg80211_err("vdev object is NULL"); + return -EIO; + } + + wlan_vdev_obj_lock(vdev); + osif_priv = wlan_vdev_get_ospriv(vdev); + wlan_vdev_obj_unlock(vdev); + + tdls_priv = osif_priv->osif_tdls; + + /* make sure doesn't call send_mgmt() while it is pending */ + if (TDLS_VDEV_MAGIC == tdls_priv->mgmt_tx_completion_status) { + cfg80211_err(QDF_MAC_ADDRESS_STR " action %d couldn't sent, as one is pending. return EBUSY", + QDF_MAC_ADDR_ARRAY(peer_mac), action_code); + wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID); + return -EBUSY; + } + + /* Reset TDLS VDEV magic */ + tdls_priv->mgmt_tx_completion_status = TDLS_VDEV_MAGIC; + + + /*prepare the request */ + + /* Validate the management Request */ + chk_frame.vdev = vdev; + chk_frame.action_code = action_code; + qdf_mem_copy(chk_frame.peer_mac, peer_mac, QDF_MAC_ADDR_SIZE); + chk_frame.dialog_token = dialog_token; + chk_frame.action_code = action_code; + chk_frame.status_code = status_code; + chk_frame.len = len; + chk_frame.max_sta_failed = max_sta_failed; + + mgmt_req.chk_frame = &chk_frame; + + mgmt_req.vdev = vdev; + mgmt_req.vdev_id = wlan_vdev_get_id(vdev); + mgmt_req.session_id = mgmt_req.vdev_id; + /* populate management req params */ + qdf_mem_copy(mgmt_req.tdls_mgmt.peer_mac.bytes, + peer_mac, QDF_MAC_ADDR_SIZE); + mgmt_req.tdls_mgmt.dialog = dialog_token; + mgmt_req.tdls_mgmt.frame_type = action_code; + mgmt_req.tdls_mgmt.len = len; + mgmt_req.tdls_mgmt.peer_capability = peer_capability; + mgmt_req.tdls_mgmt.status_code = chk_frame.status_code; + + /*populate the additional IE's */ + mgmt_req.cmd_buf = buf; + mgmt_req.len = len; + + reinit_completion(&tdls_priv->tdls_mgmt_comp); + status = ucfg_tdls_send_mgmt_frame(&mgmt_req); + if (QDF_IS_STATUS_ERROR(status)) { + cfg80211_err("ucfg_tdls_send_mgmt failed err %d", status); + status = -EIO; + tdls_priv->mgmt_tx_completion_status = false; + goto error_mgmt_req; + } + + cfg80211_info("Wait for tdls_mgmt_comp. Timeout %u ms", + WAIT_TIME_FOR_TDLS_MGMT); + + rc = wait_for_completion_timeout( + &tdls_priv->tdls_mgmt_comp, + msecs_to_jiffies(WAIT_TIME_FOR_TDLS_MGMT)); + + if ((0 == rc) || (true != tdls_priv->mgmt_tx_completion_status)) { + cfg80211_err("%s rc %ld mgmtTxCompletionStatus %u", + !rc ? "Mgmt Tx Completion timed out" : + "Mgmt Tx Completion failed", + rc, tdls_priv->mgmt_tx_completion_status); + + tdls_priv->mgmt_tx_completion_status = false; + status = -EINVAL; + goto error_mgmt_req; + } + + cfg80211_info("Mgmt Tx Completion status %ld TxCompletion %u", + rc, tdls_priv->mgmt_tx_completion_status); + + if (chk_frame.max_sta_failed) { + status = max_sta_failed; + goto error_mgmt_req; + } + + if (TDLS_SETUP_RESPONSE == action_code || + TDLS_SETUP_CONFIRM == action_code) { + qdf_mem_copy(set_responder.peer_mac, peer_mac, + QDF_MAC_ADDR_SIZE); + set_responder.vdev = vdev; + if (TDLS_SETUP_RESPONSE == action_code) + set_responder.responder = false; + if (TDLS_SETUP_CONFIRM == action_code) + set_responder.responder = true; + ucfg_tdls_responder(&set_responder); + } + +error_mgmt_req: + wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID); + return status; +} + static void wlan_cfg80211_tdls_indicate_discovery(struct tdls_osif_indication *ind) { @@ -504,6 +732,10 @@ void wlan_cfg80211_tdls_event_callback(void *user_data, wlan_vdev_obj_unlock(ind->vdev); switch (type) { + case TDLS_EVENT_MGMT_TX_ACK_CNF: + tdls_priv->mgmt_tx_completion_status = ind->status; + complete(&tdls_priv->tdls_mgmt_comp); + break; case TDLS_EVENT_ADD_PEER: tdls_priv->tdls_add_peer_status = ind->status; complete(&tdls_priv->tdls_add_peer_comp); diff --git a/umac/cmn_services/mgmt_txrx/dispatcher/inc/wlan_mgmt_txrx_utils_api.h b/umac/cmn_services/mgmt_txrx/dispatcher/inc/wlan_mgmt_txrx_utils_api.h index ecde70481c95..fc33a07c6e52 100644 --- a/umac/cmn_services/mgmt_txrx/dispatcher/inc/wlan_mgmt_txrx_utils_api.h +++ b/umac/cmn_services/mgmt_txrx/dispatcher/inc/wlan_mgmt_txrx_utils_api.h @@ -309,17 +309,18 @@ enum wnm_actioncode { * @TDLS_DISCOVERY_REQUEST: tdls discovery request frame */ enum tdls_actioncode { - TDLS_SETUP_REQUEST, - TDLS_SETUP_RESPONSE, - TDLS_SETUP_CONFIRM, - TDLS_TEARDOWN, - TDLS_PEER_TRAFFIC_INDICATION, - TDLS_CHANNEL_SWITCH_REQUEST, - TDLS_CHANNEL_SWITCH_RESPONSE, - TDLS_PEER_PSM_REQUEST, - TDLS_PEER_PSM_RESPONSE, - TDLS_PEER_TRAFFIC_RESPONSE, - TDLS_DISCOVERY_REQUEST, + TDLS_SETUP_REQUEST = 0, + TDLS_SETUP_RESPONSE = 1, + TDLS_SETUP_CONFIRM = 2, + TDLS_TEARDOWN = 3, + TDLS_PEER_TRAFFIC_INDICATION = 4, + TDLS_CHANNEL_SWITCH_REQUEST = 5, + TDLS_CHANNEL_SWITCH_RESPONSE = 6, + TDLS_PEER_PSM_REQUEST = 7, + TDLS_PEER_PSM_RESPONSE = 8, + TDLS_PEER_TRAFFIC_RESPONSE = 9, + TDLS_DISCOVERY_REQUEST = 10, + TDLS_DISCOVERY_RESPONSE = 14, }; /** diff --git a/umac/cmn_services/obj_mgr/inc/wlan_objmgr_peer_obj.h b/umac/cmn_services/obj_mgr/inc/wlan_objmgr_peer_obj.h index 6b9a276b6623..0a609b512623 100644 --- a/umac/cmn_services/obj_mgr/inc/wlan_objmgr_peer_obj.h +++ b/umac/cmn_services/obj_mgr/inc/wlan_objmgr_peer_obj.h @@ -133,6 +133,7 @@ struct wlan_objmgr_peer_mlme { uint32_t max_rate; uint16_t seq_num; enum wlan_peer_state state; + bool is_authenticated; }; /** @@ -732,6 +733,25 @@ static inline void wlan_peer_mlme_set_state( peer->peer_mlme.state = state; } +/** + * wlan_peer_mlme_set_auth_state() - peer mlme auth state + * @peer: PEER object + * @is_authenticated: true or false + * + * API to update the current peer auth state + * + * Caller need to acquire lock with wlan_peer_obj_lock() + * + * Return: void + */ +static inline void wlan_peer_mlme_set_auth_state( + struct wlan_objmgr_peer *peer, + bool is_authenticated) +{ + /* This API is invoked with lock acquired, do not add log prints */ + peer->peer_mlme.is_authenticated = is_authenticated; +} + /** * wlan_peer_mlme_get_state() - peer mlme state * @peer: PEER object @@ -749,6 +769,23 @@ static inline enum wlan_peer_state wlan_peer_mlme_get_state( return peer->peer_mlme.state; } +/** + * wlan_peer_mlme_get_auth_state() - peer mlme auth state + * @peer: PEER object + * + * API to get peer auth state + * + * Caller need to acquire lock with wlan_peer_obj_lock() + * + * Return: auth state true/false + */ +static inline bool wlan_peer_mlme_get_auth_state( + struct wlan_objmgr_peer *peer) +{ + /* This API is invoked with lock acquired, do not add log prints */ + return peer->peer_mlme.is_authenticated; +} + /** * wlan_peer_mlme_get_next_seq_num() - get peer mlme next sequence number * @peer: PEER object diff --git a/umac/tdls/core/src/wlan_tdls_cmds_process.c b/umac/tdls/core/src/wlan_tdls_cmds_process.c index 51361b65c18f..26594e3f37f4 100644 --- a/umac/tdls/core/src/wlan_tdls_cmds_process.c +++ b/umac/tdls/core/src/wlan_tdls_cmds_process.c @@ -569,6 +569,244 @@ tdls_add_peer_serialize_callback(struct wlan_serialization_command *cmd, return status; } +void tdls_reset_nss(struct tdls_soc_priv_obj *tdls_soc, + uint8_t action_code) +{ + if (!tdls_soc) + return; + + if (TDLS_TEARDOWN != action_code || + tdls_soc->tdls_nss_switch_in_progress) + return; + + if (tdls_soc->tdls_teardown_peers_cnt != 0) + tdls_soc->tdls_teardown_peers_cnt--; + if (tdls_soc->tdls_teardown_peers_cnt == 0) { + if (tdls_soc->tdls_nss_transition_mode == + TDLS_NSS_TRANSITION_S_1x1_to_2x2) { + /* TDLS NSS switch is fully completed, so + * reset the flags. + */ + tdls_notice("TDLS NSS switch is fully completed"); + tdls_soc->tdls_nss_switch_in_progress = false; + tdls_soc->tdls_nss_teardown_complete = false; + } else { + /* TDLS NSS switch is not yet completed, but + * tdls teardown is completed for all the + * peers. + */ + tdls_notice("teardown done & NSS switch in progress"); + tdls_soc->tdls_nss_teardown_complete = true; + } + } + +} + +/** + * tdls_set_cap() - set TDLS capability type + * @tdls_vdev: tdls vdev object + * @mac: peer mac address + * @cap: TDLS capability type + * + * Return: 0 if successful or negative errno otherwise + */ +int tdls_set_cap(struct tdls_vdev_priv_obj *tdls_vdev, const uint8_t *mac, + enum tdls_peer_capab cap) +{ + struct tdls_peer *curr_peer; + + curr_peer = tdls_get_peer(tdls_vdev, mac); + if (curr_peer == NULL) { + tdls_err("curr_peer is NULL"); + return -EINVAL; + } + + curr_peer->tdls_support = cap; + return 0; +} + +static int tdls_validate_setup_frames(struct tdls_soc_priv_obj *tdls_soc, + struct tdls_validate_action_req *tdls_validate) +{ + /* supplicant still sends tdls_mgmt(SETUP_REQ) + * even after we return error code at + * 'add_station()'. Hence we have this check + * again in addition to add_station(). Anyway, + * there is no harm to double-check. + */ + if (TDLS_SETUP_REQUEST == tdls_validate->action_code) { + tdls_err(QDF_MAC_ADDRESS_STR " TDLS Max peer already connected. action (%d) declined. Num of peers (%d), Max allowed (%d).", + QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac), + tdls_validate->action_code, + tdls_soc->connected_peer_count, + tdls_soc->max_num_tdls_sta); + return -EINVAL; + } + /* maximum reached. tweak to send + * error code to peer and return error + * code to supplicant + */ + tdls_validate->status_code = QDF_STATUS_E_RESOURCES; + tdls_err(QDF_MAC_ADDRESS_STR " TDLS Max peer already connected, send response status (%d). Num of peers (%d), Max allowed (%d).", + QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac), + tdls_validate->action_code, + tdls_soc->connected_peer_count, + tdls_soc->max_num_tdls_sta); + + tdls_validate->max_sta_failed = -EPERM; + return 0; +} + +int tdls_validate_mgmt_request(struct tdls_validate_action_req *tdls_validate) +{ + struct tdls_vdev_priv_obj *tdls_vdev; + struct tdls_soc_priv_obj *tdls_soc; + struct tdls_peer *curr_peer; + struct tdls_peer *temp_peer; + QDF_STATUS status; + + + if (!tdls_validate || !tdls_validate->vdev) + return -EINVAL; + + if (QDF_STATUS_SUCCESS != tdls_get_vdev_objects(tdls_validate->vdev, + &tdls_vdev, + &tdls_soc)) + return -ENOTSUPP; + + /* + * STA or P2P client should be connected and authenticated before + * sending any TDLS frames + */ + if (!tdls_is_vdev_connected(tdls_validate->vdev) || + !tdls_is_vdev_authenticated(tdls_validate->vdev)) { + tdls_err("STA is not connected or not authenticated."); + return -EAGAIN; + } + + /* other than teardown frame, mgmt frames are not sent if disabled */ + if (TDLS_TEARDOWN != tdls_validate->action_code) { + if (!tdls_check_is_tdls_allowed(tdls_validate->vdev)) { + tdls_err("TDLS not allowed, reject MGMT, action = %d", + tdls_validate->action_code); + return -EPERM; + } + /* if tdls_mode is disabled, then decline the peer's request */ + if (TDLS_SUPPORT_DISABLED == tdls_soc->tdls_current_mode || + TDLS_SUPPORT_SUSPENDED == tdls_soc->tdls_current_mode) { + tdls_notice(QDF_MAC_ADDRESS_STR + " TDLS mode is disabled. action %d declined.", + QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac), + tdls_validate->action_code); + return -ENOTSUPP; + } + if (tdls_soc->tdls_nss_switch_in_progress) { + tdls_err("nss switch in progress, action %d declined " + QDF_MAC_ADDRESS_STR, + tdls_validate->action_code, + QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac)); + return -EAGAIN; + } + } + + if (TDLS_IS_SETUP_ACTION(tdls_validate->action_code)) { + if (NULL != tdls_is_progress(tdls_vdev, + tdls_validate->peer_mac, true)) { + tdls_err("setup is ongoing. action %d declined for " + QDF_MAC_ADDRESS_STR, + tdls_validate->action_code, + QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac)); + return -EPERM; + } + } + + /* + * Discard TDLS Discovery request and setup confirm if violates + * ACM rules + */ + if ((TDLS_DISCOVERY_REQUEST == tdls_validate->action_code || + TDLS_SETUP_CONFIRM == tdls_validate->action_code)) { + /* call hdd_wmm_is_acm_allowed() */ + if (!tdls_soc->tdls_wmm_cb(&tdls_vdev->vdev)) { + tdls_err("admission ctrl set to VI, action %d declined", + tdls_validate->action_code); + return -EPERM; + } + } + + + if (TDLS_SETUP_REQUEST == tdls_validate->action_code || + TDLS_SETUP_RESPONSE == tdls_validate->action_code) { + if (tdls_soc->max_num_tdls_sta <= + tdls_soc->connected_peer_count) { + status = tdls_validate_setup_frames(tdls_soc, + tdls_validate); + if (QDF_STATUS_SUCCESS != status) + return status; + /* fall through to send setup resp + * with failure status code + */ + } else { + curr_peer = + tdls_find_peer(tdls_vdev, + tdls_validate->peer_mac); + if (curr_peer) { + if (TDLS_IS_LINK_CONNECTED(curr_peer)) { + tdls_err(QDF_MAC_ADDRESS_STR " already connected action %d declined.", + QDF_MAC_ADDR_ARRAY( + tdls_validate->peer_mac), + tdls_validate->action_code); + + return -EPERM; + } + } + } + } + + tdls_notice("tdls_mgmt" QDF_MAC_ADDRESS_STR " action %d, dialog_token %d status %d, len = %zu", + QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac), + tdls_validate->action_code, tdls_validate->dialog_token, + tdls_validate->status_code, tdls_validate->len); + + /*Except teardown responder will not be used so just make 0 */ + tdls_validate->responder = 0; + if (TDLS_TEARDOWN == tdls_validate->action_code) { + temp_peer = tdls_find_peer(tdls_vdev, tdls_validate->peer_mac); + if (!temp_peer) { + tdls_err(QDF_MAC_ADDRESS_STR " peer doesn't exist", + QDF_MAC_ADDR_ARRAY( + tdls_validate->peer_mac)); + return -EPERM; + } + + if (TDLS_IS_LINK_CONNECTED(temp_peer)) + tdls_validate->responder = temp_peer->is_responder; + else { + tdls_err(QDF_MAC_ADDRESS_STR " peer doesn't exist or not connected %d dialog_token %d status %d, tdls_validate->len = %zu", + QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac), + temp_peer->link_status, + tdls_validate->dialog_token, + tdls_validate->status_code, + tdls_validate->len); + return -EPERM; + } + } + + /* For explicit trigger of DIS_REQ come out of BMPS for + * successfully receiving DIS_RSP from peer. + */ + if ((TDLS_SETUP_RESPONSE == tdls_validate->action_code) || + (TDLS_SETUP_CONFIRM == tdls_validate->action_code) || + (TDLS_DISCOVERY_RESPONSE == tdls_validate->action_code) || + (TDLS_DISCOVERY_REQUEST == tdls_validate->action_code)) { + /* Fw will take care if PS offload is enabled. */ + if (TDLS_DISCOVERY_REQUEST != tdls_validate->action_code) + tdls_set_cap(tdls_vdev, tdls_validate->peer_mac, + TDLS_CAP_SUPPORTED); + } + return 0; +} + QDF_STATUS tdls_process_add_peer(struct tdls_add_peer_request *req) { struct wlan_serialization_command cmd = {0,}; @@ -1000,6 +1238,105 @@ error: return status; } +/** + * tdls_process_send_mgmt_rsp() - handle response for send mgmt + * @rsp: TDLS send mgmt response + * + * Return: QDF_STATUS_SUCCESS for success; other values if failed + */ +QDF_STATUS tdls_process_send_mgmt_rsp(struct tdls_send_mgmt_rsp *rsp) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_psoc *psoc; + struct tdls_vdev_priv_obj *tdls_vdev; + struct tdls_soc_priv_obj *tdls_soc = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct tdls_osif_indication ind; + + psoc = rsp->psoc; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, rsp->session_id, + WLAN_TDLS_SB_ID); + if (!vdev) { + tdls_err("invalid vdev"); + status = QDF_STATUS_E_INVAL; + qdf_mem_free(rsp); + return status; + } + tdls_soc = wlan_psoc_get_tdls_soc_obj(psoc); + tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev); + if (!tdls_soc || !tdls_vdev) { + tdls_err("soc object:%p, vdev object:%p", tdls_soc, tdls_vdev); + status = QDF_STATUS_E_FAILURE; + } + + tdls_release_serialization_command(vdev, WLAN_SER_CMD_TDLS_SEND_MGMT); + + if (legacy_result_success == rsp->status_code) + goto free_rsp; + tdls_err("send mgmt failed. status code(=%d)", rsp->status_code); + status = QDF_STATUS_E_FAILURE; + + if (tdls_soc && tdls_soc->tdls_event_cb) { + ind.vdev = vdev; + ind.status = rsp->status_code; + tdls_soc->tdls_event_cb(tdls_soc->tdls_evt_cb_data, + TDLS_EVENT_MGMT_TX_ACK_CNF, &ind); + } + +free_rsp: + qdf_mem_free(rsp); + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID); + return status; +} + +/** + * tdls_send_mgmt_tx_completion() - process tx completion + * @tx_complete: TDLS mgmt completion info + * + * Return: QDF_STATUS_SUCCESS for success; other values if failed + */ +QDF_STATUS tdls_send_mgmt_tx_completion( + struct tdls_mgmt_tx_completion_ind *tx_complete) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_psoc *psoc; + struct tdls_vdev_priv_obj *tdls_vdev; + struct tdls_soc_priv_obj *tdls_soc = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct tdls_osif_indication ind; + + psoc = tx_complete->psoc; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + tx_complete->session_id, + WLAN_TDLS_SB_ID); + + if (!vdev) { + tdls_err("invalid vdev"); + status = QDF_STATUS_E_INVAL; + goto free_tx_complete; + } + + tdls_soc = wlan_psoc_get_tdls_soc_obj(psoc); + tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev); + + if (!tdls_soc || !tdls_vdev) { + tdls_err("soc object:%p, vdev object:%p", tdls_soc, tdls_vdev); + status = QDF_STATUS_E_FAILURE; + } + + if (tdls_soc && tdls_soc->tdls_event_cb) { + ind.vdev = vdev; + ind.status = tx_complete->tx_complete_status; + tdls_soc->tdls_event_cb(tdls_soc->tdls_evt_cb_data, + TDLS_EVENT_MGMT_TX_ACK_CNF, &ind); + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID); +free_tx_complete: + qdf_mem_free(tx_complete); + return status; +} + /** * tdls_add_peer_rsp() - handle response for add TDLS peer * @rsp: TDLS add peer response @@ -1139,10 +1476,12 @@ QDF_STATUS tdls_process_del_peer_rsp(struct tdls_del_sta_rsp *rsp) tdls_debug(QDF_MAC_ADDRESS_STR " status is %d", QDF_MAC_ADDR_ARRAY(macaddr), curr_peer->link_status); + wlan_vdev_obj_lock(vdev); id = wlan_vdev_get_id(vdev); wlan_vdev_obj_unlock(vdev); - if (TDLS_IS_CONNECTED(curr_peer)) { + + if (TDLS_IS_LINK_CONNECTED(curr_peer)) { soc_obj->tdls_dereg_tl_peer( soc_obj->tdls_tl_peer_data, id, curr_peer->sta_id); @@ -1464,6 +1803,10 @@ static QDF_STATUS tdls_config_force_peer( tdls_set_callback(peer, req->callback); + tdls_set_ct_mode(soc_obj->soc); + if (soc_obj->enable_tdls_connection_tracker) + tdls_implicit_enable(vdev_obj); + return status; error: qdf_mem_free(peer_update_param); @@ -1605,8 +1948,10 @@ QDF_STATUS tdls_process_remove_force_peer(struct tdls_oper_request *req) qdf_mem_free(peer_update_param); goto error; } + tdls_set_ct_mode(soc_obj->soc); + if (!soc_obj->enable_tdls_connection_tracker) + tdls_implicit_disable(vdev_obj); - /*TODO set tdls connection tracker state*/ error: wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); qdf_mem_free(req); diff --git a/umac/tdls/core/src/wlan_tdls_cmds_process.h b/umac/tdls/core/src/wlan_tdls_cmds_process.h index 8c17dfebd454..ec2f40e1070d 100644 --- a/umac/tdls/core/src/wlan_tdls_cmds_process.h +++ b/umac/tdls/core/src/wlan_tdls_cmds_process.h @@ -25,6 +25,11 @@ #ifndef _WLAN_TDLS_CMDS_PROCESS_H_ #define _WLAN_TDLS_CMDS_PROCESS_H_ +#define TDLS_IS_SETUP_ACTION(action) \ + ((TDLS_SETUP_REQUEST <= action) && \ + (TDLS_SETUP_CONFIRM >= action)) + + /** * enum tdls_add_oper - add peer type * @TDLS_OPER_NONE: none @@ -37,6 +42,53 @@ enum tdls_add_oper { TDLS_OPER_UPDATE }; +/** + * enum legacy_result_code - defined to comply with tSirResultCodes, need refine + * when mlme converged. + * @legacy_result_success: success + * @legacy_result_max: max result value + */ +enum legacy_result_code { + legacy_result_success, + legacy_result_max = 0x7FFFFFFF +}; + +/** + * struct tdls_send_mgmt_rsp - TDLS Response struct PE --> TDLS module + * same as struct tSirSmeRsp + * @message_type: message type eWNI_SME_TDLS_SEND_MGMT_RSP + * @length: message length + * @session_id: session id + * @transaction_id: transaction id + * @status_code: status code as tSirResultCodes + * @psoc: soc object + */ +struct tdls_send_mgmt_rsp { + uint16_t message_type; + uint16_t length; + uint8_t session_id; + uint16_t transaction_id; + enum legacy_result_code status_code; + struct wlan_objmgr_psoc *psoc; +}; + +/** + * struct tdls_mgmt_tx_completion_ind - TDLS TX completion PE --> TDLS module + * same as struct sSirMgmtTxCompletionInd + * @message_type: message type eWNI_SME_MGMT_FRM_TX_COMPLETION_IND + * @length: message length + * @session_id: session id + * @tx_complete_status: tx complete status + * @psoc: soc object + */ +struct tdls_mgmt_tx_completion_ind { + uint16_t message_type; + uint16_t length; + uint8_t session_id; /* Session ID */ + uint32_t tx_complete_status; + struct wlan_objmgr_psoc *psoc; +}; + /** * struct tdls_add_sta_req - TDLS request struct TDLS module --> PE * same as struct tSirTdlsAddStaReq; @@ -213,6 +265,52 @@ QDF_STATUS tdls_pe_del_peer(struct tdls_del_peer_request *req); */ QDF_STATUS tdls_process_add_peer_rsp(struct tdls_add_sta_rsp *rsp); +/** + * tdls_reset_nss() - reset tdls nss parameters + * @tdls_soc: TDLS soc object + * @action_code: action code + * + * Return: None + */ +void tdls_reset_nss(struct tdls_soc_priv_obj *tdls_soc, + uint8_t action_code); + +/** + * tdls_set_cap() - set TDLS capability type + * @tdls_vdev: tdls vdev object + * @mac: peer mac address + * @cap: TDLS capability type + * + * Return: 0 if successful or negative errno otherwise + */ +int tdls_set_cap(struct tdls_vdev_priv_obj *tdls_vdev, const uint8_t *mac, + enum tdls_peer_capab cap); + +/** + * tdls_validate_mgmt_request() -validate mgmt request + * @tdls_validate: action frame request + * + * Return: 0 for success or -EINVAL otherwise + */ +int tdls_validate_mgmt_request(struct tdls_validate_action_req *tdls_validate); + +/** + * tdls_process_send_mgmt_rsp() - handle response for send mgmt + * @rsp: TDLS send mgmt response + * + * Return: QDF_STATUS_SUCCESS for success; other values if failed + */ +QDF_STATUS tdls_process_send_mgmt_rsp(struct tdls_send_mgmt_rsp *rsp); + +/** + * tdls_send_mgmt_tx_completion() - process tx completion + * @tx_complete: TDLS mgmt completion info + * + * Return: QDF_STATUS_SUCCESS for success; other values if failed + */ +QDF_STATUS tdls_send_mgmt_tx_completion( + struct tdls_mgmt_tx_completion_ind *tx_complete); + /** * tdls_process_add_peer_rsp() - handle response for delete TDLS peer * @rsp: TDLS delete peer response diff --git a/umac/tdls/core/src/wlan_tdls_ct.c b/umac/tdls/core/src/wlan_tdls_ct.c index 52ccfcfd2046..cb48dd205771 100644 --- a/umac/tdls/core/src/wlan_tdls_ct.c +++ b/umac/tdls/core/src/wlan_tdls_ct.c @@ -52,6 +52,27 @@ bool tdls_is_vdev_connected(struct wlan_objmgr_vdev *vdev) return true; } +bool tdls_is_vdev_authenticated(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_peer *peer; + bool is_authenticated = false; + + wlan_vdev_obj_lock(vdev); + peer = wlan_vdev_get_bsspeer(vdev); + wlan_vdev_obj_unlock(vdev); + + if (!peer) { + tdls_err("peer is null"); + return false; + } + + wlan_peer_obj_lock(peer); + is_authenticated = wlan_peer_mlme_get_auth_state(peer); + wlan_peer_obj_unlock(peer); + + return is_authenticated; +} + /** * tdls_peer_reset_discovery_processed() - reset discovery status * @tdls_vdev: TDLS vdev object diff --git a/umac/tdls/core/src/wlan_tdls_ct.h b/umac/tdls/core/src/wlan_tdls_ct.h index d894794eb568..e497daed2bac 100644 --- a/umac/tdls/core/src/wlan_tdls_ct.h +++ b/umac/tdls/core/src/wlan_tdls_ct.h @@ -155,4 +155,21 @@ void tdls_discovery_timeout_peer_cb(void *user_data); * Return: Void */ void tdls_implicit_disable(struct tdls_vdev_priv_obj *tdls_vdev); + +/** + * tdls_is_vdev_connected() -check the vdev connection + * @vdev: vdev oobject + * + * Return: true or false + */ +bool tdls_is_vdev_connected(struct wlan_objmgr_vdev *vdev); + +/** + * tdls_is_vdev_authenticated() -check the vdev authentication state + * @vdev: vdev oobject + * + * Return: true or false + */ +bool tdls_is_vdev_authenticated(struct wlan_objmgr_vdev *vdev); + #endif diff --git a/umac/tdls/core/src/wlan_tdls_main.c b/umac/tdls/core/src/wlan_tdls_main.c index 5fef8c76e727..c58d8682b38b 100644 --- a/umac/tdls/core/src/wlan_tdls_main.c +++ b/umac/tdls/core/src/wlan_tdls_main.c @@ -30,6 +30,8 @@ #include "wlan_tdls_tgt_api.h" #include "wlan_policy_mgr_public_struct.h" #include "wlan_policy_mgr_api.h" +#include "wlan_scan_ucfg_api.h" + /* Global tdls soc pvt object * this is useful for some functions which does not receive either vdev or psoc diff --git a/umac/tdls/core/src/wlan_tdls_main.h b/umac/tdls/core/src/wlan_tdls_main.h index 30ace4511980..bfbddf0dede2 100644 --- a/umac/tdls/core/src/wlan_tdls_main.h +++ b/umac/tdls/core/src/wlan_tdls_main.h @@ -34,6 +34,7 @@ #include #include #include "wlan_serialization_api.h" +#include "wlan_tdls_mgmt.h" /* Bit mask flag for tdls_option to FW */ #define ENA_TDLS_OFFCHAN (1 << 0) /* TDLS Off Channel support */ @@ -74,7 +75,7 @@ #define tdls_alert(format, args...) \ tdls_logfl(QDF_TRACE_LEVEL_FATAL, format, ## args) -#define TDLS_IS_CONNECTED(peer) \ +#define TDLS_IS_LINK_CONNECTED(peer) \ ((TDLS_LINK_CONNECTED == (peer)->link_status) || \ (TDLS_LINK_TEARING == (peer)->link_status)) @@ -203,6 +204,10 @@ struct tdls_soc_priv_obj { enum tdls_nss_transition_state tdls_nss_transition_mode; int32_t tdls_teardown_peers_cnt; struct tdls_set_state_info set_state_info; + tdls_rx_callback tdls_rx_cb; + void *tdls_rx_cb_data; + tdls_wmm_check tdls_wmm_cb; + void *tdls_wmm_cb_data; tdls_tx_ack_cnf_callback tdls_tx_cnf_cb; void *tx_ack_cnf_cb_data; tdls_evt_callback tdls_event_cb; diff --git a/umac/tdls/core/src/wlan_tdls_mgmt.c b/umac/tdls/core/src/wlan_tdls_mgmt.c index 3f28bf08174f..f6e27dfd757e 100644 --- a/umac/tdls/core/src/wlan_tdls_mgmt.c +++ b/umac/tdls/core/src/wlan_tdls_mgmt.c @@ -113,7 +113,6 @@ static QDF_STATUS tdls_process_rx_mgmt( tdls_set_rssi(tdls_vdev, mac, rx_mgmt->rx_rssi); } - if (rx_mgmt->buf[TDLS_PUBLIC_ACTION_FRAME_OFFSET] == TDLS_ACTION_FRAME) { action_frame_type = @@ -127,7 +126,7 @@ static QDF_STATUS tdls_process_rx_mgmt( } } - /* tdls_soc_obj->tdls_rx_cb ==> wlan_tdls_rx_callback() */ + /* tdls_soc_obj->tdls_rx_cb ==> wlan_cfg80211_tdls_rx_callback() */ if (tdls_soc_obj && tdls_soc_obj->tdls_rx_cb) tdls_soc_obj->tdls_rx_cb(tdls_soc_obj->tdls_rx_cb_data, rx_mgmt); @@ -157,7 +156,6 @@ QDF_STATUS tdls_process_rx_frame(struct scheduler_msg *msg) if (vdev) { tdls_debug("tdls rx mgmt frame received"); - tdls_vdev = wlan_objmgr_vdev_get_comp_private_obj(vdev, WLAN_UMAC_COMP_TDLS); if (tdls_vdev) @@ -175,6 +173,7 @@ QDF_STATUS tdls_mgmt_rx_ops(struct wlan_objmgr_psoc *psoc, bool isregister) { struct mgmt_txrx_mgmt_frame_cb_info frm_cb_info[3]; + QDF_STATUS status; int num_of_entries; diff --git a/umac/tdls/core/src/wlan_tdls_mgmt.h b/umac/tdls/core/src/wlan_tdls_mgmt.h index 94e6d11f9749..3d3e6dd54a50 100644 --- a/umac/tdls/core/src/wlan_tdls_mgmt.h +++ b/umac/tdls/core/src/wlan_tdls_mgmt.h @@ -28,6 +28,24 @@ /* default tdls serialize timeout is set to 10 secs */ #define TDLS_DEFAULT_SERIALIZE_CMD_TIMEOUT 10000 +#define TDLS_PUBLIC_ACTION_FRAME_OFFSET 24 +#define TDLS_PUBLIC_ACTION_FRAME 4 +#define TDLS_PUBLIC_ACTION_DISC_RESP 14 +#define TDLS_ACTION_FRAME 12 +#define TDLS_80211_PEER_ADDR_OFFSET (TDLS_PUBLIC_ACTION_FRAME + \ + QDF_MAC_ADDR_SIZE) +#define TDLS_ACTION_FRAME_TYPE_MAX 11 + +/** + * struct tdls_rx_mgmt_event - tdls rx mgmt frame event + * @tdls_soc_obj: tdls soc private object + * @rx_mgmt: tdls rx mgmt frame structure + */ +struct tdls_rx_mgmt_event { + struct tdls_soc_priv_obj *tdls_soc_obj; + struct tdls_rx_mgmt_frame *rx_mgmt; +}; + /* * struct tdls_send_mgmt_request - tdls management request * @message_type: type of pe message @@ -70,5 +88,26 @@ struct tdls_send_mgmt_request { */ QDF_STATUS tdls_process_mgmt_req( struct tdls_action_frame_request *tdls_mgmt_req); + +/** + * tdls_mgmt_rx_ops() - register or unregister rx callback + * @psoc: psoc object + * @isregister: register if true, unregister if false + * + * This function registers or unregisters rx callback to mgmt txrx + * component. + * + * Return: QDF_STATUS + */ +QDF_STATUS tdls_mgmt_rx_ops(struct wlan_objmgr_psoc *psoc, + bool isregister); + +/** + * tdls_process_rx_frame() - process tdls rx frames + * @msg: scheduler msg + * + * Return: QDF_STATUS + */ +QDF_STATUS tdls_process_rx_frame(struct scheduler_msg *msg); #endif diff --git a/umac/tdls/dispatcher/inc/wlan_tdls_public_structs.h b/umac/tdls/dispatcher/inc/wlan_tdls_public_structs.h index 4d4b7be4168f..36e3a4676c90 100644 --- a/umac/tdls/dispatcher/inc/wlan_tdls_public_structs.h +++ b/umac/tdls/dispatcher/inc/wlan_tdls_public_structs.h @@ -29,6 +29,8 @@ #include #include #include +#include + #define WLAN_TDLS_STA_MAX_NUM 8 #define WLAN_TDLS_STA_P_UAPSD_OFFCHAN_MAX_NUM 1 @@ -59,7 +61,7 @@ #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 WAIT_TIME_FOR_TDLS_MGMT 11000 #define TDLS_TEARDOWN_PEER_UNREACHABLE 25 #define TDLS_TEARDOWN_PEER_UNSPEC_REASON 26 @@ -252,7 +254,7 @@ enum tdls_event_msg_type { TDLS_SHOULD_DISCOVER = 0, TDLS_SHOULD_TEARDOWN, TDLS_PEER_DISCONNECTED, - TDLS_CONNECTION_TRACKER_NOTIFY, + TDLS_CONNECTION_TRACKER_NOTIFY }; /** diff --git a/umac/tdls/dispatcher/inc/wlan_tdls_tgt_api.h b/umac/tdls/dispatcher/inc/wlan_tdls_tgt_api.h index dbc8c0683f50..4357241a4eee 100644 --- a/umac/tdls/dispatcher/inc/wlan_tdls_tgt_api.h +++ b/umac/tdls/dispatcher/inc/wlan_tdls_tgt_api.h @@ -67,6 +67,22 @@ QDF_STATUS tgt_tdls_set_offchan_mode(struct wlan_objmgr_psoc *psoc, QDF_STATUS tgt_tdls_set_uapsd(struct wlan_objmgr_psoc *psoc, struct sta_uapsd_trig_params *params); +/** + * tgt_tdls_send_mgmt_rsp() - process tdls mgmt response + * @pmsg: sheduler msg + * + * Return: QDF_STATUS + */ +QDF_STATUS tgt_tdls_send_mgmt_rsp(struct scheduler_msg *pmsg); + +/** + * tgt_tdls_send_mgmt_tx_completion() -process tx completion message + * @pmsg: sheduler msg + * + * Return: QDF_STATUS + */ +QDF_STATUS tgt_tdls_send_mgmt_tx_completion(struct scheduler_msg *pmsg); + /** * tgt_tdls_del_peer_rsp() - handle TDLS del peer response * @pmsg: sheduler msg @@ -111,4 +127,23 @@ QDF_STATUS tgt_tdls_unregister_ev_handler(struct wlan_objmgr_psoc *psoc); QDF_STATUS tgt_tdls_event_handler(struct wlan_objmgr_psoc *psoc, struct tdls_event_info *info); + +/** + * tgt_tdls_mgmt_frame_rx_cb() - callback for rx mgmt frame + * @psoc: soc context + * @peer: peer context + * @buf: rx buffer + * @mgmt_rx_params: mgmt rx parameters + * @frm_type: frame type + * + * This function gets called from mgmt tx/rx component when rx mgmt + * received. + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS tgt_tdls_mgmt_frame_rx_cb(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_peer *peer, qdf_nbuf_t buf, + struct mgmt_rx_event_params *mgmt_rx_params, + enum mgmt_frame_type frm_type); + #endif diff --git a/umac/tdls/dispatcher/src/wlan_tdls_tgt_api.c b/umac/tdls/dispatcher/src/wlan_tdls_tgt_api.c index 78a198b2a71f..a55f6d134151 100644 --- a/umac/tdls/dispatcher/src/wlan_tdls_tgt_api.c +++ b/umac/tdls/dispatcher/src/wlan_tdls_tgt_api.c @@ -87,6 +87,36 @@ QDF_STATUS tgt_tdls_set_uapsd(struct wlan_objmgr_psoc *psoc, return QDF_STATUS_SUCCESS; } +QDF_STATUS tgt_tdls_send_mgmt_tx_completion(struct scheduler_msg *pmsg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!pmsg || !pmsg->bodyptr) { + tdls_err("msg: 0x%p", pmsg); + QDF_ASSERT(0); + return QDF_STATUS_E_NULL_VALUE; + } + + status = tdls_send_mgmt_tx_completion(pmsg->bodyptr); + + return status; +} + +QDF_STATUS tgt_tdls_send_mgmt_rsp(struct scheduler_msg *pmsg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!pmsg || !pmsg->bodyptr) { + tdls_err("msg: 0x%p", pmsg); + QDF_ASSERT(0); + return QDF_STATUS_E_NULL_VALUE; + } + + status = tdls_process_send_mgmt_rsp(pmsg->bodyptr); + + return status; +} + QDF_STATUS tgt_tdls_add_peer_rsp(struct scheduler_msg *pmsg) { QDF_STATUS status = QDF_STATUS_SUCCESS; @@ -183,3 +213,124 @@ tgt_tdls_event_handler(struct wlan_objmgr_psoc *psoc, return status; } + +static +QDF_STATUS tgt_tdls_mgmt_frame_process_rx_cb( + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_peer *peer, + qdf_nbuf_t buf, + struct mgmt_rx_event_params *mgmt_rx_params, + enum mgmt_frame_type frm_type) +{ + struct tdls_rx_mgmt_frame *rx_mgmt; + struct tdls_rx_mgmt_event *rx_mgmt_event; + struct tdls_soc_priv_obj *tdls_soc_obj; + struct scheduler_msg msg; + struct wlan_objmgr_vdev *vdev; + uint32_t vdev_id; + uint8_t *pdata; + QDF_STATUS status; + + tdls_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_TDLS); + if (!tdls_soc_obj) { + tdls_err("tdls ctx is NULL, drop this frame"); + return QDF_STATUS_E_FAILURE; + } + + if (!peer) { + vdev = tdls_get_vdev(psoc, WLAN_TDLS_SB_ID); + if (!vdev) { + tdls_err("current tdls vdev is null, can't get vdev id"); + return QDF_STATUS_E_FAILURE; + } + wlan_vdev_obj_lock(vdev); + vdev_id = wlan_vdev_get_id(vdev); + wlan_vdev_obj_unlock(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID); + } else { + wlan_peer_obj_lock(peer); + vdev = wlan_peer_get_vdev(peer); + wlan_peer_obj_unlock(peer); + if (!vdev) { + tdls_err("vdev is NULL in peer, drop this frame"); + return QDF_STATUS_E_FAILURE; + } + wlan_vdev_obj_lock(vdev); + vdev_id = wlan_vdev_get_id(vdev); + wlan_vdev_obj_unlock(vdev); + } + + rx_mgmt_event = qdf_mem_malloc(sizeof(*rx_mgmt_event)); + if (!rx_mgmt_event) { + tdls_err("Failed to allocate rx mgmt event"); + return QDF_STATUS_E_NOMEM; + } + + rx_mgmt = qdf_mem_malloc(sizeof(*rx_mgmt) + + mgmt_rx_params->buf_len); + if (!rx_mgmt) { + tdls_err("Failed to allocate rx mgmt frame"); + qdf_mem_free(rx_mgmt_event); + return QDF_STATUS_E_NOMEM; + } + + pdata = (uint8_t *)qdf_nbuf_data(buf); + rx_mgmt->frame_len = mgmt_rx_params->buf_len; + rx_mgmt->rx_chan = mgmt_rx_params->channel; + rx_mgmt->vdev_id = vdev_id; + rx_mgmt->frm_type = frm_type; + rx_mgmt->rx_rssi = mgmt_rx_params->rssi; + + rx_mgmt_event->rx_mgmt = rx_mgmt; + rx_mgmt_event->tdls_soc_obj = tdls_soc_obj; + qdf_mem_copy(rx_mgmt->buf, pdata, mgmt_rx_params->buf_len); + msg.type = TDLS_EVENT_RX_MGMT; + msg.bodyptr = rx_mgmt_event; + msg.callback = tdls_process_rx_frame; + status = scheduler_post_msg(QDF_MODULE_ID_TARGET_IF, &msg); + + qdf_nbuf_free(buf); + + return status; +} + +QDF_STATUS tgt_tdls_mgmt_frame_rx_cb( + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_peer *peer, + qdf_nbuf_t buf, + struct mgmt_rx_event_params *mgmt_rx_params, + enum mgmt_frame_type frm_type) +{ + QDF_STATUS status; + + tdls_debug("psoc:%p, peer:%p, type:%d", psoc, peer, frm_type); + + + if (!buf) { + tdls_err("rx frame buff is null buf:%p", buf); + return QDF_STATUS_E_INVAL; + } + + if (!mgmt_rx_params || !psoc) { + tdls_err("input is NULL mgmt_rx_params:%p psoc:%p, peer:%p", + mgmt_rx_params, psoc, peer); + status = QDF_STATUS_E_INVAL; + goto release_nbuf; + } + + status = wlan_objmgr_peer_try_get_ref(peer, WLAN_TDLS_SB_ID); + if (QDF_STATUS_SUCCESS != status) + goto release_nbuf; + + status = tgt_tdls_mgmt_frame_process_rx_cb(psoc, peer, buf, + mgmt_rx_params, frm_type); + + wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_SB_ID); + + if (QDF_STATUS_SUCCESS != status) +release_nbuf: + qdf_nbuf_free(buf); + return status; +} + diff --git a/umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c b/umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c index 1e4afdbfaa06..ecef61fdaeed 100644 --- a/umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c +++ b/umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c @@ -194,6 +194,12 @@ QDF_STATUS ucfg_tdls_update_config(struct wlan_objmgr_psoc *psoc, return QDF_STATUS_E_FAILURE; } + soc_obj->tdls_rx_cb = req->tdls_rx_cb; + soc_obj->tdls_rx_cb_data = req->tdls_rx_cb_data; + + soc_obj->tdls_wmm_cb = req->tdls_wmm_cb; + soc_obj->tdls_wmm_cb_data = req->tdls_wmm_cb_data; + soc_obj->tdls_event_cb = req->tdls_event_cb; soc_obj->tdls_evt_cb_data = req->tdls_evt_cb_data; @@ -256,9 +262,14 @@ QDF_STATUS ucfg_tdls_psoc_enable(struct wlan_objmgr_psoc *psoc) tdls_scan_serialization_comp_info_cb); if (QDF_STATUS_SUCCESS != status) { tdls_err("Serialize scan cmd register failed "); - status = QDF_STATUS_E_FAILURE; + return status; } + /* register callbacks with tx/rx mgmt */ + status = tdls_mgmt_rx_ops(psoc, true); + if (status != QDF_STATUS_SUCCESS) + tdls_err("Failed to register mgmt rx callback, status:%d", + status); return status; } @@ -647,4 +658,6 @@ void ucfg_tdls_update_tx_pkt_cnt(struct wlan_objmgr_vdev *vdev, tdls_update_tx_pkt_cnt(vdev, mac_addr); wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); + } +