| /* |
| * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. |
| * |
| * Previously licensed under the ISC license by Qualcomm Atheros, Inc. |
| * |
| * |
| * 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. |
| */ |
| |
| /* |
| * This file was originally distributed by Qualcomm Atheros, Inc. |
| * under proprietary terms before Copyright ownership was assigned |
| * to the Linux Foundation. |
| */ |
| |
| /*=========================================================================== |
| * lim_process_tdls.c |
| * OVERVIEW: |
| * |
| * DEPENDENCIES: |
| * |
| * Are listed for each API below. |
| * ===========================================================================*/ |
| |
| /*=========================================================================== |
| |
| * EDIT HISTORY FOR FILE |
| |
| * This section contains comments describing changes made to the module. |
| * Notice that changes are listed in reverse chronological order. |
| |
| * $Header$$DateTime$$Author$ |
| |
| * when who what, where, why |
| * ---------- --- ------------------------------------------------------ |
| * 05/05/2010 Ashwani Initial Creation, added TDLS action frame |
| * functionality,TDLS message exchange with SME..etc.. |
| |
| ===========================================================================*/ |
| |
| /** |
| * \file lim_process_tdls.c |
| * |
| * \brief Code for preparing,processing and sending 802.11z action frames |
| * |
| */ |
| |
| #ifdef FEATURE_WLAN_TDLS |
| |
| #include "sir_api.h" |
| #include "ani_global.h" |
| #include "sir_mac_prot_def.h" |
| #include "cfg_api.h" |
| #include "utils_api.h" |
| #include "lim_types.h" |
| #include "lim_utils.h" |
| #include "lim_security_utils.h" |
| #include "dot11f.h" |
| #include "lim_sta_hash_api.h" |
| #include "sch_api.h" |
| #include "lim_send_messages.h" |
| #include "utils_parser.h" |
| #include "lim_assoc_utils.h" |
| #include "dph_hash_table.h" |
| #include "wma_types.h" |
| #include "cds_regdomain.h" |
| #include "cds_utils.h" |
| |
| /* define NO_PAD_TDLS_MIN_8023_SIZE to NOT padding: See CR#447630 |
| There was IOT issue with cisco 1252 open mode, where it pads |
| discovery req/teardown frame with some junk value up to min size. |
| To avoid this issue, we pad QCOM_VENDOR_IE. |
| If there is other IOT issue because of this bandage, define NO_PAD... |
| */ |
| #ifndef NO_PAD_TDLS_MIN_8023_SIZE |
| #define MIN_IEEE_8023_SIZE 46 |
| #define MIN_VENDOR_SPECIFIC_IE_SIZE 5 |
| #endif |
| |
| static tSirRetStatus lim_tdls_setup_add_sta(tpAniSirGlobal pMac, |
| tSirTdlsAddStaReq * pAddStaReq, tpPESession psessionEntry); |
| void populate_dot11f_link_iden(tpAniSirGlobal pMac, tpPESession psessionEntry, |
| tDot11fIELinkIdentifier *linkIden, |
| struct qdf_mac_addr peer_mac, uint8_t reqType); |
| void populate_dot11f_tdls_ext_capability(tpAniSirGlobal pMac, |
| tpPESession psessionEntry, |
| tDot11fIEExtCap *extCapability); |
| |
| void populate_dot11f_tdls_offchannel_params(tpAniSirGlobal pMac, |
| tpPESession psessionEntry, |
| tDot11fIESuppChannels *suppChannels, |
| tDot11fIESuppOperatingClasses * |
| suppOperClasses); |
| void lim_log_vht_cap(tpAniSirGlobal pMac, tDot11fIEVHTCaps *pDot11f); |
| tSirRetStatus lim_populate_vht_mcs_set(tpAniSirGlobal pMac, |
| tpSirSupportedRates pRates, |
| tDot11fIEVHTCaps *pPeerVHTCaps, |
| tpPESession psessionEntry, |
| uint8_t nss); |
| ePhyChanBondState lim_get_htcb_state(ePhyChanBondState aniCBMode); |
| |
| /* |
| * TDLS data frames will go out/come in as non-qos data. |
| * so, eth_890d_header will be aligned access.. |
| */ |
| static const uint8_t eth_890d_header[] = { |
| 0xaa, 0xaa, 0x03, 0x00, |
| 0x00, 0x00, 0x89, 0x0d, |
| }; |
| |
| /* |
| * type of links used in TDLS |
| */ |
| enum tdlsLinks { |
| TDLS_LINK_AP, |
| TDLS_LINK_DIRECT |
| } e_tdls_link; |
| |
| /* |
| * node status in node searching |
| */ |
| enum tdlsLinkNodeStatus { |
| TDLS_NODE_NOT_FOUND, |
| TDLS_NODE_FOUND |
| } e_tdls_link_node_status; |
| |
| enum tdlsReqType { |
| TDLS_INITIATOR, |
| TDLS_RESPONDER |
| } e_tdls_req_type; |
| |
| typedef enum tdlsLinkSetupStatus { |
| TDLS_SETUP_STATUS_SUCCESS = 0, |
| TDLS_SETUP_STATUS_FAILURE = 37 |
| } etdlsLinkSetupStatus; |
| |
| /* These maps to Kernel TDLS peer capability |
| * flags and should get changed as and when necessary |
| */ |
| enum tdls_peer_capability { |
| TDLS_PEER_HT_CAP = 0, |
| TDLS_PEER_VHT_CAP = 1, |
| TDLS_PEER_WMM_CAP = 2 |
| } e_tdls_peer_capability; |
| |
| /* some local defines */ |
| #define LINK_IDEN_ADDR_OFFSET(x) (&x.LinkIdentifier) |
| #define PTI_LINK_IDEN_OFFSET (5) |
| #define PTI_BUF_STATUS_OFFSET (25) |
| |
| /* TODO, Move this parameters to configuration */ |
| #define PEER_PSM_SUPPORT (0) |
| #define TDLS_SUPPORT (1) |
| #define TDLS_PROHIBITED (0) |
| #define TDLS_CH_SWITCH_PROHIBITED (1) |
| /** @brief Set bit manipulation macro */ |
| #define SET_BIT(value, mask) ((value) |= (1 << (mask))) |
| /** @brief Clear bit manipulation macro */ |
| #define CLEAR_BIT(value, mask) ((value) &= ~(1 << (mask))) |
| /** @brief Check bit manipulation macro */ |
| #define CHECK_BIT(value, mask) ((value) & (1 << (mask))) |
| |
| #define SET_PEER_AID_BITMAP(peer_bitmap, aid) \ |
| do { \ |
| if ((aid) < (sizeof(uint32_t) << 3)) \ |
| SET_BIT(peer_bitmap[0], (aid)); \ |
| else if ((aid) < (sizeof(uint32_t) << 4)) \ |
| SET_BIT(peer_bitmap[1], ((aid) - (sizeof(uint32_t) << 3)));\ |
| } while (0); |
| |
| #define CLEAR_PEER_AID_BITMAP(peer_bitmap, aid) \ |
| do { \ |
| if ((aid) < (sizeof(uint32_t) << 3)) \ |
| CLEAR_BIT(peer_bitmap[0], (aid)); \ |
| else if ((aid) < (sizeof(uint32_t) << 4)) \ |
| CLEAR_BIT(peer_bitmap[1], ((aid) - (sizeof(uint32_t) << 3)));\ |
| } while (0); |
| |
| #ifdef LIM_DEBUG_TDLS |
| |
| #ifdef FEATURE_WLAN_TDLS |
| #define WNI_CFG_TDLS_LINK_SETUP_RSP_TIMEOUT (800) |
| #define WNI_CFG_TDLS_LINK_SETUP_CNF_TIMEOUT (200) |
| #endif |
| |
| #define IS_QOS_ENABLED(psessionEntry) ((((psessionEntry)->limQosEnabled) && \ |
| SIR_MAC_GET_QOS((psessionEntry)->limCurrentBssCaps)) || \ |
| (((psessionEntry)->limWmeEnabled) && \ |
| LIM_BSS_CAPS_GET(WME, (psessionEntry)->limCurrentBssQosCaps))) |
| |
| #define TID_AC_VI 4 |
| #define TID_AC_BK 1 |
| |
| const uint8_t *lim_trace_tdls_action_string(uint8_t tdlsActionCode) |
| { |
| switch (tdlsActionCode) { |
| CASE_RETURN_STRING(SIR_MAC_TDLS_SETUP_REQ); |
| CASE_RETURN_STRING(SIR_MAC_TDLS_SETUP_RSP); |
| CASE_RETURN_STRING(SIR_MAC_TDLS_SETUP_CNF); |
| CASE_RETURN_STRING(SIR_MAC_TDLS_TEARDOWN); |
| CASE_RETURN_STRING(SIR_MAC_TDLS_PEER_TRAFFIC_IND); |
| CASE_RETURN_STRING(SIR_MAC_TDLS_CH_SWITCH_REQ); |
| CASE_RETURN_STRING(SIR_MAC_TDLS_CH_SWITCH_RSP); |
| CASE_RETURN_STRING(SIR_MAC_TDLS_PEER_TRAFFIC_RSP); |
| CASE_RETURN_STRING(SIR_MAC_TDLS_DIS_REQ); |
| CASE_RETURN_STRING(SIR_MAC_TDLS_DIS_RSP); |
| } |
| return (const uint8_t *)"UNKNOWN"; |
| } |
| #endif |
| /* |
| * initialize TDLS setup list and related data structures. |
| */ |
| void lim_init_tdls_data(tpAniSirGlobal pMac, tpPESession pSessionEntry) |
| { |
| lim_init_peer_idxpool(pMac, pSessionEntry); |
| |
| return; |
| } |
| |
| /* |
| * prepare TDLS frame header, it includes |
| * | | | | |
| * |802.11 header|RFC1042 header|TDLS_PYLOAD_TYPE|PAYLOAD |
| * | | | | |
| */ |
| static uint32_t lim_prepare_tdls_frame_header(tpAniSirGlobal pMac, uint8_t *pFrame, |
| tDot11fIELinkIdentifier *link_iden, |
| uint8_t tdlsLinkType, uint8_t reqType, |
| uint8_t tid, |
| tpPESession psessionEntry) |
| { |
| tpSirMacDataHdr3a pMacHdr; |
| uint32_t header_offset = 0; |
| uint8_t *addr1 = NULL; |
| uint8_t *addr3 = NULL; |
| uint8_t toDs = (tdlsLinkType == TDLS_LINK_AP) |
| ? ANI_TXDIR_TODS : ANI_TXDIR_IBSS; |
| uint8_t *peerMac = (reqType == TDLS_INITIATOR) |
| ? link_iden->RespStaAddr : link_iden->InitStaAddr; |
| uint8_t *staMac = (reqType == TDLS_INITIATOR) |
| ? link_iden->InitStaAddr : link_iden->RespStaAddr; |
| |
| pMacHdr = (tpSirMacDataHdr3a) (pFrame); |
| |
| /* |
| * if TDLS frame goes through the AP link, it follows normal address |
| * pattern, if TDLS frame goes thorugh the direct link, then |
| * A1--> Peer STA addr, A2-->Self STA address, A3--> BSSID |
| */ |
| (tdlsLinkType == TDLS_LINK_AP) ? ((addr1 = (link_iden->bssid)), |
| (addr3 = (peerMac))) |
| : ((addr1 = (peerMac)), (addr3 = (link_iden->bssid))); |
| /* |
| * prepare 802.11 header |
| */ |
| pMacHdr->fc.protVer = SIR_MAC_PROTOCOL_VERSION; |
| pMacHdr->fc.type = SIR_MAC_DATA_FRAME; |
| pMacHdr->fc.subType = |
| IS_QOS_ENABLED(psessionEntry) ? SIR_MAC_DATA_QOS_DATA : |
| SIR_MAC_DATA_DATA; |
| |
| /* |
| * TL is not setting up below fields, so we are doing it here |
| */ |
| pMacHdr->fc.toDS = toDs; |
| pMacHdr->fc.powerMgmt = 0; |
| pMacHdr->fc.wep = (psessionEntry->encryptType == eSIR_ED_NONE) ? 0 : 1; |
| |
| qdf_mem_copy((uint8_t *) pMacHdr->addr1, |
| (uint8_t *) addr1, sizeof(tSirMacAddr)); |
| qdf_mem_copy((uint8_t *) pMacHdr->addr2, |
| (uint8_t *) staMac, sizeof(tSirMacAddr)); |
| |
| qdf_mem_copy((uint8_t *) pMacHdr->addr3, |
| (uint8_t *) (addr3), sizeof(tSirMacAddr)); |
| |
| lim_log(pMac, LOG1, |
| FL( |
| "Preparing TDLS frame header to %s A1:" |
| MAC_ADDRESS_STR", A2:"MAC_ADDRESS_STR", A3:" |
| MAC_ADDRESS_STR |
| ), |
| (tdlsLinkType == TDLS_LINK_AP) ? "AP" : "DIRECT", |
| MAC_ADDR_ARRAY(pMacHdr->addr1), |
| MAC_ADDR_ARRAY(pMacHdr->addr2), |
| MAC_ADDR_ARRAY(pMacHdr->addr3)); |
| |
| if (IS_QOS_ENABLED(psessionEntry)) { |
| pMacHdr->qosControl.tid = tid; |
| header_offset += sizeof(tSirMacDataHdr3a); |
| } else |
| header_offset += sizeof(tSirMacMgmtHdr); |
| |
| /* |
| * Now form RFC1042 header |
| */ |
| qdf_mem_copy((uint8_t *) (pFrame + header_offset), |
| (uint8_t *) eth_890d_header, sizeof(eth_890d_header)); |
| |
| header_offset += sizeof(eth_890d_header); |
| |
| /* add payload type as TDLS */ |
| *(pFrame + header_offset) = PAYLOAD_TYPE_TDLS; |
| header_offset += PAYLOAD_TYPE_TDLS_SIZE; |
| return header_offset; |
| } |
| |
| /** |
| * lim_mgmt_tdls_tx_complete - callback to indicate Tx completion |
| * @mac_ctx: pointer to mac structure |
| * @tx_complete: indicates tx sucess/failure |
| * |
| * function will be invoked on receiving tx completion indication |
| * |
| * return: success: eHAL_STATUS_SUCCESS failure: eHAL_STATUS_FAILURE |
| */ |
| QDF_STATUS lim_mgmt_tdls_tx_complete(tpAniSirGlobal mac_ctx, |
| uint32_t tx_complete) |
| { |
| tpPESession session_entry = NULL; |
| |
| lim_log(mac_ctx, LOG1, FL("tdls_frm_session_id %x tx_complete %x"), |
| mac_ctx->lim.tdls_frm_session_id, tx_complete); |
| |
| if (NO_SESSION != mac_ctx->lim.tdls_frm_session_id) { |
| session_entry = pe_find_session_by_session_id(mac_ctx, |
| mac_ctx->lim.tdls_frm_session_id); |
| if (!session_entry) { |
| lim_log(mac_ctx, LOGE, FL("session id %d is not found"), |
| mac_ctx->lim.tdls_frm_session_id); |
| return QDF_STATUS_E_FAILURE; |
| } |
| lim_send_sme_mgmt_tx_completion(mac_ctx, session_entry, |
| tx_complete); |
| mac_ctx->lim.tdls_frm_session_id = NO_SESSION; |
| } |
| return QDF_STATUS_SUCCESS; |
| } |
| |
| /* |
| * This function can be used for bacst or unicast discovery request |
| * We are not differentiating it here, it will all depnds on peer MAC address, |
| */ |
| tSirRetStatus lim_send_tdls_dis_req_frame(tpAniSirGlobal pMac, |
| struct qdf_mac_addr peer_mac, |
| uint8_t dialog, |
| tpPESession psessionEntry) |
| { |
| tDot11fTDLSDisReq tdlsDisReq; |
| uint32_t status = 0; |
| uint32_t nPayload = 0; |
| uint32_t size = 0; |
| uint32_t nBytes = 0; |
| uint32_t header_offset = 0; |
| uint8_t *pFrame; |
| void *pPacket; |
| QDF_STATUS qdf_status; |
| #ifndef NO_PAD_TDLS_MIN_8023_SIZE |
| uint32_t padLen = 0; |
| #endif |
| uint8_t smeSessionId = 0; |
| |
| if (NULL == psessionEntry) { |
| lim_log(pMac, LOGE, FL("psessionEntry is NULL")); |
| return eSIR_FAILURE; |
| } |
| smeSessionId = psessionEntry->smeSessionId; |
| /* |
| * The scheme here is to fill out a 'tDot11fProbeRequest' structure |
| * and then hand it off to 'dot11f_pack_probe_request' (for |
| * serialization). We start by zero-initializing the structure: |
| */ |
| qdf_mem_set((uint8_t *) &tdlsDisReq, sizeof(tDot11fTDLSDisReq), 0); |
| |
| /* |
| * setup Fixed fields, |
| */ |
| tdlsDisReq.Category.category = SIR_MAC_ACTION_TDLS; |
| tdlsDisReq.Action.action = SIR_MAC_TDLS_DIS_REQ; |
| tdlsDisReq.DialogToken.token = dialog; |
| |
| size = sizeof(tSirMacAddr); |
| |
| populate_dot11f_link_iden(pMac, psessionEntry, &tdlsDisReq.LinkIdentifier, |
| peer_mac, TDLS_INITIATOR); |
| |
| /* |
| * now we pack it. First, how much space are we going to need? |
| */ |
| status = dot11f_get_packed_tdls_dis_req_size(pMac, &tdlsDisReq, &nPayload); |
| if (DOT11F_FAILED(status)) { |
| lim_log(pMac, LOGP, |
| FL( |
| "Failed to calculate the packed size for a discovery Request (0x%08x)." |
| ), |
| status); |
| /* We'll fall back on the worst case scenario: */ |
| nPayload = sizeof(tDot11fTDLSDisReq); |
| } else if (DOT11F_WARNED(status)) { |
| lim_log(pMac, LOGW, |
| FL( |
| "There were warnings while calculating the packed size for a discovery Request (0x%08x)." |
| ), |
| status); |
| } |
| |
| /* |
| * This frame is going out from PE as data frames with special ethertype |
| * 89-0d. |
| * 8 bytes of RFC 1042 header |
| */ |
| |
| nBytes = nPayload + ((IS_QOS_ENABLED(psessionEntry)) |
| ? sizeof(tSirMacDataHdr3a) : |
| sizeof(tSirMacMgmtHdr)) |
| + sizeof(eth_890d_header) |
| + PAYLOAD_TYPE_TDLS_SIZE; |
| |
| #ifndef NO_PAD_TDLS_MIN_8023_SIZE |
| /* IOT issue with some AP : some AP doesn't like the data packet size < minimum 802.3 frame length (64) |
| Hence AP itself padding some bytes, which caused teardown packet is dropped at |
| receiver side. To avoid such IOT issue, we added some extra bytes to meet data frame size >= 64 |
| */ |
| if (nPayload + PAYLOAD_TYPE_TDLS_SIZE < MIN_IEEE_8023_SIZE) { |
| padLen = |
| MIN_IEEE_8023_SIZE - (nPayload + PAYLOAD_TYPE_TDLS_SIZE); |
| |
| /* if padLen is less than minimum vendorSpecific (5), pad up to 5 */ |
| if (padLen < MIN_VENDOR_SPECIFIC_IE_SIZE) |
| padLen = MIN_VENDOR_SPECIFIC_IE_SIZE; |
| |
| nBytes += padLen; |
| } |
| #endif |
| |
| /* Ok-- try to allocate memory from MGMT PKT pool */ |
| |
| qdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, |
| (void **)&pPacket); |
| if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { |
| lim_log(pMac, LOGP, |
| FL( |
| "Failed to allocate %d bytes for a TDLS Discovery Request." |
| ), |
| nBytes); |
| return eSIR_MEM_ALLOC_FAILED; |
| } |
| |
| /* zero out the memory */ |
| qdf_mem_set(pFrame, nBytes, 0); |
| |
| /* |
| * IE formation, memory allocation is completed, Now form TDLS discovery |
| * request frame |
| */ |
| |
| /* fill out the buffer descriptor */ |
| |
| header_offset = lim_prepare_tdls_frame_header(pMac, pFrame, |
| LINK_IDEN_ADDR_OFFSET |
| (tdlsDisReq), TDLS_LINK_AP, |
| TDLS_INITIATOR, TID_AC_VI, |
| psessionEntry); |
| |
| status = dot11f_pack_tdls_dis_req(pMac, &tdlsDisReq, pFrame |
| + header_offset, nPayload, &nPayload); |
| |
| if (DOT11F_FAILED(status)) { |
| lim_log(pMac, LOGE, |
| FL("Failed to pack a TDLS discovery req (0x%08x)."), |
| status); |
| cds_packet_free((void *)pPacket); |
| return eSIR_FAILURE; |
| } else if (DOT11F_WARNED(status)) { |
| lim_log(pMac, LOGW, |
| FL( |
| "There were warnings while packing TDLS Discovery Request (0x%08x)." |
| ), |
| status); |
| } |
| #ifndef NO_PAD_TDLS_MIN_8023_SIZE |
| if (padLen != 0) { |
| /* QCOM VENDOR OUI = { 0x00, 0xA0, 0xC6, type = 0x0000 }; */ |
| uint8_t *padVendorSpecific = pFrame + header_offset + nPayload; |
| /* make QCOM_VENDOR_OUI, and type = 0x0000, and all the payload to be zero */ |
| padVendorSpecific[0] = 221; |
| padVendorSpecific[1] = padLen - 2; |
| padVendorSpecific[2] = 0x00; |
| padVendorSpecific[3] = 0xA0; |
| padVendorSpecific[4] = 0xC6; |
| |
| lim_log(pMac, LOGW, |
| FL("Padding Vendor Specific Ie Len = %d"), padLen); |
| |
| /* padding zero if more than 5 bytes are required */ |
| if (padLen > MIN_VENDOR_SPECIFIC_IE_SIZE) |
| qdf_mem_set(pFrame + header_offset + nPayload + |
| MIN_VENDOR_SPECIFIC_IE_SIZE, |
| padLen - MIN_VENDOR_SPECIFIC_IE_SIZE, 0); |
| } |
| #endif |
| |
| lim_log(pMac, LOG1, |
| FL("[TDLS] action %d (%s) -AP-> OTA peer="MAC_ADDRESS_STR), |
| SIR_MAC_TDLS_DIS_REQ, |
| lim_trace_tdls_action_string(SIR_MAC_TDLS_DIS_REQ), |
| MAC_ADDR_ARRAY(peer_mac.bytes)); |
| |
| pMac->lim.tdls_frm_session_id = psessionEntry->peSessionId; |
| qdf_status = wma_tx_frameWithTxComplete(pMac, pPacket, |
| (uint16_t) nBytes, |
| TXRX_FRM_802_11_DATA, |
| ANI_TXDIR_TODS, |
| TID_AC_VI, |
| lim_tx_complete, pFrame, |
| lim_mgmt_tdls_tx_complete, |
| HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME | |
| HAL_USE_PEER_STA_REQUESTED_MASK, |
| smeSessionId, false, 0); |
| if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { |
| pMac->lim.tdls_frm_session_id = NO_SESSION; |
| lim_log(pMac, LOGE, |
| FL("could not send TDLS Discovery Request frame")); |
| return eSIR_FAILURE; |
| } |
| |
| return eSIR_SUCCESS; |
| |
| } |
| |
| /* |
| * This static function is consistent with any kind of TDLS management |
| * frames we are sending. Currently it is being used by lim_send_tdls_dis_rsp_frame, |
| * lim_send_tdls_link_setup_req_frame and lim_send_tdls_setup_rsp_frame |
| */ |
| static void populate_dot11f_tdls_ht_vht_cap(tpAniSirGlobal pMac, |
| uint32_t selfDot11Mode, |
| tDot11fIEHTCaps *htCap, |
| tDot11fIEVHTCaps *vhtCap, |
| tpPESession psessionEntry) |
| { |
| uint8_t nss; |
| uint32_t val; |
| |
| if (IS_5G_CH(psessionEntry->currentOperChannel)) |
| nss = pMac->vdev_type_nss_5g.tdls; |
| else |
| nss = pMac->vdev_type_nss_2g.tdls; |
| |
| nss = QDF_MIN(nss, pMac->user_configured_nss); |
| if (IS_DOT11_MODE_HT(selfDot11Mode)) { |
| /* Include HT Capability IE */ |
| populate_dot11f_ht_caps(pMac, NULL, htCap); |
| val = SIZE_OF_SUPPORTED_MCS_SET; |
| wlan_cfg_get_str(pMac, WNI_CFG_SUPPORTED_MCS_SET, |
| &htCap->supportedMCSSet[0], &val); |
| if (NSS_1x1_MODE == nss) |
| htCap->supportedMCSSet[1] = 0; |
| /* |
| * Advertise ht capability and max supported channel bandwidth |
| * when populating HT IE in TDLS Setup Request/Setup Response/ |
| * Setup Confirmation frames. |
| * 11.21.6.2 Setting up a 40 MHz direct link: A 40 MHz |
| * off-channel direct link may be started if both TDLS peer STAs |
| * indicated 40 MHz support in the Supported Channel Width Set |
| * field of the HT Capabilities element (which is included in |
| * the TDLS Setup Request frame and the TDLS Setup Response |
| * frame). Switching to a 40 MHz off-channel direct link is |
| * achieved by including the following information in the TDLS |
| * Channel Switch Request |
| * 11.21.1 General: The channel width of the TDLS direct link on |
| * the base channel shall not exceed the channel width of the |
| * BSS to which the TDLS peer STAs are associated. |
| */ |
| htCap->supportedChannelWidthSet = 1; |
| } else { |
| htCap->present = 0; |
| } |
| lim_log(pMac, LOG1, FL("HT present = %hu, Chan Width = %hu"), |
| htCap->present, htCap->supportedChannelWidthSet); |
| if (((psessionEntry->currentOperChannel <= SIR_11B_CHANNEL_END) && |
| pMac->roam.configParam.enableVhtFor24GHz) || |
| (psessionEntry->currentOperChannel >= SIR_11B_CHANNEL_END)) { |
| if (IS_DOT11_MODE_VHT(selfDot11Mode) && |
| IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { |
| /* Include VHT Capability IE */ |
| populate_dot11f_vht_caps(pMac, psessionEntry, vhtCap); |
| |
| /* |
| * Set to 0 if the TDLS STA does not support either 160 |
| * or 80+80 MHz. |
| * Set to 1 if the TDLS STA supports 160 MHz. |
| * Set to 2 if the TDLS STA supports 160 MHz and |
| * 80+80 MHz. |
| * The value 3 is reserved |
| */ |
| vhtCap->supportedChannelWidthSet = 0; |
| |
| vhtCap->suBeamformeeCap = 0; |
| vhtCap->suBeamFormerCap = 0; |
| vhtCap->muBeamformeeCap = 0; |
| vhtCap->muBeamformerCap = 0; |
| |
| wlan_cfg_get_int(pMac, WNI_CFG_VHT_RX_MCS_MAP, &val); |
| vhtCap->rxMCSMap = val; |
| wlan_cfg_get_int(pMac, |
| WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE, |
| &val); |
| vhtCap->rxHighSupDataRate = val; |
| wlan_cfg_get_int(pMac, WNI_CFG_VHT_TX_MCS_MAP, &val); |
| vhtCap->txMCSMap = val; |
| wlan_cfg_get_int(pMac, |
| WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE, |
| &val); |
| vhtCap->txSupDataRate = val; |
| if (nss == NSS_1x1_MODE) { |
| vhtCap->txMCSMap |= DISABLE_NSS2_MCS; |
| vhtCap->rxMCSMap |= DISABLE_NSS2_MCS; |
| vhtCap->txSupDataRate = |
| VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1; |
| vhtCap->rxHighSupDataRate = |
| VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1; |
| } |
| } else { |
| vhtCap->present = 0; |
| } |
| } else { |
| /* Vht Disable from ini in 2.4 GHz */ |
| vhtCap->present = 0; |
| } |
| lim_log(pMac, LOG1, FL("VHT present = %hu, Chan Width = %hu"), |
| vhtCap->present, vhtCap->supportedChannelWidthSet); |
| } |
| |
| /* |
| * Send TDLS discovery response frame on direct link. |
| */ |
| |
| static tSirRetStatus lim_send_tdls_dis_rsp_frame(tpAniSirGlobal pMac, |
| struct qdf_mac_addr peer_mac, |
| uint8_t dialog, |
| tpPESession psessionEntry, |
| uint8_t *addIe, |
| uint16_t addIeLen) |
| { |
| tDot11fTDLSDisRsp tdlsDisRsp; |
| uint16_t caps = 0; |
| uint32_t status = 0; |
| uint32_t nPayload = 0; |
| uint32_t nBytes = 0; |
| uint8_t *pFrame; |
| void *pPacket; |
| QDF_STATUS qdf_status; |
| uint32_t selfDot11Mode; |
| /* Placeholder to support different channel bonding mode of TDLS than AP. */ |
| /* Today, WNI_CFG_CHANNEL_BONDING_MODE will be overwritten when connecting to AP */ |
| /* To support this feature, we need to introduce WNI_CFG_TDLS_CHANNEL_BONDING_MODE */ |
| /* As of now, we hardcoded to max channel bonding of dot11Mode (i.e HT80 for 11ac/HT40 for 11n) */ |
| /* uint32_t tdlsChannelBondingMode; */ |
| uint8_t smeSessionId = 0; |
| |
| if (NULL == psessionEntry) { |
| lim_log(pMac, LOGE, FL("psessionEntry is NULL")); |
| return eSIR_FAILURE; |
| } |
| smeSessionId = psessionEntry->smeSessionId; |
| |
| /* |
| * The scheme here is to fill out a 'tDot11fProbeRequest' structure |
| * and then hand it off to 'dot11f_pack_probe_request' (for |
| * serialization). We start by zero-initializing the structure: |
| */ |
| qdf_mem_set((uint8_t *) &tdlsDisRsp, sizeof(tDot11fTDLSDisRsp), 0); |
| |
| /* |
| * setup Fixed fields, |
| */ |
| tdlsDisRsp.Category.category = SIR_MAC_ACTION_PUBLIC_USAGE; |
| tdlsDisRsp.Action.action = SIR_MAC_TDLS_DIS_RSP; |
| tdlsDisRsp.DialogToken.token = dialog; |
| |
| populate_dot11f_link_iden(pMac, psessionEntry, |
| &tdlsDisRsp.LinkIdentifier, |
| peer_mac, TDLS_RESPONDER); |
| |
| if (cfg_get_capability_info(pMac, &caps, psessionEntry) |
| != eSIR_SUCCESS) { |
| /* |
| * Could not get Capabilities value |
| * from CFG. Log error. |
| */ |
| lim_log(pMac, LOGE, |
| FL("could not retrieve Capabilities value")); |
| } |
| swap_bit_field16(caps, (uint16_t *) &tdlsDisRsp.Capabilities); |
| |
| /* populate supported rate and ext supported rate IE */ |
| if (eSIR_FAILURE == populate_dot11f_rates_tdls(pMac, |
| &tdlsDisRsp.SuppRates, |
| &tdlsDisRsp.ExtSuppRates, |
| psessionEntry->currentOperChannel)) |
| lim_log(pMac, LOGE, |
| FL("could not populate supported data rates")); |
| |
| /* populate extended capability IE */ |
| populate_dot11f_tdls_ext_capability(pMac, |
| psessionEntry, |
| &tdlsDisRsp.ExtCap); |
| |
| wlan_cfg_get_int(pMac, WNI_CFG_DOT11_MODE, &selfDot11Mode); |
| |
| /* Populate HT/VHT Capabilities */ |
| populate_dot11f_tdls_ht_vht_cap(pMac, selfDot11Mode, &tdlsDisRsp.HTCaps, |
| &tdlsDisRsp.VHTCaps, psessionEntry); |
| |
| /* Populate TDLS offchannel param only if offchannel is enabled |
| * and TDLS Channel Switching is not prohibited by AP in ExtCap |
| * IE in assoc/re-assoc response. |
| */ |
| if ((1 == pMac->lim.gLimTDLSOffChannelEnabled) && |
| (!psessionEntry->tdls_chan_swit_prohibited)) { |
| populate_dot11f_tdls_offchannel_params(pMac, psessionEntry, |
| &tdlsDisRsp.SuppChannels, |
| &tdlsDisRsp. |
| SuppOperatingClasses); |
| if (pMac->roam.configParam.bandCapability != eCSR_BAND_24) { |
| tdlsDisRsp.ht2040_bss_coexistence.present = 1; |
| tdlsDisRsp.ht2040_bss_coexistence.info_request = 1; |
| } |
| } else { |
| lim_log(pMac, LOG1, |
| FL("TDLS offchan not enabled, or channel switch prohibited by AP, gLimTDLSOffChannelEnabled (%d), tdls_chan_swit_prohibited (%d)"), |
| pMac->lim.gLimTDLSOffChannelEnabled, |
| psessionEntry->tdls_chan_swit_prohibited); |
| } |
| /* |
| * now we pack it. First, how much space are we going to need? |
| */ |
| status = dot11f_get_packed_tdls_dis_rsp_size(pMac, &tdlsDisRsp, &nPayload); |
| if (DOT11F_FAILED(status)) { |
| lim_log(pMac, LOGE, |
| FL( |
| "Failed to calculate the packed size for a Discovery Response (0x%08x)." |
| ), |
| status); |
| /* We'll fall back on the worst case scenario: */ |
| nPayload = sizeof(tDot11fProbeRequest); |
| } else if (DOT11F_WARNED(status)) { |
| lim_log(pMac, LOGW, |
| FL( |
| "There were warnings while calculating the packed size for a Discovery Response (0x%08x)." |
| ), |
| status); |
| } |
| |
| /* |
| * This frame is going out from PE as data frames with special ethertype |
| * 89-0d. |
| * 8 bytes of RFC 1042 header |
| */ |
| |
| nBytes = nPayload + sizeof(tSirMacMgmtHdr) + addIeLen; |
| |
| /* Ok-- try to allocate memory from MGMT PKT pool */ |
| qdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, |
| (void **)&pPacket); |
| if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { |
| lim_log(pMac, LOGE, |
| FL( |
| "Failed to allocate %d bytes for a TDLS Discovery Request." |
| ), |
| nBytes); |
| return eSIR_MEM_ALLOC_FAILED; |
| } |
| |
| /* zero out the memory */ |
| qdf_mem_set(pFrame, nBytes, 0); |
| |
| /* |
| * IE formation, memory allocation is completed, Now form TDLS discovery |
| * response frame |
| */ |
| |
| /* Make public Action Frame */ |
| |
| lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, |
| SIR_MAC_MGMT_ACTION, peer_mac.bytes, |
| psessionEntry->selfMacAddr); |
| |
| { |
| tpSirMacMgmtHdr pMacHdr; |
| pMacHdr = (tpSirMacMgmtHdr) pFrame; |
| pMacHdr->fc.toDS = ANI_TXDIR_IBSS; |
| pMacHdr->fc.powerMgmt = 0; |
| sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); |
| } |
| |
| status = dot11f_pack_tdls_dis_rsp(pMac, &tdlsDisRsp, pFrame + |
| sizeof(tSirMacMgmtHdr), |
| nPayload, &nPayload); |
| |
| if (DOT11F_FAILED(status)) { |
| lim_log(pMac, LOGE, |
| FL( |
| "Failed to pack a TDLS discovery response (0x%08x)." |
| ), |
| status); |
| cds_packet_free((void *)pPacket); |
| return eSIR_FAILURE; |
| } else if (DOT11F_WARNED(status)) { |
| lim_log(pMac, LOGW, |
| FL( |
| "There were warnings while packing TDLS Discovery Response (0x%08x)." |
| ), |
| status); |
| } |
| if (0 != addIeLen) { |
| lim_log(pMac, LOG1, |
| FL("Copy Additional Ie Len = %d"), addIeLen); |
| qdf_mem_copy(pFrame + sizeof(tSirMacMgmtHdr) + nPayload, addIe, |
| addIeLen); |
| } |
| lim_log(pMac, LOG1, |
| FL("[TDLS] action %d (%s) -DIRECT-> OTA peer="MAC_ADDRESS_STR), |
| SIR_MAC_TDLS_DIS_RSP, |
| lim_trace_tdls_action_string(SIR_MAC_TDLS_DIS_RSP), |
| MAC_ADDR_ARRAY(peer_mac.bytes)); |
| |
| pMac->lim.tdls_frm_session_id = psessionEntry->peSessionId; |
| /* |
| * Transmit Discovery response and watch if this is delivered to |
| * peer STA. |
| */ |
| /* In CLD 2.0, pass Discovery Response as mgmt frame so that |
| * wma does not do header conversion to 802.3 before calling tx/rx |
| * routine and subsequenly target also sends frame as is OTA |
| */ |
| qdf_status = wma_tx_frameWithTxComplete(pMac, pPacket, (uint16_t) nBytes, |
| TXRX_FRM_802_11_MGMT, |
| ANI_TXDIR_IBSS, |
| 0, |
| lim_tx_complete, pFrame, |
| lim_mgmt_tdls_tx_complete, |
| HAL_USE_SELF_STA_REQUESTED_MASK, |
| smeSessionId, false, 0); |
| if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { |
| pMac->lim.tdls_frm_session_id = NO_SESSION; |
| lim_log(pMac, LOGE, |
| FL("could not send TDLS Discovery Response frame!")); |
| return eSIR_FAILURE; |
| } |
| |
| return eSIR_SUCCESS; |
| |
| } |
| |
| /* |
| * This static function is currently used by lim_send_tdls_link_setup_req_frame and |
| * lim_send_tdls_setup_rsp_frame to populate the AID if device is 11ac capable. |
| */ |
| static void populate_dotf_tdls_vht_aid(tpAniSirGlobal pMac, uint32_t selfDot11Mode, |
| struct qdf_mac_addr peerMac, |
| tDot11fIEAID *Aid, |
| tpPESession psessionEntry) |
| { |
| if (((psessionEntry->currentOperChannel <= SIR_11B_CHANNEL_END) && |
| pMac->roam.configParam.enableVhtFor24GHz) || |
| (psessionEntry->currentOperChannel >= SIR_11B_CHANNEL_END)) { |
| if (IS_DOT11_MODE_VHT(selfDot11Mode) && |
| IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { |
| |
| uint16_t aid; |
| tpDphHashNode pStaDs; |
| |
| pStaDs = |
| dph_lookup_hash_entry(pMac, peerMac.bytes, &aid, |
| &psessionEntry->dph. |
| dphHashTable); |
| if (NULL != pStaDs) { |
| Aid->present = 1; |
| Aid->assocId = aid | LIM_AID_MASK; /* set bit 14 and 15 1's */ |
| } else { |
| Aid->present = 0; |
| lim_log(pMac, LOGE, |
| FL("pStaDs is NULL for " |
| MAC_ADDRESS_STR), |
| MAC_ADDR_ARRAY(peerMac.bytes)); |
| } |
| } |
| } else { |
| Aid->present = 0; |
| lim_log(pMac, LOGW, FL("Vht not enable from ini for 2.4GHz.")); |
| } |
| } |
| |
| #ifdef CONFIG_HL_SUPPORT |
| |
| /** |
| * wma_tx_frame_with_tx_complete_send() - Send tx frames on Direct link or AP link |
| * depend on reason code |
| * @pMac: pointer to MAC Sirius parameter structure |
| * @pPacket: pointer to mgmt packet |
| * @nBytes: number of bytes to send |
| * @tid:tid value for AC |
| * @pFrame: pointer to tdls frame |
| * @smeSessionId:session id |
| * @flag: tdls flag |
| * |
| * Send TDLS Teardown frame on Direct link or AP link, depends on reason code. |
| * |
| * Return: None |
| */ |
| static inline QDF_STATUS |
| wma_tx_frame_with_tx_complete_send(tpAniSirGlobal pMac, void *pPacket, |
| uint16_t nBytes, |
| uint8_t tid, |
| uint8_t *pFrame, |
| uint8_t smeSessionId, bool flag) |
| { |
| return wma_tx_frameWithTxComplete(pMac, pPacket, |
| (uint16_t) nBytes, |
| TXRX_FRM_802_11_DATA, |
| ANI_TXDIR_TODS, |
| tid, |
| lim_tx_complete, pFrame, |
| lim_mgmt_tdls_tx_complete, |
| HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME |
| | HAL_USE_PEER_STA_REQUESTED_MASK, |
| smeSessionId, flag, 0); |
| } |
| #else |
| |
| static inline QDF_STATUS |
| wma_tx_frame_with_tx_complete_send(tpAniSirGlobal pMac, void *pPacket, |
| uint16_t nBytes, |
| uint8_t tid, |
| uint8_t *pFrame, |
| uint8_t smeSessionId, bool flag) |
| { |
| return wma_tx_frameWithTxComplete(pMac, pPacket, |
| (uint16_t) nBytes, |
| TXRX_FRM_802_11_DATA, |
| ANI_TXDIR_TODS, |
| tid, |
| lim_tx_complete, pFrame, |
| lim_mgmt_tdls_tx_complete, |
| HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME |
| | HAL_USE_PEER_STA_REQUESTED_MASK, |
| smeSessionId, false, 0); |
| } |
| #endif |
| |
| void lim_set_tdls_flags(roam_offload_synch_ind *roam_sync_ind_ptr, |
| tpPESession ft_session_ptr) |
| { |
| roam_sync_ind_ptr->join_rsp->tdls_prohibited = |
| ft_session_ptr->tdls_prohibited; |
| roam_sync_ind_ptr->join_rsp->tdls_chan_swit_prohibited = |
| ft_session_ptr->tdls_chan_swit_prohibited; |
| } |
| |
| /* |
| * TDLS setup Request frame on AP link |
| */ |
| tSirRetStatus lim_send_tdls_link_setup_req_frame(tpAniSirGlobal pMac, |
| struct qdf_mac_addr peer_mac, |
| uint8_t dialog, |
| tpPESession psessionEntry, |
| uint8_t *addIe, |
| uint16_t addIeLen) |
| { |
| tDot11fTDLSSetupReq tdlsSetupReq; |
| uint16_t caps = 0; |
| uint32_t status = 0; |
| uint32_t nPayload = 0; |
| uint32_t nBytes = 0; |
| uint32_t header_offset = 0; |
| uint8_t *pFrame; |
| void *pPacket; |
| QDF_STATUS qdf_status; |
| uint32_t selfDot11Mode; |
| uint8_t smeSessionId = 0; |
| /* Placeholder to support different channel bonding mode of TDLS than AP. */ |
| /* Today, WNI_CFG_CHANNEL_BONDING_MODE will be overwritten when connecting to AP */ |
| /* To support this feature, we need to introduce WNI_CFG_TDLS_CHANNEL_BONDING_MODE */ |
| /* As of now, we hardcoded to max channel bonding of dot11Mode (i.e HT80 for 11ac/HT40 for 11n) */ |
| /* uint32_t tdlsChannelBondingMode; */ |
| |
| /* |
| * The scheme here is to fill out a 'tDot11fProbeRequest' structure |
| * and then hand it off to 'dot11f_pack_probe_request' (for |
| * serialization). We start by zero-initializing the structure: |
| */ |
| smeSessionId = psessionEntry->smeSessionId; |
| |
| qdf_mem_set((uint8_t *) &tdlsSetupReq, sizeof(tDot11fTDLSSetupReq), 0); |
| tdlsSetupReq.Category.category = SIR_MAC_ACTION_TDLS; |
| tdlsSetupReq.Action.action = SIR_MAC_TDLS_SETUP_REQ; |
| tdlsSetupReq.DialogToken.token = dialog; |
| |
| populate_dot11f_link_iden(pMac, psessionEntry, |
| &tdlsSetupReq.LinkIdentifier, peer_mac, |
| TDLS_INITIATOR); |
| |
| if (cfg_get_capability_info(pMac, &caps, psessionEntry) != eSIR_SUCCESS) { |
| /* |
| * Could not get Capabilities value |
| * from CFG. Log error. |
| */ |
| lim_log(pMac, LOGE, |
| FL("could not retrieve Capabilities value")); |
| } |
| swap_bit_field16(caps, (uint16_t *) &tdlsSetupReq.Capabilities); |
| |
| /* populate supported rate and ext supported rate IE */ |
| if (eSIR_FAILURE == populate_dot11f_rates_tdls(pMac, |
| &tdlsSetupReq.SuppRates, |
| &tdlsSetupReq.ExtSuppRates, |
| psessionEntry->currentOperChannel)) |
| lim_log(pMac, LOGE, |
| FL("could not populate supported data rates")); |
| |
| /* Populate extended capability IE */ |
| populate_dot11f_tdls_ext_capability(pMac, |
| psessionEntry, |
| &tdlsSetupReq.ExtCap); |
| |
| if (1 == pMac->lim.gLimTDLSWmmMode) { |
| uint32_t val = 0; |
| |
| lim_log(pMac, LOG1, |
| FL("populate WMM IE in Setup Request Frame")); |
| /* include WMM IE */ |
| tdlsSetupReq.WMMInfoStation.version = SIR_MAC_OUI_VERSION_1; |
| tdlsSetupReq.WMMInfoStation.acvo_uapsd = |
| (pMac->lim.gLimTDLSUapsdMask & 0x01); |
| tdlsSetupReq.WMMInfoStation.acvi_uapsd = |
| ((pMac->lim.gLimTDLSUapsdMask & 0x02) >> 1); |
| tdlsSetupReq.WMMInfoStation.acbk_uapsd = |
| ((pMac->lim.gLimTDLSUapsdMask & 0x04) >> 2); |
| tdlsSetupReq.WMMInfoStation.acbe_uapsd = |
| ((pMac->lim.gLimTDLSUapsdMask & 0x08) >> 3); |
| |
| if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_SP_LENGTH, &val) != |
| eSIR_SUCCESS) |
| lim_log(pMac, LOGE, |
| FL("could not retrieve Max SP Length")); |
| |
| tdlsSetupReq.WMMInfoStation.max_sp_length = (uint8_t) val; |
| tdlsSetupReq.WMMInfoStation.present = 1; |
| } else { |
| /* |
| * TODO: we need to see if we have to support conditions where |
| * we have EDCA parameter info element is needed a) if we need |
| * different QOS parameters for off channel operations or QOS |
| * is not supported on AP link and we wanted to QOS on direct |
| * link. |
| */ |
| |
| /* Populate QOS info, needed for Peer U-APSD session */ |
| |
| /* |
| * TODO: Now hardcoded, since populate_dot11f_qos_caps_station() |
| * depends on AP's capability, and TDLS doesn't want to depend |
| * on AP's capability |
| */ |
| |
| lim_log(pMac, LOG1, |
| FL("populate QOS IE in Setup Request Frame")); |
| tdlsSetupReq.QOSCapsStation.present = 1; |
| tdlsSetupReq.QOSCapsStation.max_sp_length = 0; |
| tdlsSetupReq.QOSCapsStation.qack = 0; |
| tdlsSetupReq.QOSCapsStation.acbe_uapsd = |
| ((pMac->lim.gLimTDLSUapsdMask & 0x08) >> 3); |
| tdlsSetupReq.QOSCapsStation.acbk_uapsd = |
| ((pMac->lim.gLimTDLSUapsdMask & 0x04) >> 2); |
| tdlsSetupReq.QOSCapsStation.acvi_uapsd = |
| ((pMac->lim.gLimTDLSUapsdMask & 0x02) >> 1); |
| tdlsSetupReq.QOSCapsStation.acvo_uapsd = |
| (pMac->lim.gLimTDLSUapsdMask & 0x01); |
| } |
| |
| /* |
| * we will always try to init TDLS link with 11n capabilities |
| * let TDLS setup response to come, and we will set our caps based |
| * of peer caps |
| */ |
| |
| wlan_cfg_get_int(pMac, WNI_CFG_DOT11_MODE, &selfDot11Mode); |
| |
| /* Populate HT/VHT Capabilities */ |
| populate_dot11f_tdls_ht_vht_cap(pMac, selfDot11Mode, &tdlsSetupReq.HTCaps, |
| &tdlsSetupReq.VHTCaps, psessionEntry); |
| |
| /* Populate AID */ |
| populate_dotf_tdls_vht_aid(pMac, selfDot11Mode, peer_mac, |
| &tdlsSetupReq.AID, psessionEntry); |
| |
| /* Populate TDLS offchannel param only if offchannel is enabled |
| * and TDLS Channel Switching is not prohibited by AP in ExtCap |
| * IE in assoc/re-assoc response. |
| */ |
| if ((1 == pMac->lim.gLimTDLSOffChannelEnabled) && |
| (!psessionEntry->tdls_chan_swit_prohibited)) { |
| populate_dot11f_tdls_offchannel_params(pMac, psessionEntry, |
| &tdlsSetupReq.SuppChannels, |
| &tdlsSetupReq. |
| SuppOperatingClasses); |
| if (pMac->roam.configParam.bandCapability != eCSR_BAND_24) { |
| tdlsSetupReq.ht2040_bss_coexistence.present = 1; |
| tdlsSetupReq.ht2040_bss_coexistence.info_request = 1; |
| } |
| } else { |
| lim_log(pMac, LOG1, |
| FL("TDLS offchan not enabled, or channel switch prohibited by AP, gLimTDLSOffChannelEnabled (%d), tdls_chan_swit_prohibited (%d)"), |
| pMac->lim.gLimTDLSOffChannelEnabled, |
| psessionEntry->tdls_chan_swit_prohibited); |
| } |
| /* |
| * now we pack it. First, how much space are we going to need? |
| */ |
| status = dot11f_get_packed_tdls_setup_req_size(pMac, &tdlsSetupReq, |
| &nPayload); |
| if (DOT11F_FAILED(status)) { |
| lim_log(pMac, LOGE, |
| FL( |
| "Failed to calculate the packed size for a Setup Request (0x%08x)." |
| ), |
| status); |
| /* We'll fall back on the worst case scenario: */ |
| nPayload = sizeof(tDot11fProbeRequest); |
| } else if (DOT11F_WARNED(status)) { |
| lim_log(pMac, LOGW, |
| FL( |
| "There were warnings while calculating the packed size for a Setup Request (0x%08x)." |
| ), |
| status); |
| } |
| |
| /* |
| * This frame is going out from PE as data frames with special ethertype |
| * 89-0d. |
| * 8 bytes of RFC 1042 header |
| */ |
| |
| nBytes = nPayload + ((IS_QOS_ENABLED(psessionEntry)) |
| ? sizeof(tSirMacDataHdr3a) : |
| sizeof(tSirMacMgmtHdr)) |
| + sizeof(eth_890d_header) |
| + PAYLOAD_TYPE_TDLS_SIZE + addIeLen; |
| |
| /* Ok-- try to allocate memory from MGMT PKT pool */ |
| qdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, |
| (void **)&pPacket); |
| if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { |
| lim_log(pMac, LOGE, |
| FL( |
| "Failed to allocate %d bytes for a TDLS Setup Request." |
| ), |
| nBytes); |
| return eSIR_MEM_ALLOC_FAILED; |
| } |
| |
| /* zero out the memory */ |
| qdf_mem_set(pFrame, nBytes, 0); |
| |
| /* |
| * IE formation, memory allocation is completed, Now form TDLS discovery |
| * request frame |
| */ |
| |
| /* fill out the buffer descriptor */ |
| |
| header_offset = lim_prepare_tdls_frame_header(pMac, pFrame, |
| LINK_IDEN_ADDR_OFFSET |
| (tdlsSetupReq), TDLS_LINK_AP, |
| TDLS_INITIATOR, TID_AC_VI, |
| psessionEntry); |
| |
| lim_log(pMac, LOGW, |
| FL( |
| "SupportedChnlWidth %x rxMCSMap %x rxMCSMap %x txSupDataRate %x" |
| ), |
| tdlsSetupReq.VHTCaps.supportedChannelWidthSet, |
| tdlsSetupReq.VHTCaps.rxMCSMap, |
| tdlsSetupReq.VHTCaps.txMCSMap, |
| tdlsSetupReq.VHTCaps.txSupDataRate); |
| |
| status = dot11f_pack_tdls_setup_req(pMac, &tdlsSetupReq, pFrame |
| + header_offset, nPayload, &nPayload); |
| |
| if (DOT11F_FAILED(status)) { |
| lim_log(pMac, LOGE, |
| FL("Failed to pack a TDLS Setup request (0x%08x)."), |
| status); |
| cds_packet_free((void *)pPacket); |
| return eSIR_FAILURE; |
| } else if (DOT11F_WARNED(status)) { |
| lim_log(pMac, LOGW, |
| FL( |
| "There were warnings while packing TDLS Setup Request (0x%08x)." |
| ), |
| status); |
| } |
| /* Copy the additional IE. */ |
| /* TODO : addIe is added at the end of the frame. This means it doesnt */ |
| /* follow the order. This should be ok, but we should consider changing this */ |
| /* if there is any IOT issue. */ |
| if (addIeLen != 0) { |
| lim_log(pMac, LOG1, FL("Copy Additional Ie Len = %d"), |
| addIeLen); |
| qdf_mem_copy(pFrame + header_offset + nPayload, addIe, |
| addIeLen); |
| } |
| |
| lim_log(pMac, LOG1, |
| FL("[TDLS] action %d (%s) -AP-> OTA peer="MAC_ADDRESS_STR), |
| SIR_MAC_TDLS_SETUP_REQ, |
| lim_trace_tdls_action_string(SIR_MAC_TDLS_SETUP_REQ), |
| MAC_ADDR_ARRAY(peer_mac.bytes)); |
| |
| pMac->lim.tdls_frm_session_id = psessionEntry->peSessionId; |
| |
| qdf_status = wma_tx_frame_with_tx_complete_send(pMac, pPacket, |
| (uint16_t) nBytes, |
| TID_AC_VI, |
| pFrame, |
| smeSessionId, true); |
| |
| if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { |
| pMac->lim.tdls_frm_session_id = NO_SESSION; |
| lim_log(pMac, LOGE, |
| FL("could not send TDLS Setup Request frame!")); |
| return eSIR_FAILURE; |
| } |
| |
| return eSIR_SUCCESS; |
| |
| } |
| |
| /* |
| * Send TDLS Teardown frame on Direct link or AP link, depends on reason code. |
| */ |
| |
| tSirRetStatus lim_send_tdls_teardown_frame(tpAniSirGlobal pMac, |
| struct qdf_mac_addr peer_mac, |
| uint16_t reason, |
| uint8_t responder, |
| tpPESession psessionEntry, |
| uint8_t *addIe, uint16_t addIeLen) |
| { |
| tDot11fTDLSTeardown teardown; |
| uint32_t status = 0; |
| uint32_t nPayload = 0; |
| uint32_t nBytes = 0; |
| uint32_t header_offset = 0; |
| uint8_t *pFrame; |
| void *pPacket; |
| QDF_STATUS qdf_status; |
| #ifndef NO_PAD_TDLS_MIN_8023_SIZE |
| uint32_t padLen = 0; |
| #endif |
| uint8_t smeSessionId = 0; |
| |
| if (NULL == psessionEntry) { |
| lim_log(pMac, LOGE, FL("psessionEntry is NULL")); |
| return eSIR_FAILURE; |
| } |
| smeSessionId = psessionEntry->smeSessionId; |
| /* |
| * The scheme here is to fill out a 'tDot11fProbeRequest' structure |
| * and then hand it off to 'dot11f_pack_probe_request' (for |
| * serialization). We start by zero-initializing the structure: |
| */ |
| qdf_mem_set((uint8_t *) &teardown, sizeof(tDot11fTDLSTeardown), 0); |
| teardown.Category.category = SIR_MAC_ACTION_TDLS; |
| teardown.Action.action = SIR_MAC_TDLS_TEARDOWN; |
| teardown.Reason.code = reason; |
| |
| populate_dot11f_link_iden(pMac, psessionEntry, &teardown.LinkIdentifier, |
| peer_mac, |
| (responder == |
| true) ? TDLS_RESPONDER : TDLS_INITIATOR); |
| |
| /* |
| * now we pack it. First, how much space are we going to need? |
| */ |
| status = dot11f_get_packed_tdls_teardown_size(pMac, &teardown, &nPayload); |
| if (DOT11F_FAILED(status)) { |
| lim_log(pMac, LOGE, |
| FL( |
| "Failed to calculate the packed size for a discovery Request (0x%08x)." |
| ), |
| status); |
| /* We'll fall back on the worst case scenario: */ |
| nPayload = sizeof(tDot11fProbeRequest); |
| } else if (DOT11F_WARNED(status)) { |
| lim_log(pMac, LOGW, |
| FL( |
| "There were warnings while calculating the packed size for a discovery Request (0x%08x)." |
| ), |
| status); |
| } |
| |
| /* |
| * This frame is going out from PE as data frames with special ethertype |
| * 89-0d. |
| * 8 bytes of RFC 1042 header |
| */ |
| |
| nBytes = nPayload + ((IS_QOS_ENABLED(psessionEntry)) |
| ? sizeof(tSirMacDataHdr3a) : |
| sizeof(tSirMacMgmtHdr)) |
| + sizeof(eth_890d_header) |
| + PAYLOAD_TYPE_TDLS_SIZE + addIeLen; |
| |
| #ifndef NO_PAD_TDLS_MIN_8023_SIZE |
| /* IOT issue with some AP : some AP doesn't like the data packet size < minimum 802.3 frame length (64) |
| Hence AP itself padding some bytes, which caused teardown packet is dropped at |
| receiver side. To avoid such IOT issue, we added some extra bytes to meet data frame size >= 64 |
| */ |
| if (nPayload + PAYLOAD_TYPE_TDLS_SIZE < MIN_IEEE_8023_SIZE) { |
| padLen = |
| MIN_IEEE_8023_SIZE - (nPayload + PAYLOAD_TYPE_TDLS_SIZE); |
| |
| /* if padLen is less than minimum vendorSpecific (5), pad up to 5 */ |
| if (padLen < MIN_VENDOR_SPECIFIC_IE_SIZE) |
| padLen = MIN_VENDOR_SPECIFIC_IE_SIZE; |
| |
| nBytes += padLen; |
| } |
| #endif |
| |
| /* Ok-- try to allocate memory from MGMT PKT pool */ |
| qdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, |
| (void **)&pPacket); |
| if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { |
| lim_log(pMac, LOGE, |
| FL( |
| "Failed to allocate %d bytes for a TDLS Teardown Frame." |
| ), |
| nBytes); |
| return eSIR_MEM_ALLOC_FAILED; |
| } |
| |
| /* zero out the memory */ |
| qdf_mem_set(pFrame, nBytes, 0); |
| |
| /* |
| * IE formation, memory allocation is completed, Now form TDLS discovery |
| * request frame |
| */ |
| |
| /* fill out the buffer descriptor */ |
| lim_log(pMac, LOGE, FL("Reason of TDLS Teardown: %d"), reason); |
| header_offset = lim_prepare_tdls_frame_header(pMac, pFrame, |
| LINK_IDEN_ADDR_OFFSET |
| (teardown), |
| (reason == |
| eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE) |
| ? TDLS_LINK_AP : |
| TDLS_LINK_DIRECT, |
| (responder == |
| true) ? TDLS_RESPONDER : |
| TDLS_INITIATOR, TID_AC_VI, |
| psessionEntry); |
| |
| status = dot11f_pack_tdls_teardown(pMac, &teardown, pFrame |
| + header_offset, nPayload, &nPayload); |
| |
| if (DOT11F_FAILED(status)) { |
| lim_log(pMac, LOGE, |
| FL("Failed to pack a TDLS Teardown frame (0x%08x)."), |
| status); |
| cds_packet_free((void *)pPacket); |
| return eSIR_FAILURE; |
| } else if (DOT11F_WARNED(status)) { |
| lim_log(pMac, LOGW, |
| FL( |
| "There were warnings while packing TDLS Teardown frame (0x%08x)." |
| ), |
| status); |
| } |
| |
| if (addIeLen != 0) { |
| lim_log(pMac, LOGW, |
| FL("Copy Additional Ie Len = %d"), addIeLen); |
| qdf_mem_copy(pFrame + header_offset + nPayload, addIe, |
| addIeLen); |
| } |
| #ifndef NO_PAD_TDLS_MIN_8023_SIZE |
| if (padLen != 0) { |
| /* QCOM VENDOR OUI = { 0x00, 0xA0, 0xC6, type = 0x0000 }; */ |
| uint8_t *padVendorSpecific = |
| pFrame + header_offset + nPayload + addIeLen; |
| /* make QCOM_VENDOR_OUI, and type = 0x0000, and all the payload to be zero */ |
| padVendorSpecific[0] = 221; |
| padVendorSpecific[1] = padLen - 2; |
| padVendorSpecific[2] = 0x00; |
| padVendorSpecific[3] = 0xA0; |
| padVendorSpecific[4] = 0xC6; |
| |
| lim_log(pMac, LOG1, FL("Padding Vendor Specific Ie Len = %d"), |
| padLen); |
| |
| /* padding zero if more than 5 bytes are required */ |
| if (padLen > MIN_VENDOR_SPECIFIC_IE_SIZE) |
| qdf_mem_set(pFrame + header_offset + nPayload + |
| addIeLen + MIN_VENDOR_SPECIFIC_IE_SIZE, |
| padLen - MIN_VENDOR_SPECIFIC_IE_SIZE, 0); |
| } |
| #endif |
| lim_log(pMac, LOG1, |
| FL("[TDLS] action %d (%s) -%s-> OTA peer="MAC_ADDRESS_STR), |
| SIR_MAC_TDLS_TEARDOWN, |
| lim_trace_tdls_action_string(SIR_MAC_TDLS_TEARDOWN), |
| ((reason == eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE) ? "AP" : |
| "DIRECT"), |
| MAC_ADDR_ARRAY(peer_mac.bytes)); |
| |
| pMac->lim.tdls_frm_session_id = psessionEntry->peSessionId; |
| |
| qdf_status = wma_tx_frame_with_tx_complete_send(pMac, pPacket, |
| (uint16_t) nBytes, |
| TID_AC_VI, |
| pFrame, |
| smeSessionId, |
| (reason == eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE) |
| ? true : false); |
| |
| if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { |
| pMac->lim.tdls_frm_session_id = NO_SESSION; |
| lim_log(pMac, LOGE, |
| FL("could not send TDLS Teardown frame")); |
| return eSIR_FAILURE; |
| |
| } |
| return eSIR_SUCCESS; |
| } |
| |
| /* |
| * Send Setup RSP frame on AP link. |
| */ |
| static tSirRetStatus lim_send_tdls_setup_rsp_frame(tpAniSirGlobal pMac, |
| struct qdf_mac_addr peer_mac, |
| uint8_t dialog, |
| tpPESession psessionEntry, |
| etdlsLinkSetupStatus setupStatus, |
| uint8_t *addIe, |
| uint16_t addIeLen) |
| { |
| tDot11fTDLSSetupRsp tdlsSetupRsp; |
| uint32_t status = 0; |
| uint16_t caps = 0; |
| uint32_t nPayload = 0; |
| uint32_t header_offset = 0; |
| uint32_t nBytes = 0; |
| uint8_t *pFrame; |
| void *pPacket; |
| QDF_STATUS qdf_status; |
| uint32_t selfDot11Mode; |
| /* Placeholder to support different channel bonding mode of TDLS than AP. */ |
| /* Today, WNI_CFG_CHANNEL_BONDING_MODE will be overwritten when connecting to AP */ |
| /* To support this feature, we need to introduce WNI_CFG_TDLS_CHANNEL_BONDING_MODE */ |
| /* As of now, we hardcoded to max channel bonding of dot11Mode (i.e HT80 for 11ac/HT40 for 11n) */ |
| /* uint32_t tdlsChannelBondingMode; */ |
| uint8_t smeSessionId = 0; |
| |
| if (NULL == psessionEntry) { |
| lim_log(pMac, LOGE, FL("psessionEntry is NULL")); |
| return eSIR_FAILURE; |
| } |
| smeSessionId = psessionEntry->smeSessionId; |
| |
| /* |
| * The scheme here is to fill out a 'tDot11fProbeRequest' structure |
| * and then hand it off to 'dot11f_pack_probe_request' (for |
| * serialization). We start by zero-initializing the structure: |
| */ |
| qdf_mem_set((uint8_t *) &tdlsSetupRsp, sizeof(tDot11fTDLSSetupRsp), 0); |
| |
| /* |
| * setup Fixed fields, |
| */ |
| tdlsSetupRsp.Category.category = SIR_MAC_ACTION_TDLS; |
| tdlsSetupRsp.Action.action = SIR_MAC_TDLS_SETUP_RSP; |
| tdlsSetupRsp.DialogToken.token = dialog; |
| |
| populate_dot11f_link_iden(pMac, psessionEntry, |
| &tdlsSetupRsp.LinkIdentifier, peer_mac, |
| TDLS_RESPONDER); |
| |
| if (cfg_get_capability_info(pMac, &caps, psessionEntry) != eSIR_SUCCESS) { |
| /* |
| * Could not get Capabilities value |
| * from CFG. Log error. |
| */ |
| lim_log(pMac, LOGE, |
| FL("could not retrieve Capabilities value")); |
| } |
| swap_bit_field16(caps, (uint16_t *) &tdlsSetupRsp.Capabilities); |
| |
| /* populate supported rate and ext supported rate IE */ |
| if (eSIR_FAILURE == populate_dot11f_rates_tdls(pMac, |
| &tdlsSetupRsp.SuppRates, |
| &tdlsSetupRsp.ExtSuppRates, |
| psessionEntry->currentOperChannel)) |
| lim_log(pMac, LOGE, |
| FL("could not populate supported data rates")); |
| |
| /* Populate extended capability IE */ |
| populate_dot11f_tdls_ext_capability(pMac, |
| psessionEntry, |
| &tdlsSetupRsp.ExtCap); |
| |
| if (1 == pMac->lim.gLimTDLSWmmMode) { |
| uint32_t val = 0; |
| |
| lim_log(pMac, LOG1, |
| FL("populate WMM IE in Setup Response frame")); |
| /* include WMM IE */ |
| tdlsSetupRsp.WMMInfoStation.version = SIR_MAC_OUI_VERSION_1; |
| tdlsSetupRsp.WMMInfoStation.acvo_uapsd = |
| (pMac->lim.gLimTDLSUapsdMask & 0x01); |
| tdlsSetupRsp.WMMInfoStation.acvi_uapsd = |
| ((pMac->lim.gLimTDLSUapsdMask & 0x02) >> 1); |
| tdlsSetupRsp.WMMInfoStation.acbk_uapsd = |
| ((pMac->lim.gLimTDLSUapsdMask & 0x04) >> 2); |
| tdlsSetupRsp.WMMInfoStation.acbe_uapsd = |
| ((pMac->lim.gLimTDLSUapsdMask & 0x08) >> 3); |
| if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_SP_LENGTH, &val) != |
| eSIR_SUCCESS) |
| lim_log(pMac, LOGE, |
| FL("could not retrieve Max SP Length")); |
| tdlsSetupRsp.WMMInfoStation.max_sp_length = (uint8_t) val; |
| tdlsSetupRsp.WMMInfoStation.present = 1; |
| } else { |
| /* |
| * TODO: we need to see if we have to support conditions where |
| * we have EDCA parameter info element is needed a) if we need |
| * different QOS parameters for off channel operations or QOS |
| * is not supported on AP link and we wanted to QOS on direct |
| * link. |
| */ |
| /* Populate QOS info, needed for Peer U-APSD session */ |
| /* |
| * TODO: Now hardcoded, because |
| * populate_dot11f_qos_caps_station() depends on AP's |
| * capability, and TDLS doesn't want to depend on AP's |
| * capability |
| */ |
| lim_log(pMac, LOG1, |
| FL("populate QOS IE in Setup Response frame")); |
| tdlsSetupRsp.QOSCapsStation.present = 1; |
| tdlsSetupRsp.QOSCapsStation.max_sp_length = 0; |
| tdlsSetupRsp.QOSCapsStation.qack = 0; |
| tdlsSetupRsp.QOSCapsStation.acbe_uapsd = |
| ((pMac->lim.gLimTDLSUapsdMask & 0x08) >> 3); |
| tdlsSetupRsp.QOSCapsStation.acbk_uapsd = |
| ((pMac->lim.gLimTDLSUapsdMask & 0x04) >> 2); |
| tdlsSetupRsp.QOSCapsStation.acvi_uapsd = |
| ((pMac->lim.gLimTDLSUapsdMask & 0x02) >> 1); |
| tdlsSetupRsp.QOSCapsStation.acvo_uapsd = |
| (pMac->lim.gLimTDLSUapsdMask & 0x01); |
| } |
| |
| wlan_cfg_get_int(pMac, WNI_CFG_DOT11_MODE, &selfDot11Mode); |
| |
| /* Populate HT/VHT Capabilities */ |
| populate_dot11f_tdls_ht_vht_cap(pMac, selfDot11Mode, &tdlsSetupRsp.HTCaps, |
| &tdlsSetupRsp.VHTCaps, psessionEntry); |
| |
| /* Populate AID */ |
| populate_dotf_tdls_vht_aid(pMac, selfDot11Mode, peer_mac, |
| &tdlsSetupRsp.AID, psessionEntry); |
| |
| /* Populate TDLS offchannel param only if offchannel is enabled |
| * and TDLS Channel Switching is not prohibited by AP in ExtCap |
| * IE in assoc/re-assoc response. |
| */ |
| if ((1 == pMac->lim.gLimTDLSOffChannelEnabled) && |
| (!psessionEntry->tdls_chan_swit_prohibited)) { |
| populate_dot11f_tdls_offchannel_params(pMac, psessionEntry, |
| &tdlsSetupRsp.SuppChannels, |
| &tdlsSetupRsp. |
| SuppOperatingClasses); |
| if (pMac->roam.configParam.bandCapability != eCSR_BAND_24) { |
| tdlsSetupRsp.ht2040_bss_coexistence.present = 1; |
| tdlsSetupRsp.ht2040_bss_coexistence.info_request = 1; |
| } |
| } else { |
| lim_log(pMac, LOG1, |
| FL("TDLS offchan not enabled, or channel switch prohibited by AP, gLimTDLSOffChannelEnabled (%d), tdls_chan_swit_prohibited (%d)"), |
| pMac->lim.gLimTDLSOffChannelEnabled, |
| psessionEntry->tdls_chan_swit_prohibited); |
| } |
| tdlsSetupRsp.Status.status = setupStatus; |
| /* |
| * now we pack it. First, how much space are we going to need? |
| */ |
| status = dot11f_get_packed_tdls_setup_rsp_size(pMac, &tdlsSetupRsp, |
| &nPayload); |
| if (DOT11F_FAILED(status)) { |
| lim_log(pMac, LOGE, |
| FL( |
| "Failed to calculate the packed size for a Setup Response (0x%08x)." |
| ), |
| status); |
| /* We'll fall back on the worst case scenario: */ |
| nPayload = sizeof(tDot11fProbeRequest); |
| } else if (DOT11F_WARNED(status)) { |
| lim_log(pMac, LOGW, |
| FL( |
| "There were warnings while calculating the packed size for Setup Response (0x%08x)." |
| ), |
| status); |
| } |
| |
| /* |
| * This frame is going out from PE as data frames with special ethertype |
| * 89-0d. |
| * 8 bytes of RFC 1042 header |
| */ |
| |
| nBytes = nPayload + ((IS_QOS_ENABLED(psessionEntry)) |
| ? sizeof(tSirMacDataHdr3a) : |
| sizeof(tSirMacMgmtHdr)) |
| + sizeof(eth_890d_header) |
| + PAYLOAD_TYPE_TDLS_SIZE + addIeLen; |
| |
| /* Ok-- try to allocate memory from MGMT PKT pool */ |
| qdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, |
| (void **)&pPacket); |
| if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { |
| lim_log(pMac, LOGE, |
| FL( |
| "Failed to allocate %d bytes for a TDLS Setup Response." |
| ), |
| nBytes); |
| return eSIR_MEM_ALLOC_FAILED; |
| } |
| |
| /* zero out the memory */ |
| qdf_mem_set(pFrame, nBytes, 0); |
| |
| /* |
| * IE formation, memory allocation is completed, Now form TDLS discovery |
| * request frame |
| */ |
| |
| /* fill out the buffer descriptor */ |
| |
| header_offset = lim_prepare_tdls_frame_header(pMac, pFrame, |
| LINK_IDEN_ADDR_OFFSET |
| (tdlsSetupRsp), TDLS_LINK_AP, |
| TDLS_RESPONDER, TID_AC_VI, |
| psessionEntry); |
| |
| lim_log(pMac, LOG1, |
| FL( |
| "SupportedChnlWidth %x rxMCSMap %x rxMCSMap %x txSupDataRate %x" |
| ), |
| tdlsSetupRsp.VHTCaps.supportedChannelWidthSet, |
| tdlsSetupRsp.VHTCaps.rxMCSMap, |
| tdlsSetupRsp.VHTCaps.txMCSMap, |
| tdlsSetupRsp.VHTCaps.txSupDataRate); |
| status = dot11f_pack_tdls_setup_rsp(pMac, &tdlsSetupRsp, |
| pFrame + header_offset, |
| nPayload, &nPayload); |
| |
| if (DOT11F_FAILED(status)) { |
| lim_log(pMac, LOGE, |
| FL("Failed to pack a TDLS Setup Response (0x%08x)."), |
| status); |
| cds_packet_free((void *)pPacket); |
| return eSIR_FAILURE; |
| } else if (DOT11F_WARNED(status)) { |
| lim_log(pMac, LOGW, |
| FL( |
| "There were warnings while packing TDLS Setup Response (0x%08x)." |
| ), |
| status); |
| } |
| /* Copy the additional IE. */ |
| /* TODO : addIe is added at the end of the frame. This means it doesnt */ |
| /* follow the order. This should be ok, but we should consider changing this */ |
| /* if there is any IOT issue. */ |
| if (addIeLen != 0) { |
| qdf_mem_copy(pFrame + header_offset + nPayload, addIe, |
| addIeLen); |
| } |
| |
| lim_log(pMac, LOG1, |
| FL("[TDLS] action %d (%s) -AP-> OTA peer="MAC_ADDRESS_STR), |
| SIR_MAC_TDLS_SETUP_RSP, |
| lim_trace_tdls_action_string(SIR_MAC_TDLS_SETUP_RSP), |
| MAC_ADDR_ARRAY(peer_mac.bytes)); |
| |
| pMac->lim.tdls_frm_session_id = psessionEntry->peSessionId; |
| |
| qdf_status = wma_tx_frame_with_tx_complete_send(pMac, pPacket, |
| (uint16_t) nBytes, |
| TID_AC_VI, |
| pFrame, |
| smeSessionId, true); |
| |
| if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { |
| pMac->lim.tdls_frm_session_id = NO_SESSION; |
| lim_log(pMac, LOGE, |
| FL("could not send TDLS Dis Request frame!")); |
| return eSIR_FAILURE; |
| } |
| |
| return eSIR_SUCCESS; |
| } |
| |
| /* |
| * Send TDLS setup CNF frame on AP link |
| */ |
| |
| tSirRetStatus lim_send_tdls_link_setup_cnf_frame(tpAniSirGlobal pMac, |
| struct qdf_mac_addr peer_mac, |
| uint8_t dialog, |
| uint32_t peerCapability, |
| tpPESession psessionEntry, |
| uint8_t *addIe, uint16_t addIeLen) |
| { |
| tDot11fTDLSSetupCnf tdlsSetupCnf; |
| uint32_t status = 0; |
| uint32_t nPayload = 0; |
| uint32_t nBytes = 0; |
| uint32_t header_offset = 0; |
| uint8_t *pFrame; |
| void *pPacket; |
| QDF_STATUS qdf_status; |
| #ifndef NO_PAD_TDLS_MIN_8023_SIZE |
| uint32_t padLen = 0; |
| #endif |
| uint8_t smeSessionId = 0; |
| |
| /* |
| * The scheme here is to fill out a 'tDot11fProbeRequest' structure |
| * and then hand it off to 'dot11f_pack_probe_request' (for |
| * serialization). We start by zero-initializing the structure: |
| */ |
| smeSessionId = psessionEntry->smeSessionId; |
| |
| qdf_mem_set((uint8_t *) &tdlsSetupCnf, sizeof(tDot11fTDLSSetupCnf), 0); |
| |
| /* |
| * setup Fixed fields, |
| */ |
| tdlsSetupCnf.Category.category = SIR_MAC_ACTION_TDLS; |
| tdlsSetupCnf.Action.action = SIR_MAC_TDLS_SETUP_CNF; |
| tdlsSetupCnf.DialogToken.token = dialog; |
| |
| populate_dot11f_link_iden(pMac, psessionEntry, |
| &tdlsSetupCnf.LinkIdentifier, peer_mac, |
| TDLS_INITIATOR); |
| /* |
| * TODO: we need to see if we have to support conditions where we have |
| * EDCA parameter info element is needed a) if we need different QOS |
| * parameters for off channel operations or QOS is not supported on |
| * AP link and we wanted to QOS on direct link. |
| */ |
| |
| /* Check self and peer WMM capable */ |
| if ((1 == pMac->lim.gLimTDLSWmmMode) && |
| (CHECK_BIT(peerCapability, TDLS_PEER_WMM_CAP))) { |
| lim_log(pMac, LOG1, FL("populate WMM praram in Setup Confirm")); |
| populate_dot11f_wmm_params(pMac, &tdlsSetupCnf.WMMParams, |
| psessionEntry); |
| } |
| |
| /* Check peer is VHT capable */ |
| if (CHECK_BIT(peerCapability, TDLS_PEER_VHT_CAP)) { |
| populate_dot11f_vht_operation(pMac, |
| psessionEntry, |
| &tdlsSetupCnf.VHTOperation); |
| populate_dot11f_ht_info(pMac, &tdlsSetupCnf.HTInfo, psessionEntry); |
| } else if (CHECK_BIT(peerCapability, TDLS_PEER_HT_CAP)) { /* Check peer is HT capable */ |
| populate_dot11f_ht_info(pMac, &tdlsSetupCnf.HTInfo, psessionEntry); |
| } |
| |
| /* |
| * now we pack it. First, how much space are we going to need? |
| */ |
| status = dot11f_get_packed_tdls_setup_cnf_size(pMac, &tdlsSetupCnf, |
| &nPayload); |
| if (DOT11F_FAILED(status)) { |
| lim_log(pMac, LOGE, |
| FL( |
| "Failed to calculate the packed size for a Setup Confirm (0x%08x)." |
| ), |
| status); |
| /* We'll fall back on the worst case scenario: */ |
| nPayload = sizeof(tDot11fProbeRequest); |
| } else if (DOT11F_WARNED(status)) { |
| lim_log(pMac, LOGW, |
| FL( |
| "There were warnings while calculating the packed size for Setup Confirm (0x%08x)." |
| ), |
| status); |
| } |
| |
| /* |
| * This frame is going out from PE as data frames with special ethertype |
| * 89-0d. |
| * 8 bytes of RFC 1042 header |
| */ |
| |
| nBytes = nPayload + ((IS_QOS_ENABLED(psessionEntry)) |
| ? sizeof(tSirMacDataHdr3a) : |
| sizeof(tSirMacMgmtHdr)) |
| + sizeof(eth_890d_header) |
| + PAYLOAD_TYPE_TDLS_SIZE + addIeLen; |
| |
| #ifndef NO_PAD_TDLS_MIN_8023_SIZE |
| /* IOT issue with some AP : some AP doesn't like the data packet size < minimum 802.3 frame length (64) |
| Hence AP itself padding some bytes, which caused teardown packet is dropped at |
| receiver side. To avoid such IOT issue, we added some extra bytes to meet data frame size >= 64 |
| */ |
| if (nPayload + PAYLOAD_TYPE_TDLS_SIZE < MIN_IEEE_8023_SIZE) { |
| padLen = |
| MIN_IEEE_8023_SIZE - (nPayload + PAYLOAD_TYPE_TDLS_SIZE); |
| |
| /* if padLen is less than minimum vendorSpecific (5), pad up to 5 */ |
| if (padLen < MIN_VENDOR_SPECIFIC_IE_SIZE) |
| padLen = MIN_VENDOR_SPECIFIC_IE_SIZE; |
| |
| nBytes += padLen; |
| } |
| #endif |
| |
| /* Ok-- try to allocate memory from MGMT PKT pool */ |
| qdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, |
| (void **)&pPacket); |
| if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { |
| lim_log(pMac, LOGE, |
| FL( |
| "Failed to allocate %d bytes for a TDLS Setup Confirm." |
| ), |
| nBytes); |
| return eSIR_MEM_ALLOC_FAILED; |
| } |
| |
| /* zero out the memory */ |
| qdf_mem_set(pFrame, nBytes, 0); |
| |
| /* |
| * IE formation, memory allocation is completed, Now form TDLS discovery |
| * request frame |
| */ |
| |
| /* fill out the buffer descriptor */ |
| |
| header_offset = lim_prepare_tdls_frame_header(pMac, pFrame, |
| LINK_IDEN_ADDR_OFFSET |
| (tdlsSetupCnf), TDLS_LINK_AP, |
| TDLS_INITIATOR, TID_AC_VI, |
| psessionEntry); |
| |
| status = dot11f_pack_tdls_setup_cnf(pMac, &tdlsSetupCnf, pFrame |
| + header_offset, nPayload, &nPayload); |
| |
| if (DOT11F_FAILED(status)) { |
| lim_log(pMac, LOGE, |
| FL("Failed to pack a TDLS discovery req (0x%08x)."), |
| status); |
| cds_packet_free((void *)pPacket); |
| return eSIR_FAILURE; |
| } else if (DOT11F_WARNED(status)) { |
| lim_log(pMac, LOGW, |
| FL( |
| "There were warnings while packing TDLS Discovery Request (0x%08x)." |
| ), |
| status); |
| } |
| /* Copy the additional IE. */ |
| /* TODO : addIe is added at the end of the frame. This means it doesnt */ |
| /* follow the order. This should be ok, but we should consider changing this */ |
| /* if there is any IOT issue. */ |
| if (addIeLen != 0) { |
| qdf_mem_copy(pFrame + header_offset + nPayload, addIe, |
| addIeLen); |
| } |
| #ifndef NO_PAD_TDLS_MIN_8023_SIZE |
| if (padLen != 0) { |
| /* QCOM VENDOR OUI = { 0x00, 0xA0, 0xC6, type = 0x0000 }; */ |
| uint8_t *padVendorSpecific = |
| pFrame + header_offset + nPayload + addIeLen; |
| /* make QCOM_VENDOR_OUI, and type = 0x0000, and all the payload to be zero */ |
| padVendorSpecific[0] = 221; |
| padVendorSpecific[1] = padLen - 2; |
| padVendorSpecific[2] = 0x00; |
| padVendorSpecific[3] = 0xA0; |
| padVendorSpecific[4] = 0xC6; |
| |
| lim_log(pMac, LOG1, FL("Padding Vendor Specific Ie Len = %d"), |
| padLen); |
| |
| /* padding zero if more than 5 bytes are required */ |
| if (padLen > MIN_VENDOR_SPECIFIC_IE_SIZE) |
| qdf_mem_set(pFrame + header_offset + nPayload + |
| addIeLen + MIN_VENDOR_SPECIFIC_IE_SIZE, |
| padLen - MIN_VENDOR_SPECIFIC_IE_SIZE, 0); |
| } |
| #endif |
| |
| lim_log(pMac, LOG1, |
| FL("[TDLS] action %d (%s) -AP-> OTA peer="MAC_ADDRESS_STR), |
| SIR_MAC_TDLS_SETUP_CNF, |
| lim_trace_tdls_action_string(SIR_MAC_TDLS_SETUP_CNF), |
| MAC_ADDR_ARRAY(peer_mac.bytes)); |
| |
| pMac->lim.tdls_frm_session_id = psessionEntry->peSessionId; |
| |
| qdf_status = wma_tx_frame_with_tx_complete_send(pMac, pPacket, |
| (uint16_t) nBytes, |
| TID_AC_VI, |
| pFrame, |
| smeSessionId, true); |
| |
| if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { |
| pMac->lim.tdls_frm_session_id = NO_SESSION; |
| lim_log(pMac, LOGE, |
| FL("could not send TDLS Setup Confirm frame")); |
| return eSIR_FAILURE; |
| |
| } |
| |
| return eSIR_SUCCESS; |
| } |
| |
| /* This Function is similar to populate_dot11f_ht_caps, except that the HT Capabilities |
| * are considered from the AddStaReq rather from the cfg.dat as in populate_dot11f_ht_caps |
| */ |
| static tSirRetStatus lim_tdls_populate_dot11f_ht_caps(tpAniSirGlobal pMac, |
| tpPESession psessionEntry, |
| tSirTdlsAddStaReq * |
| pTdlsAddStaReq, |
| tDot11fIEHTCaps *pDot11f) |
| { |
| uint32_t nCfgValue; |
| uint8_t nCfgValue8; |
| tSirMacHTParametersInfo *pHTParametersInfo; |
| union { |
| uint16_t nCfgValue16; |
| tSirMacHTCapabilityInfo htCapInfo; |
| tSirMacExtendedHTCapabilityInfo extHtCapInfo; |
| } uHTCapabilityInfo; |
| |
| tSirMacTxBFCapabilityInfo *pTxBFCapabilityInfo; |
| tSirMacASCapabilityInfo *pASCapabilityInfo; |
| |
| nCfgValue = pTdlsAddStaReq->htCap.capInfo; |
| |
| uHTCapabilityInfo.nCfgValue16 = nCfgValue & 0xFFFF; |
| |
| pDot11f->advCodingCap = uHTCapabilityInfo.htCapInfo.advCodingCap; |
| pDot11f->mimoPowerSave = uHTCapabilityInfo.htCapInfo.mimoPowerSave; |
| pDot11f->greenField = uHTCapabilityInfo.htCapInfo.greenField; |
| pDot11f->shortGI20MHz = uHTCapabilityInfo.htCapInfo.shortGI20MHz; |
| pDot11f->shortGI40MHz = uHTCapabilityInfo.htCapInfo.shortGI40MHz; |
| pDot11f->txSTBC = uHTCapabilityInfo.htCapInfo.txSTBC; |
| pDot11f->rxSTBC = uHTCapabilityInfo.htCapInfo.rxSTBC; |
| pDot11f->delayedBA = uHTCapabilityInfo.htCapInfo.delayedBA; |
| pDot11f->maximalAMSDUsize = |
| uHTCapabilityInfo.htCapInfo.maximalAMSDUsize; |
| pDot11f->dsssCckMode40MHz = |
| uHTCapabilityInfo.htCapInfo.dsssCckMode40MHz; |
| pDot11f->psmp = uHTCapabilityInfo.htCapInfo.psmp; |
| pDot11f->stbcControlFrame = |
| uHTCapabilityInfo.htCapInfo.stbcControlFrame; |
| pDot11f->lsigTXOPProtection = |
| uHTCapabilityInfo.htCapInfo.lsigTXOPProtection; |
| |
| /* |
| * All sessionized entries will need the check below |
| * Only in case of NO session |
| */ |
| if (psessionEntry == NULL) { |
| pDot11f->supportedChannelWidthSet = |
| uHTCapabilityInfo.htCapInfo.supportedChannelWidthSet; |
| } else { |
| pDot11f->supportedChannelWidthSet = |
| psessionEntry->htSupportedChannelWidthSet; |
| } |
| |
| /* Ensure that shortGI40MHz is Disabled if supportedChannelWidthSet is |
| eHT_CHANNEL_WIDTH_20MHZ */ |
| if (pDot11f->supportedChannelWidthSet == eHT_CHANNEL_WIDTH_20MHZ) { |
| pDot11f->shortGI40MHz = 0; |
| } |
| |
| lim_log(pMac, LOG1, |
| FL( |
| "SupportedChnlWidth: %d, mimoPS: %d, GF: %d, shortGI20:%d, shortGI40: %d, dsssCck: %d" |
| ), |
| pDot11f->supportedChannelWidthSet, |
| pDot11f->mimoPowerSave, |
| pDot11f->greenField, |
| pDot11f->shortGI20MHz, |
| pDot11f->shortGI40MHz, |
| pDot11f->dsssCckMode40MHz); |
| |
| nCfgValue = pTdlsAddStaReq->htCap.ampduParamsInfo; |
| |
| nCfgValue8 = (uint8_t) nCfgValue; |
| pHTParametersInfo = (tSirMacHTParametersInfo *) &nCfgValue8; |
| |
| pDot11f->maxRxAMPDUFactor = pHTParametersInfo->maxRxAMPDUFactor; |
| pDot11f->mpduDensity = pHTParametersInfo->mpduDensity; |
| pDot11f->reserved1 = pHTParametersInfo->reserved; |
| |
| lim_log(pMac, LOG1, FL("AMPDU Param: %x"), nCfgValue); |
| |
| qdf_mem_copy(pDot11f->supportedMCSSet, pTdlsAddStaReq->htCap.suppMcsSet, |
| SIZE_OF_SUPPORTED_MCS_SET); |
| |
| nCfgValue = pTdlsAddStaReq->htCap.extendedHtCapInfo; |
| |
| uHTCapabilityInfo.nCfgValue16 = nCfgValue & 0xFFFF; |
| |
| pDot11f->pco = uHTCapabilityInfo.extHtCapInfo.pco; |
| pDot11f->transitionTime = uHTCapabilityInfo.extHtCapInfo.transitionTime; |
| pDot11f->mcsFeedback = uHTCapabilityInfo.extHtCapInfo.mcsFeedback; |
| |
| nCfgValue = pTdlsAddStaReq->htCap.txBFCapInfo; |
| |
| pTxBFCapabilityInfo = (tSirMacTxBFCapabilityInfo *) &nCfgValue; |
| pDot11f->txBF = pTxBFCapabilityInfo->txBF; |
| pDot11f->rxStaggeredSounding = pTxBFCapabilityInfo->rxStaggeredSounding; |
| pDot11f->txStaggeredSounding = pTxBFCapabilityInfo->txStaggeredSounding; |
| pDot11f->rxZLF = pTxBFCapabilityInfo->rxZLF; |
| pDot11f->txZLF = pTxBFCapabilityInfo->txZLF; |
| pDot11f->implicitTxBF = pTxBFCapabilityInfo->implicitTxBF; |
| pDot11f->calibration = pTxBFCapabilityInfo->calibration; |
| pDot11f->explicitCSITxBF = pTxBFCapabilityInfo->explicitCSITxBF; |
| pDot11f->explicitUncompressedSteeringMatrix = |
| pTxBFCapabilityInfo->explicitUncompressedSteeringMatrix; |
| pDot11f->explicitBFCSIFeedback = |
| pTxBFCapabilityInfo->explicitBFCSIFeedback; |
| pDot11f->explicitUncompressedSteeringMatrixFeedback = |
| pTxBFCapabilityInfo->explicitUncompressedSteeringMatrixFeedback; |
| pDot11f->explicitCompressedSteeringMatrixFeedback = |
| pTxBFCapabilityInfo->explicitCompressedSteeringMatrixFeedback; |
| pDot11f->csiNumBFAntennae = pTxBFCapabilityInfo->csiNumBFAntennae; |
| pDot11f->uncompressedSteeringMatrixBFAntennae = |
| pTxBFCapabilityInfo->uncompressedSteeringMatrixBFAntennae; |
| pDot11f->compressedSteeringMatrixBFAntennae = |
| pTxBFCapabilityInfo->compressedSteeringMatrixBFAntennae; |
| |
| nCfgValue = pTdlsAddStaReq->htCap.antennaSelectionInfo; |
| |
| nCfgValue8 = (uint8_t) nCfgValue; |
| |
| pASCapabilityInfo = (tSirMacASCapabilityInfo *) &nCfgValue8; |
| pDot11f->antennaSelection = pASCapabilityInfo->antennaSelection; |
| pDot11f->explicitCSIFeedbackTx = |
| pASCapabilityInfo->explicitCSIFeedbackTx; |
| pDot11f->antennaIndicesFeedbackTx = |
| pASCapabilityInfo->antennaIndicesFeedbackTx; |
| pDot11f->explicitCSIFeedback = pASCapabilityInfo->explicitCSIFeedback; |
| pDot11f->antennaIndicesFeedback = |
| pASCapabilityInfo->antennaIndicesFeedback; |
| pDot11f->rxAS = pASCapabilityInfo->rxAS; |
| pDot11f->txSoundingPPDUs = pASCapabilityInfo->txSoundingPPDUs; |
| |
| pDot11f->present = pTdlsAddStaReq->htcap_present; |
| |
| return eSIR_SUCCESS; |
| |
| } |
| |
| tSirRetStatus |
| lim_tdls_populate_dot11f_vht_caps(tpAniSirGlobal pMac, |
| tSirTdlsAddStaReq *pTdlsAddStaReq, |
| tDot11fIEVHTCaps *pDot11f) |
| { |
| uint32_t nCfgValue = 0; |
| union { |
| uint32_t nCfgValue32; |
| tSirMacVHTCapabilityInfo vhtCapInfo; |
| } uVHTCapabilityInfo; |
| union { |
| uint16_t nCfgValue16; |
| tSirMacVHTTxSupDataRateInfo vhtTxSupDataRateInfo; |
| tSirMacVHTRxSupDataRateInfo vhtRxsupDataRateInfo; |
| } uVHTSupDataRateInfo; |
| |
| pDot11f->present = pTdlsAddStaReq->vhtcap_present; |
| |
| nCfgValue = pTdlsAddStaReq->vhtCap.vhtCapInfo; |
| uVHTCapabilityInfo.nCfgValue32 = nCfgValue; |
| |
| pDot11f->maxMPDULen = uVHTCapabilityInfo.vhtCapInfo.maxMPDULen; |
| pDot11f->supportedChannelWidthSet = |
| uVHTCapabilityInfo.vhtCapInfo.supportedChannelWidthSet; |
| pDot11f->ldpcCodingCap = uVHTCapabilityInfo.vhtCapInfo.ldpcCodingCap; |
| pDot11f->shortGI80MHz = uVHTCapabilityInfo.vhtCapInfo.shortGI80MHz; |
| pDot11f->shortGI160and80plus80MHz = |
| uVHTCapabilityInfo.vhtCapInfo.shortGI160and80plus80MHz; |
| pDot11f->txSTBC = uVHTCapabilityInfo.vhtCapInfo.txSTBC; |
| pDot11f->rxSTBC = uVHTCapabilityInfo.vhtCapInfo.rxSTBC; |
| pDot11f->suBeamFormerCap = 0; |
| pDot11f->suBeamformeeCap = 0; |
| pDot11f->csnofBeamformerAntSup = |
| uVHTCapabilityInfo.vhtCapInfo.csnofBeamformerAntSup; |
| pDot11f->numSoundingDim = uVHTCapabilityInfo.vhtCapInfo.numSoundingDim; |
| pDot11f->muBeamformerCap = 0; |
| pDot11f->muBeamformeeCap = 0; |
| pDot11f->vhtTXOPPS = uVHTCapabilityInfo.vhtCapInfo.vhtTXOPPS; |
| pDot11f->htcVHTCap = uVHTCapabilityInfo.vhtCapInfo.htcVHTCap; |
| pDot11f->maxAMPDULenExp = uVHTCapabilityInfo.vhtCapInfo.maxAMPDULenExp; |
| pDot11f->vhtLinkAdaptCap = |
| uVHTCapabilityInfo.vhtCapInfo.vhtLinkAdaptCap; |
| pDot11f->rxAntPattern = uVHTCapabilityInfo.vhtCapInfo.rxAntPattern; |
| pDot11f->txAntPattern = uVHTCapabilityInfo.vhtCapInfo.txAntPattern; |
| pDot11f->reserved1 = uVHTCapabilityInfo.vhtCapInfo.reserved1; |
| |
| pDot11f->rxMCSMap = pTdlsAddStaReq->vhtCap.suppMcs.rxMcsMap; |
| |
| nCfgValue = pTdlsAddStaReq->vhtCap.suppMcs.rxHighest; |
| uVHTSupDataRateInfo.nCfgValue16 = nCfgValue & 0xffff; |
| pDot11f->rxHighSupDataRate = |
| uVHTSupDataRateInfo.vhtRxsupDataRateInfo.rxSupDataRate; |
| |
| pDot11f->txMCSMap = pTdlsAddStaReq->vhtCap.suppMcs.txMcsMap; |
| |
| nCfgValue = pTdlsAddStaReq->vhtCap.suppMcs.txHighest; |
| uVHTSupDataRateInfo.nCfgValue16 = nCfgValue & 0xffff; |
| pDot11f->txSupDataRate = |
| uVHTSupDataRateInfo.vhtTxSupDataRateInfo.txSupDataRate; |
| |
| pDot11f->reserved3 = uVHTSupDataRateInfo.vhtTxSupDataRateInfo.reserved; |
| |
| lim_log_vht_cap(pMac, pDot11f); |
| |
| return eSIR_SUCCESS; |
| |
| } |
| |
| /** |
| * lim_tdls_populate_matching_rate_set() - populate matching rate set |
| * |
| * @mac_ctx - global MAC context |
| * @stads - station hash entry |
| * @supp_rate_set - pointer to supported rate set |
| * @supp_rates_len - length of the supported rates |
| * @supp_mcs_set - pointer to supported MSC set |
| * @session_entry - pointer to PE session entry |
| * @vht_caps - pointer to VHT capability |
| * |
| * |
| * This function gets set of available rates from the config and compare them |
| * against the set of received supported rates. After the comparison station |
| * entry's rates is populated with 11A rates and 11B rates. |
| * |
| * Return: eSIR_SUCCESS on success, eSIR_FAILURE on failure. |
| */ |
| static tSirRetStatus |
| lim_tdls_populate_matching_rate_set(tpAniSirGlobal mac_ctx, tpDphHashNode stads, |
| uint8_t *supp_rate_set, |
| uint8_t supp_rates_len, |
| uint8_t *supp_mcs_set, |
| tpPESession session_entry, |
| tDot11fIEVHTCaps *vht_caps) |
| { |
| tSirMacRateSet temp_rate_set; |
| uint32_t i, j, val, min, is_a_rate; |
| tSirMacRateSet temp_rate_set2; |
| uint32_t phymode; |
| uint8_t mcsSet[SIZE_OF_SUPPORTED_MCS_SET]; |
| tpSirSupportedRates rates; |
| uint8_t a_rateindex = 0; |
| uint8_t b_rateindex = 0; |
| uint8_t nss; |
| is_a_rate = 0; |
| temp_rate_set2.numRates = 0; |
| |
| lim_get_phy_mode(mac_ctx, &phymode, NULL); |
| |
| /* get own rate set */ |
| val = WNI_CFG_OPERATIONAL_RATE_SET_LEN; |
| if (wlan_cfg_get_str(mac_ctx, WNI_CFG_OPERATIONAL_RATE_SET, |
| (uint8_t *) &temp_rate_set.rate, |
| &val) != eSIR_SUCCESS) { |
| /* Could not get rateset from CFG. Log error. */ |
| lim_log(mac_ctx, LOGE, FL("could not retrieve rateset")); |
| val = 0; |
| } |
| temp_rate_set.numRates = val; |
| |
| if (phymode == WNI_CFG_PHY_MODE_11G) { |
| /* get own extended rate set */ |
| val = WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET_LEN; |
| if (wlan_cfg_get_str(mac_ctx, |
| WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, |
| (uint8_t *) &temp_rate_set2.rate, |
| &val) != eSIR_SUCCESS) |
| temp_rate_set2.numRates = val; |
| } |
| |
| if ((temp_rate_set.numRates + temp_rate_set2.numRates) > 12) { |
| lim_log(mac_ctx, LOGE, FL("more than 12 rates in CFG")); |
| return eSIR_FAILURE; |
| } |
| |
| /** |
| * Handling of the rate set IEs is the following: |
| * - keep only rates that we support and that the station supports |
| * - sort and the rates into the pSta->rate array |
| */ |
| |
| /* Copy all rates in temp_rate_set, there are 12 rates max */ |
| for (i = 0; i < temp_rate_set2.numRates; i++) |
| temp_rate_set.rate[i + temp_rate_set.numRates] = |
| temp_rate_set2.rate[i]; |
| |
| temp_rate_set.numRates += temp_rate_set2.numRates; |
| |
| /** |
| * Sort rates in temp_rate_set (they are likely to be already sorted) |
| * put the result in temp_rate_set2 |
| */ |
| temp_rate_set2.numRates = 0; |
| |
| for (i = 0; i < temp_rate_set.numRates; i++) { |
| min = 0; |
| val = 0xff; |
| |
| for (j = 0; j < temp_rate_set.numRates; j++) |
| if ((uint32_t) (temp_rate_set.rate[j] & 0x7f) < val) { |
| val = temp_rate_set.rate[j] & 0x7f; |
| min = j; |
| } |
| |
| temp_rate_set2.rate[temp_rate_set2.numRates++] = |
| temp_rate_set.rate[min]; |
| temp_rate_set.rate[min] = 0xff; |
| } |
| |
| /** |
| * Copy received rates in temp_rate_set, the parser has ensured |
| * unicity of the rates so there cannot be more than 12 . |
| */ |
| if (supp_rates_len > SIR_MAC_RATESET_EID_MAX) { |
| lim_log(mac_ctx, LOGW, |
| FL( |
| "Supported rates length %d more than the Max limit, reset to Max" |
| ), |
| supp_rates_len); |
| supp_rates_len = SIR_MAC_RATESET_EID_MAX; |
| } |
| |
| for (i = 0; i < supp_rates_len; i++) |
| temp_rate_set.rate[i] = supp_rate_set[i]; |
| |
| temp_rate_set.numRates = supp_rates_len; |
| |
| rates = &stads->supportedRates; |
| qdf_mem_set((uint8_t *) rates, sizeof(tSirSupportedRates), 0); |
| |
| for (i = 0; i < temp_rate_set2.numRates; i++) { |
| for (j = 0; j < temp_rate_set.numRates; j++) { |
| if ((temp_rate_set2.rate[i] & 0x7F) != |
| (temp_rate_set.rate[j] & 0x7F)) |
| continue; |
| |
| if ((b_rateindex > SIR_NUM_11B_RATES) || |
| (a_rateindex > SIR_NUM_11A_RATES)) { |
| lim_log(mac_ctx, LOGE, |
| FL("Invalid number of rates (11b->%d, 11a->%d)"), |
| b_rateindex, a_rateindex); |
| return eSIR_FAILURE; |
| } |
| if (sirIsArate(temp_rate_set2.rate[i] & 0x7f)) { |
| is_a_rate = 1; |
| if (a_rateindex < SIR_NUM_11A_RATES) |
| rates->llaRates[a_rateindex++] = temp_rate_set2.rate[i]; |
| } else { |
| if (b_rateindex < SIR_NUM_11B_RATES) |
| rates->llbRates[b_rateindex++] = temp_rate_set2.rate[i]; |
| } |
| break; |
| } |
| } |
| |
| if (IS_5G_CH(session_entry->currentOperChannel)) |
| nss = mac_ctx->vdev_type_nss_5g.tdls; |
| else |
| nss = mac_ctx->vdev_type_nss_2g.tdls; |
| |
| nss = QDF_MIN(nss, mac_ctx->user_configured_nss); |
| |
| /* compute the matching MCS rate set, if peer is 11n capable and self mode is 11n */ |
| #ifdef FEATURE_WLAN_TDLS |
| if (stads->mlmStaContext.htCapability) |
| #else |
| if (IS_DOT11_MODE_HT(session_entry->dot11mode) && |
| (stads->mlmStaContext.htCapability)) |
| #endif |
| { |
| val = SIZE_OF_SUPPORTED_MCS_SET; |
| if (wlan_cfg_get_str(mac_ctx, WNI_CFG_SUPPORTED_MCS_SET, |
| mcsSet, &val) != eSIR_SUCCESS) { |
| /* Could not get rateset from CFG. Log error. */ |
| lim_log(mac_ctx, LOGP, |
| FL("could not retrieve supportedMCSSet")); |
| return eSIR_FAILURE; |
| } |
| |
| if (NSS_1x1_MODE == nss) |
| mcsSet[1] = 0; |
| for (i = 0; i < val; i++) |
| stads->supportedRates.supportedMCSSet[i] = |
| mcsSet[i] & supp_mcs_set[i]; |
| |
| lim_log(mac_ctx, LOG1, |
| FL("MCS Rate Set Bitmap from CFG and DPH")); |
| for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) { |
| lim_log(mac_ctx, LOG1, FL("%x %x"), mcsSet[i], |
| stads->supportedRates.supportedMCSSet[i]); |
| } |
| } |
| lim_populate_vht_mcs_set(mac_ctx, &stads->supportedRates, vht_caps, |
| session_entry, nss); |
| /** |
| * Set the erpEnabled bit if the phy is in G mode and at least |
| * one A rate is supported |
| */ |
| if ((phymode == WNI_CFG_PHY_MODE_11G) && is_a_rate) |
| stads->erpEnabled = eHAL_SET; |
| |
| return eSIR_SUCCESS; |
| } |
| |
| /* |
| * update HASH node entry info |
| */ |
| static void lim_tdls_update_hash_node_info(tpAniSirGlobal pMac, |
| tDphHashNode *pStaDs, |
| tSirTdlsAddStaReq *pTdlsAddStaReq, |
| tpPESession psessionEntry) |
| { |
| tDot11fIEHTCaps htCap = {0,}; |
| tDot11fIEHTCaps *htCaps; |
| tDot11fIEVHTCaps *pVhtCaps = NULL; |
| tDot11fIEVHTCaps *pVhtCaps_txbf = NULL; |
| tDot11fIEVHTCaps vhtCap; |
| uint8_t cbMode; |
| tpDphHashNode pSessStaDs = NULL; |
| uint16_t aid; |
| |
| if (pTdlsAddStaReq->tdlsAddOper == TDLS_OPER_ADD) { |
| populate_dot11f_ht_caps(pMac, psessionEntry, &htCap); |
| } else if (pTdlsAddStaReq->tdlsAddOper == TDLS_OPER_UPDATE) { |
| lim_tdls_populate_dot11f_ht_caps(pMac, NULL, pTdlsAddStaReq, &htCap); |
| } |
| htCaps = &htCap; |
| if (htCaps->present) { |
| pStaDs->mlmStaContext.htCapability = 1; |
| pStaDs->htGreenfield = htCaps->greenField; |
| /* |
| * pStaDs->htSupportedChannelWidthSet should have the base |
| * channel capability. The htSupportedChannelWidthSet of the |
| * TDLS link on base channel should be less than or equal to |
| * channel width of STA-AP link. So take this setting from the |
| * psessionEntry. |
| */ |
| lim_log(pMac, LOG1, |
| FL("supportedChannelWidthSet 0x%x htSupportedChannelWidthSet 0x%x"), |
| htCaps->supportedChannelWidthSet, |
| psessionEntry->htSupportedChannelWidthSet); |
| pStaDs->htSupportedChannelWidthSet = |
| (htCaps->supportedChannelWidthSet < |
| psessionEntry->htSupportedChannelWidthSet) ? |
| htCaps->supportedChannelWidthSet : |
| psessionEntry->htSupportedChannelWidthSet; |
| lim_log(pMac, LOG1, FL("pStaDs->htSupportedChannelWidthSet 0x%x"), |
| pStaDs->htSupportedChannelWidthSet); |
| |
| pStaDs->htMIMOPSState = htCaps->mimoPowerSave; |
| pStaDs->htMaxAmsduLength = htCaps->maximalAMSDUsize; |
| pStaDs->htAMpduDensity = htCaps->mpduDensity; |
| pStaDs->htDsssCckRate40MHzSupport = htCaps->dsssCckMode40MHz; |
| pStaDs->htShortGI20Mhz = htCaps->shortGI20MHz; |
| pStaDs->htShortGI40Mhz = htCaps->shortGI40MHz; |
| pStaDs->htMaxRxAMpduFactor = htCaps->maxRxAMPDUFactor; |
| lim_fill_rx_highest_supported_rate(pMac, |
| &pStaDs->supportedRates. |
| rxHighestDataRate, |
| htCaps->supportedMCSSet); |
| pStaDs->baPolicyFlag = 0xFF; |
| pMac->lim.gLimTdlsLinkMode = TDLS_LINK_MODE_N; |
| pStaDs->ht_caps = pTdlsAddStaReq->htCap.capInfo; |
| } else { |
| pStaDs->mlmStaContext.htCapability = 0; |
| pMac->lim.gLimTdlsLinkMode = TDLS_LINK_MODE_BG; |
| } |
| lim_tdls_populate_dot11f_vht_caps(pMac, pTdlsAddStaReq, &vhtCap); |
| pVhtCaps = &vhtCap; |
| if (pVhtCaps->present) { |
| pStaDs->mlmStaContext.vhtCapability = 1; |
| |
| /* |
| * 11.21.1 General: The channel width of the TDLS direct |
| * link on the base channel shall not exceed the channel |
| * width of the BSS to which the TDLS peer STAs are |
| * associated. |
| */ |
| if (psessionEntry->ch_width) |
| pStaDs->vhtSupportedChannelWidthSet = |
| psessionEntry->ch_width - 1; |
| else |
| pStaDs->vhtSupportedChannelWidthSet = |
| psessionEntry->ch_width; |
| |
| lim_log(pMac, LOG1, FL("vhtSupportedChannelWidthSet = %hu, htSupportedChannelWidthSet %hu"), |
| pStaDs->vhtSupportedChannelWidthSet, |
| pStaDs->htSupportedChannelWidthSet); |
| |
| pStaDs->vhtLdpcCapable = pVhtCaps->ldpcCodingCap; |
| pStaDs->vhtBeamFormerCapable = 0; |
| pMac->lim.gLimTdlsLinkMode = TDLS_LINK_MODE_AC; |
| pVhtCaps_txbf = (tDot11fIEVHTCaps *) (&pTdlsAddStaReq->vhtCap); |
| pVhtCaps_txbf->suBeamformeeCap = 0; |
| pVhtCaps_txbf->suBeamFormerCap = 0; |
| pVhtCaps_txbf->muBeamformerCap = 0; |
| pVhtCaps_txbf->muBeamformeeCap = 0; |
| pStaDs->vht_caps = pTdlsAddStaReq->vhtCap.vhtCapInfo; |
| } else { |
| pStaDs->mlmStaContext.vhtCapability = 0; |
| pStaDs->vhtSupportedChannelWidthSet = |
| WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; |
| } |
| /*Calculate the Secondary Coannel Offset */ |
| cbMode = lim_select_cb_mode(pStaDs, psessionEntry, |
| psessionEntry->currentOperChannel, |
| pStaDs->vhtSupportedChannelWidthSet); |
| |
| pStaDs->htSecondaryChannelOffset = cbMode; |
| |
| if (pStaDs->mlmStaContext.vhtCapability) { |
| pStaDs->htSecondaryChannelOffset = lim_get_htcb_state(cbMode); |
| } |
| pSessStaDs = dph_lookup_hash_entry(pMac, psessionEntry->bssId, &aid, |
| &psessionEntry->dph.dphHashTable); |
| /* Lets enable QOS parameter */ |
| pStaDs->qosMode = 1; |
| pStaDs->wmeEnabled = 1; |
| pStaDs->lleEnabled = 0; |
| /* TDLS Dummy AddSTA does not have qosInfo , is it OK ?? |
| */ |
| pStaDs->qos.capability.qosInfo = |
| (*(tSirMacQosInfoStation *) &pTdlsAddStaReq->uapsd_queues); |
| |
| /* populate matching rate set */ |
| |
| /* TDLS Dummy AddSTA does not have HTCap,VHTCap,Rates info , is it OK ?? |
| */ |
| lim_tdls_populate_matching_rate_set(pMac, pStaDs, |
| pTdlsAddStaReq->supported_rates, |
| pTdlsAddStaReq->supported_rates_length, |
| (uint8_t *) pTdlsAddStaReq->htCap. |
| suppMcsSet, psessionEntry, pVhtCaps); |
| |
| /* TDLS Dummy AddSTA does not have right capability , is it OK ?? |
| */ |
| pStaDs->mlmStaContext.capabilityInfo = |
| (*(tSirMacCapabilityInfo *) &pTdlsAddStaReq->capability); |
| |
| return; |
| } |
| |
| /* |
| * Add STA for TDLS setup procedure |
| */ |
| static tSirRetStatus lim_tdls_setup_add_sta(tpAniSirGlobal pMac, |
| tSirTdlsAddStaReq *pAddStaReq, |
| tpPESession psessionEntry) |
| { |
| tpDphHashNode pStaDs = NULL; |
| tSirRetStatus status = eSIR_SUCCESS; |
| uint16_t aid = 0; |
| |
| pStaDs = dph_lookup_hash_entry(pMac, pAddStaReq->peermac.bytes, &aid, |
| &psessionEntry->dph.dphHashTable); |
| if (NULL == pStaDs) { |
| aid = lim_assign_peer_idx(pMac, psessionEntry); |
| |
| if (!aid) { |
| lim_log(pMac, LOGE, |
| FL("No more free AID for peer " |
| MAC_ADDRESS_STR), |
| MAC_ADDR_ARRAY(pAddStaReq->peermac.bytes)); |
| return eSIR_FAILURE; |
| } |
| |
| /* Set the aid in peerAIDBitmap as it has been assigned to TDLS peer */ |
| SET_PEER_AID_BITMAP(psessionEntry->peerAIDBitmap, aid); |
| |
| lim_log(pMac, LOG1, FL("Aid = %d, for peer =" MAC_ADDRESS_STR), |
| aid, MAC_ADDR_ARRAY(pAddStaReq->peermac.bytes)); |
| pStaDs = |
| dph_get_hash_entry(pMac, aid, |
| &psessionEntry->dph.dphHashTable); |
| |
| if (pStaDs) { |
| (void)lim_del_sta(pMac, pStaDs, false /*asynchronous */, |
| psessionEntry); |
| lim_delete_dph_hash_entry(pMac, pStaDs->staAddr, aid, |
| psessionEntry); |
| } |
| |
| pStaDs = dph_add_hash_entry(pMac, pAddStaReq->peermac.bytes, |
| aid, &psessionEntry->dph.dphHashTable); |
| |
| if (NULL == pStaDs) { |
| lim_log(pMac, LOGE, FL("add hash entry failed")); |
| QDF_ASSERT(0); |
| return eSIR_FAILURE; |
| } |
| } |
| |
| lim_tdls_update_hash_node_info(pMac, pStaDs, pAddStaReq, psessionEntry); |
| |
| pStaDs->staType = STA_ENTRY_TDLS_PEER; |
| |
| status = |
| lim_add_sta(pMac, pStaDs, |
| (pAddStaReq->tdlsAddOper == |
| TDLS_OPER_UPDATE) ? true : false, psessionEntry); |
| |
| if (eSIR_SUCCESS != status) { |
| /* should not fail */ |
| QDF_ASSERT(0); |
| } |
| return status; |
| } |
| |
| /* |
| * Del STA, after Link is teardown or discovery response sent on direct link |
| */ |
| static tpDphHashNode lim_tdls_del_sta(tpAniSirGlobal pMac, |
| struct qdf_mac_addr peerMac, |
| tpPESession psessionEntry) |
| { |
| tSirRetStatus status = eSIR_SUCCESS; |
| uint16_t peerIdx = 0; |
| tpDphHashNode pStaDs = NULL; |
| |
| pStaDs = dph_lookup_hash_entry(pMac, peerMac.bytes, &peerIdx, |
| &psessionEntry->dph.dphHashTable); |
| |
| if (pStaDs) { |
| |
| lim_log(pMac, LOG1, FL("DEL STA peer MAC: "MAC_ADDRESS_STR), |
| MAC_ADDR_ARRAY(pStaDs->staAddr)); |
| |
| lim_log(pMac, LOG1, FL("STA type = %x, sta idx = %x"), |
| pStaDs->staType, |
| pStaDs->staIndex); |
| |
| status = lim_del_sta(pMac, pStaDs, false, psessionEntry); |
| } |
| |
| return pStaDs; |
| } |
| |
| /* |
| * Once Link is setup with PEER, send Add STA ind to SME |
| */ |
| static QDF_STATUS lim_send_sme_tdls_add_sta_rsp(tpAniSirGlobal pMac, |
| uint8_t sessionId, |
| tSirMacAddr peerMac, |
| uint8_t updateSta, |
| tDphHashNode *pStaDs, uint8_t status) |
| { |
| tSirMsgQ mmhMsg = { 0 }; |
| tSirTdlsAddStaRsp *addStaRsp = NULL; |
| mmhMsg.type = eWNI_SME_TDLS_ADD_STA_RSP; |
| |
| addStaRsp = qdf_mem_malloc(sizeof(tSirTdlsAddStaRsp)); |
| if (NULL == addStaRsp) { |
| lim_log(pMac, LOGE, FL("Failed to allocate memory")); |
| return QDF_STATUS_E_NOMEM; |
| } |
| |
| addStaRsp->sessionId = sessionId; |
| addStaRsp->statusCode = status; |
| if (pStaDs) { |
| addStaRsp->staId = pStaDs->staIndex; |
| addStaRsp->ucastSig = pStaDs->ucUcastSig; |
| addStaRsp->bcastSig = pStaDs->ucBcastSig; |
| } |
| if (peerMac) { |
| qdf_mem_copy(addStaRsp->peermac.bytes, |
| (uint8_t *) peerMac, QDF_MAC_ADDR_SIZE); |
| } |
| if (updateSta) |
| addStaRsp->tdlsAddOper = TDLS_OPER_UPDATE; |
| else |
| addStaRsp->tdlsAddOper = TDLS_OPER_ADD; |
| |
| addStaRsp->length = sizeof(tSirTdlsAddStaRsp); |
| addStaRsp->messageType = eWNI_SME_TDLS_ADD_STA_RSP; |
| |
| mmhMsg.bodyptr = addStaRsp; |
| mmhMsg.bodyval = 0; |
| lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); |
| |
| return QDF_STATUS_SUCCESS; |
| } |
| |
| /* |
| * STA RSP received from HAL |
| */ |
| QDF_STATUS lim_process_tdls_add_sta_rsp(tpAniSirGlobal pMac, void *msg, |
| tpPESession psessionEntry) |
| { |
| tAddStaParams *pAddStaParams = (tAddStaParams *) msg; |
| uint8_t status = eSIR_SUCCESS; |
| tDphHashNode *pStaDs = NULL; |
| uint16_t aid = 0; |
| |
| SET_LIM_PROCESS_DEFD_MESGS(pMac, true); |
| lim_log(pMac, LOG1, FL("staIdx=%d, staMac="MAC_ADDRESS_STR), |
| pAddStaParams->staIdx, |
| MAC_ADDR_ARRAY(pAddStaParams->staMac)); |
| |
| if (pAddStaParams->status != QDF_STATUS_SUCCESS) { |
| QDF_ASSERT(0); |
| lim_log(pMac, LOGE, FL("Add sta failed ")); |
| status = eSIR_FAILURE; |
| goto add_sta_error; |
| } |
| |
| pStaDs = dph_lookup_hash_entry(pMac, pAddStaParams->staMac, &aid, |
| &psessionEntry->dph.dphHashTable); |
| if (NULL == pStaDs) { |
| lim_log(pMac, LOGE, FL("pStaDs is NULL ")); |
| status = eSIR_FAILURE; |
| goto add_sta_error; |
| } |
| |
| pStaDs->bssId = pAddStaParams->bssIdx; |
| pStaDs->staIndex = pAddStaParams->staIdx; |
| pStaDs->ucUcastSig = pAddStaParams->ucUcastSig; |
| pStaDs->ucBcastSig = pAddStaParams->ucBcastSig; |
| pStaDs->mlmStaContext.mlmState = eLIM_MLM_LINK_ESTABLISHED_STATE; |
| pStaDs->valid = 1; |
| add_sta_error: |
| status = lim_send_sme_tdls_add_sta_rsp(pMac, psessionEntry->smeSessionId, |
| pAddStaParams->staMac, |
| pAddStaParams->updateSta, pStaDs, |
| status); |
| qdf_mem_free(pAddStaParams); |
| return status; |
| } |
| |
| void populate_dot11f_tdls_offchannel_params(tpAniSirGlobal pMac, |
| tpPESession psessionEntry, |
| tDot11fIESuppChannels *suppChannels, |
| tDot11fIESuppOperatingClasses * |
| suppOperClasses) |
| { |
| uint32_t numChans = WNI_CFG_VALID_CHANNEL_LIST_LEN; |
| uint8_t validChan[WNI_CFG_VALID_CHANNEL_LIST_LEN]; |
| uint8_t i; |
| uint8_t valid_count = 0; |
| uint8_t chanOffset; |
| uint8_t op_class; |
| uint8_t numClasses; |
| uint8_t classes[CDS_MAX_SUPP_OPER_CLASSES]; |
| uint32_t band; |
| uint8_t nss_2g; |
| uint8_t nss_5g; |
| |
| if (wlan_cfg_get_str(pMac, WNI_CFG_VALID_CHANNEL_LIST, |
| validChan, &numChans) != eSIR_SUCCESS) { |
| /** |
| * Could not get Valid channel list from CFG. |
| * Log error. |
| */ |
| lim_log(pMac, LOGE, |
| FL("could not retrieve Valid channel list")); |
| return; |
| } |
| |
| if (IS_5G_CH(psessionEntry->currentOperChannel)) |
| band = eCSR_BAND_5G; |
| else |
| band = eCSR_BAND_24; |
| |
| nss_5g = QDF_MIN(pMac->vdev_type_nss_5g.tdls, |
| pMac->user_configured_nss); |
| nss_2g = QDF_MIN(pMac->vdev_type_nss_2g.tdls, |
| pMac->user_configured_nss); |
| |
| /* validating the channel list for DFS and 2G channels */ |
| for (i = 0U; i < numChans; i++) { |
| if ((band == eCSR_BAND_5G) && |
| (NSS_2x2_MODE == nss_5g) && |
| (NSS_1x1_MODE == nss_2g) && |
| (true == CDS_IS_DFS_CH(validChan[i]))) { |
| lim_log(pMac, LOG1, |
| FL("skipping channel %d, nss_5g: %d, nss_2g: %d"), |
| validChan[i], nss_5g, nss_2g); |
| continue; |
| } else { |
| if (true == cds_is_dsrc_channel( |
| cds_chan_to_freq(validChan[i]))) { |
| lim_log(pMac, LOG1, |
| FL("skipping channel %d from the valid channel list"), |
| validChan[i]); |
| continue; |
| } |
| } |
| |
| if (valid_count >= ARRAY_SIZE(suppChannels->bands)) |
| break; |
| suppChannels->bands[valid_count][0] = validChan[i]; |
| suppChannels->bands[valid_count][1] = 1; |
| valid_count++; |
| } |
| |
| suppChannels->num_bands = valid_count; |
| suppChannels->present = 1; |
| |
| /* find channel offset and get op class for current operating channel */ |
| switch (psessionEntry->htSecondaryChannelOffset) { |
| case PHY_SINGLE_CHANNEL_CENTERED: |
| chanOffset = BW20; |
| break; |
| |
| case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: |
| chanOffset = BW40_LOW_PRIMARY; |
| break; |
| |
| case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: |
| chanOffset = BW40_HIGH_PRIMARY; |
| break; |
| |
| default: |
| chanOffset = BWALL; |
| break; |
| |
| } |
| |
| op_class = cds_reg_dmn_get_opclass_from_channel( |
| pMac->scan.countryCodeCurrent, |
| psessionEntry->currentOperChannel, |
| chanOffset); |
| |
| if (op_class == 0) { |
| lim_log(pMac, LOGE, |
| FL( |
| "Present Operating class is wrong, countryCodeCurrent: %s, currentOperChannel: %d, htSecondaryChannelOffset: %d, chanOffset: %d" |
| ), |
| pMac->scan.countryCodeCurrent, |
| psessionEntry->currentOperChannel, |
| psessionEntry->htSecondaryChannelOffset, |
| chanOffset); |
| } else { |
| lim_log(pMac, LOG1, |
| FL( |
| "Present Operating channel: %d chanOffset: %d, op class=%d" |
| ), |
| psessionEntry->currentOperChannel, chanOffset, |
| op_class); |
| } |
| suppOperClasses->present = 1; |
| suppOperClasses->classes[0] = op_class; |
| |
| cds_reg_dmn_get_curr_opclasses(&numClasses, &classes[0]); |
| |
| for (i = 0; i < numClasses; i++) { |
| suppOperClasses->classes[i + 1] = classes[i]; |
| } |
| /* add one for present operating class, added in the beginning */ |
| suppOperClasses->num_classes = numClasses + 1; |
| |
| return; |
| } |
| |
| /* |
| * FUNCTION: Populate Link Identifier element IE |
| * |
| */ |
| |
| void populate_dot11f_link_iden(tpAniSirGlobal pMac, tpPESession psessionEntry, |
| tDot11fIELinkIdentifier *linkIden, |
| struct qdf_mac_addr peer_mac, uint8_t reqType) |
| { |
| uint8_t *initStaAddr = NULL; |
| uint8_t *respStaAddr = NULL; |
| |
| (reqType == TDLS_INITIATOR) ? ((initStaAddr = linkIden->InitStaAddr), |
| (respStaAddr = linkIden->RespStaAddr)) |
| : ((respStaAddr = linkIden->InitStaAddr), |
| (initStaAddr = linkIden->RespStaAddr)); |
| qdf_mem_copy((uint8_t *) linkIden->bssid, |
| (uint8_t *) psessionEntry->bssId, QDF_MAC_ADDR_SIZE); |
| |
| qdf_mem_copy((uint8_t *) initStaAddr, |
| psessionEntry->selfMacAddr, QDF_MAC_ADDR_SIZE); |
| |
| qdf_mem_copy((uint8_t *) respStaAddr, (uint8_t *) peer_mac.bytes, |
| QDF_MAC_ADDR_SIZE); |
| |
| linkIden->present = 1; |
| return; |
| |
| } |
| |
| void populate_dot11f_tdls_ext_capability(tpAniSirGlobal pMac, |
| tpPESession psessionEntry, |
| tDot11fIEExtCap *extCapability) |
| { |
| struct s_ext_cap *p_ext_cap = (struct s_ext_cap *)extCapability->bytes; |
| |
| p_ext_cap->tdls_peer_psm_supp = PEER_PSM_SUPPORT; |
| p_ext_cap->tdls_peer_uapsd_buffer_sta = pMac->lim.gLimTDLSBufStaEnabled; |
| |
| /* |
| * Set TDLS channel switching bits only if offchannel is enabled |
| * and TDLS Channel Switching is not prohibited by AP in ExtCap |
| * IE in assoc/re-assoc response. |
| */ |
| if ((1 == pMac->lim.gLimTDLSOffChannelEnabled) && |
| (!psessionEntry->tdls_chan_swit_prohibited)) { |
| p_ext_cap->tdls_channel_switching = 1; |
| p_ext_cap->tdls_chan_swit_prohibited = 0; |
| } else { |
| p_ext_cap->tdls_channel_switching = 0; |
| p_ext_cap->tdls_chan_swit_prohibited = TDLS_CH_SWITCH_PROHIBITED; |
| } |
| p_ext_cap->tdls_support = TDLS_SUPPORT; |
| p_ext_cap->tdls_prohibited = TDLS_PROHIBITED; |
| |
| extCapability->present = 1; |
| /* For STA cases we alwasy support 11mc - Allow MAX length */ |
| extCapability->num_bytes = DOT11F_IE_EXTCAP_MAX_LEN; |
| |
| return; |
| } |
| |
| /** |
| * lim_process_sme_tdls_mgmt_send_req() - send out tdls management frames |
| * |
| * @mac_ctx - global mac context |
| * @msg - message buffer received from SME. |
| * |
| * Process Send Mgmt Request from SME and transmit to AP. |
| * |
| * Return: eSIR_SUCCESS on success, error code otherwise |
| */ |
| tSirRetStatus lim_process_sme_tdls_mgmt_send_req(tpAniSirGlobal mac_ctx, |
| uint32_t *msg) |
| { |
| /* get all discovery request parameters */ |
| tSirTdlsSendMgmtReq *send_req = (tSirTdlsSendMgmtReq *) msg; |
| tpPESession session_entry; |
| uint8_t session_id; |
| tSirResultCodes result_code = eSIR_SME_INVALID_PARAMETERS; |
| |
| lim_log(mac_ctx, LOG1, FL("Send Mgmt Recieved")); |
| session_entry = pe_find_session_by_bssid(mac_ctx, |
| send_req->bssid.bytes, &session_id); |
| if (NULL == session_entry) { |
| lim_log(mac_ctx, LOGE, |
| FL("PE Session does not exist for given sme session_id %d"), |
| send_req->sessionId); |
| goto lim_tdls_send_mgmt_error; |
| } |
| |
| /* check if we are in proper state to work as TDLS client */ |
| if (!LIM_IS_STA_ROLE(session_entry)) { |
| QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, |
| FL("send mgmt received in wrong system Role %d"), |
| GET_LIM_SYSTEM_ROLE(session_entry)); |
| goto lim_tdls_send_mgmt_error; |
| } |
| |
| /* |
| * if we are still good, go ahead and check if we are in proper state to |
| * do TDLS discovery req/rsp/....frames. |
| */ |
| if ((session_entry->limSmeState != eLIM_SME_ASSOCIATED_STATE) && |
| (session_entry->limSmeState != eLIM_SME_LINK_EST_STATE)) { |
| lim_log(mac_ctx, LOGE, |
| FL("send mgmt received in invalid LIMsme state (%d)"), |
| session_entry->limSmeState); |
| goto lim_tdls_send_mgmt_error; |
| } |
| |
| cds_tdls_tx_rx_mgmt_event(SIR_MAC_ACTION_TDLS, |
| SIR_MAC_ACTION_TX, SIR_MAC_MGMT_ACTION, |
| send_req->reqType, send_req->peer_mac.bytes); |
| |
| switch (send_req->reqType) { |
| case SIR_MAC_TDLS_DIS_REQ: |
| lim_log(mac_ctx, LOG1, FL("Transmit Discovery Request Frame")); |
| /* format TDLS discovery request frame and transmit it */ |
| lim_send_tdls_dis_req_frame(mac_ctx, send_req->peer_mac, |
| send_req->dialog, session_entry); |
| result_code = eSIR_SME_SUCCESS; |
| break; |
| case SIR_MAC_TDLS_DIS_RSP: |
| lim_log(mac_ctx, LOG1, FL("Transmit Discovery Response Frame")); |
| /* Send a response mgmt action frame */ |
| lim_send_tdls_dis_rsp_frame(mac_ctx, send_req->peer_mac, |
| send_req->dialog, session_entry, &send_req->addIe[0], |
| (send_req->length - sizeof(tSirTdlsSendMgmtReq))); |
| result_code = eSIR_SME_SUCCESS; |
| break; |
| case SIR_MAC_TDLS_SETUP_REQ: |
| lim_log(mac_ctx, LOG1, FL("Transmit Setup Request Frame")); |
| lim_send_tdls_link_setup_req_frame(mac_ctx, |
| send_req->peer_mac, send_req->dialog, session_entry, |
| &send_req->addIe[0], |
| (send_req->length - sizeof(tSirTdlsSendMgmtReq))); |
| result_code = eSIR_SME_SUCCESS; |
| break; |
| case SIR_MAC_TDLS_SETUP_RSP: |
| lim_log(mac_ctx, LOG1, FL("Transmit Setup Response Frame")); |
| lim_send_tdls_setup_rsp_frame(mac_ctx, |
| send_req->peer_mac, send_req->dialog, session_entry, |
| send_req->statusCode, &send_req->addIe[0], |
| (send_req->length - sizeof(tSirTdlsSendMgmtReq))); |
| result_code = eSIR_SME_SUCCESS; |
| break; |
| case SIR_MAC_TDLS_SETUP_CNF: |
| lim_log(mac_ctx, LOG1, FL("Transmit Setup Confirm Frame")); |
| lim_send_tdls_link_setup_cnf_frame(mac_ctx, |
| send_req->peer_mac, send_req->dialog, |
| send_req->peerCapability, session_entry, |
| &send_req->addIe[0], |
| (send_req->length - sizeof(tSirTdlsSendMgmtReq))); |
| result_code = eSIR_SME_SUCCESS; |
| break; |
| case SIR_MAC_TDLS_TEARDOWN: |
| lim_log(mac_ctx, LOG1, FL("Transmit Teardown Frame")); |
| lim_send_tdls_teardown_frame(mac_ctx, |
| send_req->peer_mac, send_req->statusCode, |
| send_req->responder, session_entry, |
| &send_req->addIe[0], |
| (send_req->length - sizeof(tSirTdlsSendMgmtReq))); |
| result_code = eSIR_SME_SUCCESS; |
| break; |
| case SIR_MAC_TDLS_PEER_TRAFFIC_IND: |
| break; |
| case SIR_MAC_TDLS_CH_SWITCH_REQ: |
| break; |
| case SIR_MAC_TDLS_CH_SWITCH_RSP: |
| break; |
| case SIR_MAC_TDLS_PEER_TRAFFIC_RSP: |
| break; |
| default: |
| break; |
| } |
| |
| lim_tdls_send_mgmt_error: |
| lim_send_sme_rsp(mac_ctx, eWNI_SME_TDLS_SEND_MGMT_RSP, |
| result_code, send_req->sessionId, |
| send_req->transactionId); |
| |
| return eSIR_SUCCESS; |
| } |
| |
| /* |
| * Send Response to Link Establish Request to SME |
| */ |
| void lim_send_sme_tdls_link_establish_req_rsp(tpAniSirGlobal pMac, |
| uint8_t sessionId, |
| struct qdf_mac_addr *peermac, |
| tDphHashNode *pStaDs, uint8_t status) |
| { |
| tSirMsgQ mmhMsg = { 0 }; |
| |
| tSirTdlsLinkEstablishReqRsp *pTdlsLinkEstablishReqRsp = NULL; |
| |
| pTdlsLinkEstablishReqRsp = |
| qdf_mem_malloc(sizeof(tSirTdlsLinkEstablishReqRsp)); |
| if (NULL == pTdlsLinkEstablishReqRsp) { |
| lim_log(pMac, LOGE, FL("Failed to allocate memory")); |
| return; |
| } |
| pTdlsLinkEstablishReqRsp->statusCode = status; |
| if (peermac) |
| qdf_copy_macaddr(&pTdlsLinkEstablishReqRsp->peermac, peermac); |
| |
| pTdlsLinkEstablishReqRsp->sessionId = sessionId; |
| mmhMsg.type = eWNI_SME_TDLS_LINK_ESTABLISH_RSP; |
| mmhMsg.bodyptr = pTdlsLinkEstablishReqRsp; |
| mmhMsg.bodyval = 0; |
| lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); |
| return; |
| |
| } |
| |
| /* |
| * Once link is teardown, send Del Peer Ind to SME |
| */ |
| static QDF_STATUS lim_send_sme_tdls_del_sta_rsp(tpAniSirGlobal pMac, |
| uint8_t sessionId, |
| struct qdf_mac_addr peerMac, |
| tDphHashNode *pStaDs, uint8_t status) |
| { |
| tSirMsgQ mmhMsg = { 0 }; |
| tSirTdlsDelStaRsp *pDelSta = NULL; |
| mmhMsg.type = eWNI_SME_TDLS_DEL_STA_RSP; |
| |
| pDelSta = qdf_mem_malloc(sizeof(tSirTdlsDelStaRsp)); |
| if (NULL == pDelSta) { |
| lim_log(pMac, LOGE, FL("Failed to allocate memory")); |
| return QDF_STATUS_E_NOMEM; |
| } |
| |
| pDelSta->sessionId = sessionId; |
| pDelSta->statusCode = status; |
| if (pStaDs) { |
| pDelSta->staId = pStaDs->staIndex; |
| } else |
| pDelSta->staId = STA_INVALID_IDX; |
| |
| qdf_copy_macaddr(&pDelSta->peermac, &peerMac); |
| |
| pDelSta->length = sizeof(tSirTdlsDelStaRsp); |
| pDelSta->messageType = eWNI_SME_TDLS_DEL_STA_RSP; |
| |
| mmhMsg.bodyptr = pDelSta; |
| |
| mmhMsg.bodyval = 0; |
| lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); |
| return QDF_STATUS_SUCCESS; |
| |
| } |
| |
| /* |
| * Process Send Mgmt Request from SME and transmit to AP. |
| */ |
| tSirRetStatus lim_process_sme_tdls_add_sta_req(tpAniSirGlobal pMac, |
| uint32_t *pMsgBuf) |
| { |
| /* get all discovery request parameters */ |
| tSirTdlsAddStaReq *pAddStaReq = (tSirTdlsAddStaReq *) pMsgBuf; |
| tpPESession psessionEntry; |
| uint8_t sessionId; |
| |
| lim_log(pMac, LOG1, FL("TDLS Add STA Request Recieved")); |
| psessionEntry = |
| pe_find_session_by_bssid(pMac, pAddStaReq->bssid.bytes, |
| &sessionId); |
| if (psessionEntry == NULL) { |
| lim_log(pMac, LOGE, |
| FL( |
| "PE Session does not exist for given sme sessionId %d" |
| ), |
| pAddStaReq->sessionId); |
| goto lim_tdls_add_sta_error; |
| } |
| |
| /* check if we are in proper state to work as TDLS client */ |
| if (!LIM_IS_STA_ROLE(psessionEntry)) { |
| QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, |
| "send mgmt received in wrong system Role %d", |
| GET_LIM_SYSTEM_ROLE(psessionEntry)); |
| goto lim_tdls_add_sta_error; |
| } |
| |
| /* |
| * if we are still good, go ahead and check if we are in proper state to |
| * do TDLS discovery req/rsp/....frames. |
| */ |
| if ((psessionEntry->limSmeState != eLIM_SME_ASSOCIATED_STATE) && |
| (psessionEntry->limSmeState != eLIM_SME_LINK_EST_STATE)) { |
| |
| lim_log(pMac, LOGE, |
| FL("send mgmt received in invalid LIMsme state (%d)"), |
| psessionEntry->limSmeState); |
| goto lim_tdls_add_sta_error; |
| } |
| |
| pMac->lim.gLimAddStaTdls = true; |
| |
| /* To start with, send add STA request to HAL */ |
| if (eSIR_FAILURE == lim_tdls_setup_add_sta(pMac, pAddStaReq, psessionEntry)) { |
| lim_log(pMac, LOGE, |
| FL("Add TDLS Station request failed")); |
| goto lim_tdls_add_sta_error; |
| } |
| return eSIR_SUCCESS; |
| lim_tdls_add_sta_error: |
| lim_send_sme_tdls_add_sta_rsp(pMac, |
| pAddStaReq->sessionId, |
| pAddStaReq->peermac.bytes, |
| (pAddStaReq->tdlsAddOper == TDLS_OPER_UPDATE), |
| NULL, eSIR_FAILURE); |
| |
| return eSIR_SUCCESS; |
| } |
| |
| /* |
| * Process Del Sta Request from SME . |
| */ |
| tSirRetStatus lim_process_sme_tdls_del_sta_req(tpAniSirGlobal pMac, |
| uint32_t *pMsgBuf) |
| { |
| /* get all discovery request parameters */ |
| tSirTdlsDelStaReq *pDelStaReq = (tSirTdlsDelStaReq *) pMsgBuf; |
| tpPESession psessionEntry; |
| uint8_t sessionId; |
| tpDphHashNode pStaDs = NULL; |
| |
| lim_log(pMac, LOG1, FL("TDLS Delete STA Request Recieved")); |
| psessionEntry = |
| pe_find_session_by_bssid(pMac, pDelStaReq->bssid.bytes, |
| &sessionId); |
| if (psessionEntry == NULL) { |
| lim_log(pMac, LOGE, |
| FL( |
| "PE Session does not exist for given sme sessionId %d" |
| ), |
| pDelStaReq->sessionId); |
| lim_send_sme_tdls_del_sta_rsp(pMac, pDelStaReq->sessionId, |
| pDelStaReq->peermac, NULL, |
| eSIR_FAILURE); |
| return eSIR_FAILURE; |
| } |
| |
| /* check if we are in proper state to work as TDLS client */ |
| if (!LIM_IS_STA_ROLE(psessionEntry)) { |
| QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, |
| "Del sta received in wrong system Role %d", |
| GET_LIM_SYSTEM_ROLE(psessionEntry)); |
| goto lim_tdls_del_sta_error; |
| } |
| |
| /* |
| * if we are still good, go ahead and check if we are in proper state to |
| * do TDLS discovery req/rsp/....frames. |
| */ |
| if ((psessionEntry->limSmeState != eLIM_SME_ASSOCIATED_STATE) && |
| (psessionEntry->limSmeState != eLIM_SME_LINK_EST_STATE)) { |
| |
| lim_log(pMac, LOGE, |
| FL("Del Sta received in invalid LIMsme state (%d)"), |
| psessionEntry->limSmeState); |
| goto lim_tdls_del_sta_error; |
| } |
| |
| pStaDs = lim_tdls_del_sta(pMac, pDelStaReq->peermac, psessionEntry); |
| |
| /* now send indication to SME-->HDD->TL to remove STA from TL */ |
| |
| if (pStaDs) { |
| lim_send_sme_tdls_del_sta_rsp(pMac, psessionEntry->smeSessionId, |
| pDelStaReq->peermac, pStaDs, |
| eSIR_SUCCESS); |
| lim_release_peer_idx(pMac, pStaDs->assocId, psessionEntry); |
| |
| /* Clear the aid in peerAIDBitmap as this aid is now in freepool */ |
| CLEAR_PEER_AID_BITMAP(psessionEntry->peerAIDBitmap, |
| pStaDs->assocId); |
| lim_delete_dph_hash_entry(pMac, pStaDs->staAddr, pStaDs->assocId, |
| psessionEntry); |
| |
| return eSIR_SUCCESS; |
| |
| } |
| |
| lim_tdls_del_sta_error: |
| lim_send_sme_tdls_del_sta_rsp(pMac, psessionEntry->smeSessionId, |
| pDelStaReq->peermac, NULL, eSIR_FAILURE); |
| |
| return eSIR_SUCCESS; |
| } |
| |
| /* Intersects the two input arrays and outputs an array */ |
| /* For now the array length of uint8_t suffices */ |
| static void lim_tdls_get_intersection(uint8_t *input_array1, |
| uint8_t input1_length, |
| uint8_t *input_array2, |
| uint8_t input2_length, |
| uint8_t *output_array, |
| uint8_t *output_length) |
| { |
| uint8_t i, j, k = 0, flag = 0; |
| for (i = 0; i < input1_length; i++) { |
| flag = 0; |
| for (j = 0; j < input2_length; j++) { |
| if (input_array1[i] == input_array2[j]) { |
| flag = 1; |
| break; |
| } |
| } |
| if (flag == 1) { |
| output_array[k] = input_array1[i]; |
| k++; |
| } |
| } |
| *output_length = k; |
| } |
| |
| /** |
| * lim_process_sme_tdls_link_establish_req() - process tdls link establishment |
| * request |
| * |
| * @mac_ctx - global MAC context |
| * @msg_buf - message buffer from SME |
| * |
| * Process Link Establishment Request from SME |
| * |
| * Return: eSIR_SUCCESS on success, failure code otherwise. |
| */ |
| tSirRetStatus lim_process_sme_tdls_link_establish_req(tpAniSirGlobal mac_ctx, |
| uint32_t *msg_buf) |
| { |
| /* get all discovery request parameters */ |
| tSirTdlsLinkEstablishReq *tdls_req = |
| (tSirTdlsLinkEstablishReq *) msg_buf; |
| tpPESession session_entry; |
| uint8_t session_id; |
| tpTdlsLinkEstablishParams tdls_req_params; |
| tSirMsgQ msg; |
| uint16_t peer_idx = 0; |
| tpDphHashNode stads = NULL; |
| uint32_t self_num_chan = WNI_CFG_VALID_CHANNEL_LIST_LEN; |
| uint8_t self_supp_chan[WNI_CFG_VALID_CHANNEL_LIST_LEN]; |
| |
| QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, |
| FL("Send Mgmt Recieved")); |
| |
| session_entry = pe_find_session_by_bssid(mac_ctx, tdls_req->bssid.bytes, |
| &session_id); |
| if (NULL == session_entry) { |
| QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, |
| FL("PE Session does not exist for sme session_id %d"), |
| tdls_req->sessionId); |
| lim_send_sme_tdls_link_establish_req_rsp(mac_ctx, |
| tdls_req->sessionId, &tdls_req->peermac, NULL, |
| eSIR_FAILURE); |
| return eSIR_FAILURE; |
| } |
| |
| /* check if we are in proper state to work as TDLS client */ |
| if (!LIM_IS_STA_ROLE(session_entry)) { |
| QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, |
| FL("TDLS Link Establish Request received in wrong system Role %d"), |
| GET_LIM_SYSTEM_ROLE(session_entry)); |
| goto lim_tdls_link_establish_error; |
| } |
| |
| /* |
| * if we are still good, go ahead and check if we are in proper state to |
| * do TDLS discovery req/rsp/....frames. |
| */ |
| if ((session_entry->limSmeState != eLIM_SME_ASSOCIATED_STATE) && |
| (session_entry->limSmeState != eLIM_SME_LINK_EST_STATE)) { |
| lim_log(mac_ctx, LOGE, |
| FL("TDLS Link Establish Request received in invalid LIMsme state (%d)"), |
| session_entry->limSmeState); |
| goto lim_tdls_link_establish_error; |
| } |
| |
| stads = dph_lookup_hash_entry(mac_ctx, tdls_req->peermac.bytes, |
| &peer_idx, |
| &session_entry->dph.dphHashTable); |
| if (NULL == stads) { |
| lim_log(mac_ctx, LOGE, FL("stads is NULL")); |
| goto lim_tdls_link_establish_error; |
| } |
| tdls_req_params = qdf_mem_malloc(sizeof(tTdlsLinkEstablishParams)); |
| if (NULL == tdls_req_params) { |
| lim_log(mac_ctx, LOGE, |
| FL("Unable to allocate memory TDLS Link Establish Request")); |
| return eSIR_MEM_ALLOC_FAILED; |
| } |
| |
| qdf_mem_set((uint8_t *) tdls_req_params, |
| sizeof(tTdlsLinkEstablishParams), 0); |
| |
| tdls_req_params->staIdx = stads->staIndex; |
| tdls_req_params->isResponder = tdls_req->isResponder; |
| tdls_req_params->uapsdQueues = tdls_req->uapsdQueues; |
| tdls_req_params->maxSp = tdls_req->maxSp; |
| tdls_req_params->isBufsta = tdls_req->isBufSta; |
| tdls_req_params->isOffChannelSupported = |
| tdls_req->isOffChannelSupported; |
| |
| if (0 == tdls_req->supportedChannelsLen) |
| goto send_tdls_establish_request; |
| |
| if (wlan_cfg_get_str(mac_ctx, WNI_CFG_VALID_CHANNEL_LIST, |
| self_supp_chan, |
| &self_num_chan) != eSIR_SUCCESS) { |
| /** |
| * Could not get Valid channel list from CFG. |
| * Log error. |
| */ |
| lim_log(mac_ctx, LOGE, |
| FL("could not retrieve Valid channel list")); |
| } |
| |
| if (self_num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) { |
| lim_log(mac_ctx, LOGE, |
| FL("Channel List more than Valid Channel list")); |
| self_num_chan = WNI_CFG_VALID_CHANNEL_LIST_LEN; |
| } |
| |
| if (tdls_req->supportedChannelsLen > SIR_MAC_MAX_SUPP_CHANNELS) { |
| lim_log(mac_ctx, LOGE, |
| FL("Channel List is more than the supported Channel list")); |
| tdls_req->supportedChannelsLen = SIR_MAC_MAX_SUPP_CHANNELS; |
| } |
| |
| lim_tdls_get_intersection(self_supp_chan, self_num_chan, |
| tdls_req->supportedChannels, tdls_req->supportedChannelsLen, |
| tdls_req_params->validChannels, |
| &tdls_req_params->validChannelsLen); |
| |
| send_tdls_establish_request: |
| qdf_mem_copy(tdls_req_params->validOperClasses, |
| tdls_req->supportedOperClasses, |
| tdls_req->supportedOperClassesLen); |
| tdls_req_params->validOperClassesLen = |
| tdls_req->supportedOperClassesLen; |
| |
| msg.type = WMA_SET_TDLS_LINK_ESTABLISH_REQ; |
| msg.reserved = 0; |
| msg.bodyptr = tdls_req_params; |
| msg.bodyval = 0; |
| if (eSIR_SUCCESS != wma_post_ctrl_msg(mac_ctx, &msg)) { |
| lim_log(mac_ctx, LOGE, FL("halPostMsgApi failed")); |
| goto lim_tdls_link_establish_error; |
| } |
| return eSIR_SUCCESS; |
| |
| lim_tdls_link_establish_error: |
| lim_send_sme_tdls_link_establish_req_rsp(mac_ctx, |
| session_entry->smeSessionId, &tdls_req->peermac, NULL, |
| eSIR_FAILURE); |
| |
| return eSIR_SUCCESS; |
| } |
| |
| /** |
| * lim_delete_tdls_peers() - delete tdls peers |
| * |
| * @mac_ctx - global MAC context |
| * @session_entry - PE session entry |
| * |
| * Delete all the TDLS peer connected before leaving the BSS |
| * |
| * Return: eSIR_SUCCESS on success, error code otherwise |
| */ |
| tSirRetStatus lim_delete_tdls_peers(tpAniSirGlobal mac_ctx, |
| tpPESession session_entry) |
| { |
| tpDphHashNode stads = NULL; |
| int i, aid; |
| size_t aid_bitmap_size = sizeof(session_entry->peerAIDBitmap); |
| |
| if (NULL == session_entry) { |
| lim_log(mac_ctx, LOGE, FL("NULL session_entry")); |
| return eSIR_FAILURE; |
| } |
| |
| /* |
| * Check all the set bit in peerAIDBitmap and delete the peer |
| * (with that aid) entry from the hash table and add the aid |
| * in free pool |
| */ |
| for (i = 0; i < aid_bitmap_size / sizeof(uint32_t); i++) { |
| for (aid = 0; aid < (sizeof(uint32_t) << 3); aid++) { |
| if (!CHECK_BIT(session_entry->peerAIDBitmap[i], aid)) |
| continue; |
| stads = dph_get_hash_entry(mac_ctx, |
| (aid + i * (sizeof(uint32_t) << 3)), |
| &session_entry->dph.dphHashTable); |
| |
| if (NULL != stads) { |
| lim_log(mac_ctx, LOGE, |
| FL("Deleting "MAC_ADDRESS_STR), |
| MAC_ADDR_ARRAY(stads->staAddr)); |
| |
| lim_send_deauth_mgmt_frame(mac_ctx, |
| eSIR_MAC_DEAUTH_LEAVING_BSS_REASON, |
| stads->staAddr, session_entry, false); |
| dph_delete_hash_entry(mac_ctx, |
| stads->staAddr, stads->assocId, |
| &session_entry->dph.dphHashTable); |
| } |
| lim_release_peer_idx(mac_ctx, |
| (aid + i * (sizeof(uint32_t) << 3)), |
| session_entry); |
| CLEAR_BIT(session_entry->peerAIDBitmap[i], aid); |
| } |
| } |
| if (lim_is_roam_synch_in_progress(session_entry)) |
| return eSIR_SUCCESS; |
| lim_send_sme_tdls_delete_all_peer_ind(mac_ctx, session_entry); |
| |
| return eSIR_SUCCESS; |
| } |
| |
| #endif |