diff --git a/os_if/linux/tdls/inc/wlan_cfg80211_tdls.h b/os_if/linux/tdls/inc/wlan_cfg80211_tdls.h index 404495cc8141..7c313cf3d494 100644 --- a/os_if/linux/tdls/inc/wlan_cfg80211_tdls.h +++ b/os_if/linux/tdls/inc/wlan_cfg80211_tdls.h @@ -44,8 +44,11 @@ * @tdls_mgmt_comp: Completion to send tdls mgmt packets * @tdls_link_establish_req_comp: Completion to establish link, sync to * send establish params to firmware, not used today. + * @tdls_teardown_comp: tdls teardown completion event + * @tdls_user_cmd_comp: tdls user command completion event * @tdls_add_peer_status: Peer status after add peer * @mgmt_tx_completion_status: Tdls mgmt frames TX completion status code + * @tdls_user_cmd_len: tdls user command written buffer length */ struct osif_tdls_vdev { struct completion tdls_add_peer_comp; @@ -53,8 +56,10 @@ struct osif_tdls_vdev { struct completion tdls_mgmt_comp; struct completion tdls_link_establish_req_comp; struct completion tdls_teardown_comp; + struct completion tdls_user_cmd_comp; QDF_STATUS tdls_add_peer_status; uint32_t mgmt_tx_completion_status; + uint32_t tdls_user_cmd_len; }; /** @@ -146,6 +151,17 @@ int wlan_cfg80211_tdls_oper(struct wlan_objmgr_pdev *pdev, const uint8_t *peer, enum nl80211_tdls_operation oper); +/** + * wlan_cfg80211_tdls_get_all_peers() - get all the TDLS peers from the list + * @vdev: vdev object + * @buf: output buffer + * @buflen: valid length of the output error + * + * Return: length of the output buffer + */ +int wlan_cfg80211_tdls_get_all_peers(struct wlan_objmgr_vdev *vdev, + char *buf, int buflen); + /** * wlan_cfg80211_tdls_mgmt() - process tdls management frames from the supplicant * @pdev: pdev object diff --git a/os_if/linux/tdls/src/wlan_cfg80211_tdls.c b/os_if/linux/tdls/src/wlan_cfg80211_tdls.c index 837c062abfa2..03614e6874d1 100644 --- a/os_if/linux/tdls/src/wlan_cfg80211_tdls.c +++ b/os_if/linux/tdls/src/wlan_cfg80211_tdls.c @@ -67,6 +67,7 @@ QDF_STATUS wlan_cfg80211_tdls_priv_init(struct vdev_osif_priv *osif_priv) init_completion(&tdls_priv->tdls_mgmt_comp); init_completion(&tdls_priv->tdls_link_establish_req_comp); init_completion(&tdls_priv->tdls_teardown_comp); + init_completion(&tdls_priv->tdls_user_cmd_comp); osif_priv->osif_tdls = tdls_priv; @@ -636,6 +637,56 @@ fail: wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); } +int wlan_cfg80211_tdls_get_all_peers(struct wlan_objmgr_vdev *vdev, + char *buf, int buflen) +{ + struct vdev_osif_priv *osif_priv; + struct osif_tdls_vdev *tdls_priv; + int32_t len; + QDF_STATUS status; + unsigned long rc; + + if (wlan_objmgr_vdev_try_get_ref(vdev, WLAN_OSIF_ID) != + QDF_STATUS_SUCCESS) { + len = scnprintf(buf, buflen, + "\nNo TDLS VDEV is null\n"); + return len; + } + + osif_priv = wlan_vdev_get_ospriv(vdev); + tdls_priv = osif_priv->osif_tdls; + + reinit_completion(&tdls_priv->tdls_user_cmd_comp); + status = ucfg_tdls_get_all_peers(vdev, buf, buflen); + if (QDF_IS_STATUS_ERROR(status)) { + cfg80211_err("ucfg_tdls_get_all_peers failed err %d", status); + len = scnprintf(buf, buflen, + "\nucfg_tdls_send_mgmt failed\n"); + goto error_get_tdls_peers; + } + + cfg80211_info("Wait for tdls_user_cmd_comp. Timeout %u ms", + WAIT_TIME_FOR_TDLS_USER_CMD); + + rc = wait_for_completion_timeout( + &tdls_priv->tdls_user_cmd_comp, + msecs_to_jiffies(WAIT_TIME_FOR_TDLS_USER_CMD)); + + if (0 == rc) { + cfg80211_err("TDLS user cmd get all peers timed out rc %ld", + rc); + len = scnprintf(buf, buflen, + "\nTDLS user cmd get all peers timed out\n"); + goto error_get_tdls_peers; + } + + len = tdls_priv->tdls_user_cmd_len; + +error_get_tdls_peers: + wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID); + return len; +} + 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, @@ -840,6 +891,11 @@ void wlan_cfg80211_tdls_event_callback(void *user_data, case TDLS_EVENT_TEARDOWN_LINKS_DONE: complete(&tdls_priv->tdls_teardown_comp); break; + case TDLS_EVENT_USER_CMD: + tdls_priv->tdls_user_cmd_len = ind->status; + complete(&tdls_priv->tdls_user_cmd_comp); + break; + default: break; } diff --git a/umac/tdls/core/src/wlan_tdls_main.c b/umac/tdls/core/src/wlan_tdls_main.c index 000bc78ee102..a423dcd08a05 100644 --- a/umac/tdls/core/src/wlan_tdls_main.c +++ b/umac/tdls/core/src/wlan_tdls_main.c @@ -293,6 +293,9 @@ QDF_STATUS tdls_process_cmd(struct scheduler_msg *msg) case TDLS_NOTIFY_RESET_ADAPTERS: tdls_notify_reset_adapter(msg->bodyptr); break; + case TDLS_CMD_GET_ALL_PEERS: + tdls_get_all_peers_from_list(msg->bodyptr); + break; default: break; } @@ -1001,6 +1004,97 @@ static void tdls_process_reset_adapter(struct wlan_objmgr_vdev *vdev) tdls_timers_stop(tdls_vdev); } +static int __tdls_get_all_peers_from_list( + struct tdls_get_all_peers *get_tdls_peers) +{ + int i; + int len, init_len; + qdf_list_t *head; + qdf_list_node_t *p_node; + struct tdls_peer *curr_peer; + char *buf; + int buf_len; + struct tdls_vdev_priv_obj *tdls_vdev; + QDF_STATUS status; + + tdls_notice("Enter "); + + buf = get_tdls_peers->buf; + buf_len = get_tdls_peers->buf_len; + + if (!tdls_is_vdev_connected(get_tdls_peers->vdev)) { + len = qdf_scnprintf(buf, buf_len, + "\nSTA is not associated\n"); + return len; + } + + tdls_vdev = wlan_vdev_get_tdls_vdev_obj(get_tdls_peers->vdev); + + if (!tdls_vdev) { + len = qdf_scnprintf(buf, buf_len, "TDLS not enabled\n"); + return len; + } + + init_len = buf_len; + len = qdf_scnprintf(buf, buf_len, + "\n%-18s%-3s%-4s%-3s%-5s\n", + "MAC", "Id", "cap", "up", "RSSI"); + buf += len; + buf_len -= len; + len = qdf_scnprintf(buf, buf_len, + "---------------------------------\n"); + buf += len; + buf_len -= len; + + for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) { + head = &tdls_vdev->peer_list[i]; + status = qdf_list_peek_front(head, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + curr_peer = qdf_container_of(p_node, + struct tdls_peer, node); + if (buf_len < 32 + 1) + break; + len = qdf_scnprintf(buf, buf_len, + QDF_MAC_ADDRESS_STR "%3d%4s%3s%5d\n", + QDF_MAC_ADDR_ARRAY(curr_peer->peer_mac.bytes), + curr_peer->sta_id, + (curr_peer->tdls_support == + TDLS_CAP_SUPPORTED) ? "Y" : "N", + TDLS_IS_LINK_CONNECTED(curr_peer) ? "Y" : + "N", curr_peer->rssi); + buf += len; + buf_len -= len; + status = qdf_list_peek_next(head, p_node, &p_node); + } + } + + tdls_notice("Exit "); + return init_len - buf_len; +} + +void tdls_get_all_peers_from_list( + struct tdls_get_all_peers *get_tdls_peers) +{ + int32_t len; + struct tdls_soc_priv_obj *tdls_soc_obj; + struct tdls_osif_indication indication; + + if (!get_tdls_peers->vdev) + qdf_mem_free(get_tdls_peers); + + len = __tdls_get_all_peers_from_list(get_tdls_peers); + + indication.status = len; + indication.vdev = get_tdls_peers->vdev; + + tdls_soc_obj = wlan_vdev_get_tdls_soc_obj(get_tdls_peers->vdev); + if (tdls_soc_obj && tdls_soc_obj->tdls_event_cb) + tdls_soc_obj->tdls_event_cb(tdls_soc_obj->tdls_evt_cb_data, + TDLS_EVENT_USER_CMD, &indication); + + qdf_mem_free(get_tdls_peers); +} + void tdls_notify_reset_adapter(struct wlan_objmgr_vdev *vdev) { if (!vdev) { diff --git a/umac/tdls/core/src/wlan_tdls_main.h b/umac/tdls/core/src/wlan_tdls_main.h index 95178af8cc65..0dee99c63fa8 100644 --- a/umac/tdls/core/src/wlan_tdls_main.h +++ b/umac/tdls/core/src/wlan_tdls_main.h @@ -574,6 +574,16 @@ QDF_STATUS tdls_notify_sta_connect(struct tdls_sta_notify_params *notify); */ QDF_STATUS tdls_notify_sta_disconnect(struct tdls_sta_notify_params *notify); + +/** + * tdls_get_all_peers_from_list() - get all the tdls peers from the list + * @get_tdls_peers: get_tdls_peers object + * + * Return: None + */ +void tdls_get_all_peers_from_list( + struct tdls_get_all_peers *get_tdls_peers); + /** * tdls_notify_reset_adapter() - notify reset adapter * @vdev: vdev object manager diff --git a/umac/tdls/dispatcher/inc/wlan_tdls_public_structs.h b/umac/tdls/dispatcher/inc/wlan_tdls_public_structs.h index 936623c0eb29..ae0a4077b247 100644 --- a/umac/tdls/dispatcher/inc/wlan_tdls_public_structs.h +++ b/umac/tdls/dispatcher/inc/wlan_tdls_public_structs.h @@ -62,6 +62,9 @@ /** Maximum time(ms) to wait for tdls mgmt to complete **/ #define WAIT_TIME_FOR_TDLS_MGMT 11000 +/** Maximum time(ms) to wait for tdls mgmt to complete **/ +#define WAIT_TIME_FOR_TDLS_USER_CMD 11000 + /** Maximum waittime for TDLS teardown links **/ #define WAIT_TIME_FOR_TDLS_TEARDOWN_LINKS 10000 @@ -181,6 +184,7 @@ enum tdls_feature_mode { * @TDLS_CMD_SESSION_DECREMENT: notify session decrement * @TDLS_CMD_TEARDOWN_LINKS: notify teardown * @TDLS_NOTIFY_RESET_ADAPTERS: notify adapater reset + * @TDLS_CMD_GET_ALL_PEERS: get all the tdls peers from the list */ enum tdls_command_type { TDLS_CMD_TX_ACTION = 1, @@ -201,6 +205,7 @@ enum tdls_command_type { TDLS_CMD_SESSION_DECREMENT, TDLS_CMD_TEARDOWN_LINKS, TDLS_NOTIFY_RESET_ADAPTERS, + TDLS_CMD_GET_ALL_PEERS, }; /** @@ -213,6 +218,8 @@ enum tdls_command_type { * @TDLS_EVENT_DISCOVERY_REQ: dicovery request * @TDLS_EVENT_TEARDOWN_REQ: teardown request * @TDLS_EVENT_SETUP_REQ: setup request + * @TDLS_EVENT_TEARDOWN_LINKS_DONE: teardown completion event + * @TDLS_EVENT_USER_CMD: tdls user command */ enum tdls_event_type { TDLS_EVENT_VDEV_STATE_CHANGE = 0, @@ -224,6 +231,7 @@ enum tdls_event_type { TDLS_EVENT_TEARDOWN_REQ, TDLS_EVENT_SETUP_REQ, TDLS_EVENT_TEARDOWN_LINKS_DONE, + TDLS_EVENT_USER_CMD, }; /** @@ -968,6 +976,18 @@ struct tdls_validate_action_req { int max_sta_failed; }; +/** + * struct tdls_get_all_peers - get all peers from the list + * @vdev: vdev object + * @buf: output string buffer to hold the peer info + * @buf_len: the size of output string buffer + */ +struct tdls_get_all_peers { + struct wlan_objmgr_vdev *vdev; + char *buf; + int buf_len; +}; + /** * struct tdls_send_action_frame_request - tdls send mgmt request * @vdev: vdev object diff --git a/umac/tdls/dispatcher/inc/wlan_tdls_ucfg_api.h b/umac/tdls/dispatcher/inc/wlan_tdls_ucfg_api.h index 0a06658fe8b7..f23bf52aebee 100644 --- a/umac/tdls/dispatcher/inc/wlan_tdls_ucfg_api.h +++ b/umac/tdls/dispatcher/inc/wlan_tdls_ucfg_api.h @@ -119,6 +119,17 @@ QDF_STATUS ucfg_tdls_update_peer(struct wlan_objmgr_vdev *vdev, QDF_STATUS ucfg_tdls_oper(struct wlan_objmgr_vdev *vdev, const uint8_t *macaddr, enum tdls_command_type cmd); +/** + * ucfg_tdls_get_all_peers() - get all tdls peers from the list + * @vdev: vdev object + * @buf: output buffer + * @buflen: length of written data + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_tdls_get_all_peers(struct wlan_objmgr_vdev *vdev, + char *buf, int buflen); + /** * ucfg_tdls_send_mgmt_frame() - send TDLS mgmt frame * @mgmt_req: pointer to TDLS action frame request struct diff --git a/umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c b/umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c index 930ea1bf9365..36c6318156f5 100644 --- a/umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c +++ b/umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c @@ -485,6 +485,35 @@ error: return status; } +QDF_STATUS ucfg_tdls_get_all_peers(struct wlan_objmgr_vdev *vdev, + char *buf, int buflen) +{ + struct scheduler_msg msg = {0, }; + struct tdls_get_all_peers *tdls_peers; + QDF_STATUS status; + + tdls_peers = qdf_mem_malloc(sizeof(*tdls_peers)); + + if (!tdls_peers) { + tdls_err("mem allocate fail"); + return QDF_STATUS_E_NOMEM; + } + + tdls_peers->vdev = vdev; + tdls_peers->buf_len = buflen; + tdls_peers->buf = buf; + + msg.bodyptr = tdls_peers; + msg.callback = tdls_process_cmd; + msg.type = TDLS_CMD_GET_ALL_PEERS; + status = scheduler_post_msg(QDF_MODULE_ID_OS_IF, &msg); + + if (status != QDF_STATUS_SUCCESS) + qdf_mem_free(tdls_peers); + + return QDF_STATUS_SUCCESS; +} + QDF_STATUS ucfg_tdls_send_mgmt_frame( struct tdls_action_frame_request *req) {