blob: 6b9e0b27ed0d9d80bd71a50a632654968373149d [file] [edit]
/******************************************************************************
*
* This file is provided under a dual license. When you use or
* distribute this software, you may choose to be licensed under
* version 2 of the GNU General Public License ("GPLv2 License")
* or BSD License.
*
* GPLv2 License
*
* Copyright(C) 2016 MediaTek Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See http://www.gnu.org/licenses/gpl-2.0.html for more details.
*
* BSD LICENSE
*
* Copyright(C) 2016 MediaTek Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
/*
* Id: tdls.c#1
*/
/*! \file tdls.c
* \brief This file includes IEEE802.11z TDLS support.
*/
/*******************************************************************************
* C O M P I L E R F L A G S
*******************************************************************************
*/
/*******************************************************************************
* E X T E R N A L R E F E R E N C E S
*******************************************************************************
*/
#include "precomp.h"
#if CFG_SUPPORT_TDLS
#include "tdls.h"
#include "gl_cfg80211.h"
#include "queue.h"
/*******************************************************************************
* C O N S T A N T S
*******************************************************************************
*/
/*******************************************************************************
* D A T A T Y P E S
*******************************************************************************
*/
/*******************************************************************************
* P U B L I C D A T A
*******************************************************************************
*/
uint8_t g_arTdlsLink[MAXNUM_TDLS_PEER] = {
0,
0,
0,
0
};
/*******************************************************************************
* P R I V A T E D A T A
*******************************************************************************
*/
static u_int8_t fgIsPtiTimeoutSkip = FALSE;
/*******************************************************************************
* M A C R O S
*******************************************************************************
*/
#define ELEM_ID_LINK_IDENTIFIER_LENGTH 16
#define TDLS_KEY_TIMEOUT_INTERVAL 43200
#define UNREACH_ABLE 25
#define TDLS_REASON_CODE_UNREACHABLE 25
#define TDLS_REASON_CODE_UNSPECIFIED 26
#define WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE 25
#define WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED 26
/*******************************************************************************
* F U N C T I O N D E C L A R A T I O N S
*******************************************************************************
*/
/*******************************************************************************
* F U N C T I O N S
*******************************************************************************
*/
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is called to hadel TDLS link oper from nl80211.
*
* \param[in] pvAdapter Pointer to the Adapter structure.
* \param[in]
* \param[in]
* \param[in] buf includes RSN IE + FT IE + Lifetimeout IE
*
* \retval WLAN_STATUS_SUCCESS
* \retval WLAN_STATUS_INVALID_LENGTH
*/
/*----------------------------------------------------------------------------*/
uint32_t TdlsexLinkMgt(struct ADAPTER *prAdapter,
void *pvSetBuffer, uint32_t u4SetBufferLen,
uint32_t *pu4SetInfoLen)
{
/* from supplicant -- wpa_supplicant_tdls_peer_addset() */
struct STA_RECORD *prStaRec;
struct BSS_INFO *prBssInfo;
struct TDLS_CMD_LINK_MGT *prCmd;
prCmd = (struct TDLS_CMD_LINK_MGT *) pvSetBuffer;
prBssInfo = prAdapter->prAisBssInfo;
DBGLOG(TDLS, INFO, "u4SetBufferLen=%d", u4SetBufferLen);
#if 1
/* AIS only */
if (prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) {
prStaRec = prBssInfo->prStaRecOfAP;
if (prStaRec == NULL)
return 0;
} else {
return -EINVAL;
}
#endif
DBGLOG(TDLS, INFO, "prCmd->ucActionCode=%d, prCmd->ucDialogToken=%d",
prCmd->ucActionCode, prCmd->ucDialogToken);
prStaRec = prBssInfo->prStaRecOfAP;
switch (prCmd->ucActionCode) {
case TDLS_FRM_ACTION_DISCOVERY_REQ:
if (prStaRec == NULL)
return 0;
if (TdlsDataFrameSend_DISCOVERY_REQ(prAdapter,
prStaRec,
prCmd->aucPeer,
prCmd->ucActionCode,
prCmd->ucDialogToken,
prCmd->u2StatusCode,
(uint8_t *) (prCmd->aucSecBuf),
prCmd->u4SecBufLen)
!= TDLS_STATUS_SUCCESS) {
return -1;
}
break;
case TDLS_FRM_ACTION_SETUP_REQ:
if (prStaRec == NULL)
return 0;
prStaRec = cnmGetTdlsPeerByAddress(prAdapter,
prAdapter->prAisBssInfo->ucBssIndex,
prCmd->aucPeer);
g_arTdlsLink[prStaRec->ucTdlsIndex] = 0;
if (TdlsDataFrameSend_SETUP_REQ(prAdapter,
prStaRec,
prCmd->aucPeer,
prCmd->ucActionCode,
prCmd->ucDialogToken,
prCmd->u2StatusCode,
(uint8_t *) (prCmd->aucSecBuf),
prCmd->u4SecBufLen)
!= TDLS_STATUS_SUCCESS) {
return -1;
}
break;
case TDLS_FRM_ACTION_SETUP_RSP:
/* fix sigma bug 5.2.4.2, 5.2.4.7, we sent Status code decline,
* but the sigma recogniezis it as scucess, and it will fail
*/
/* if(prCmd->u2StatusCode != 0) */
if (prBssInfo->fgTdlsIsProhibited)
return 0;
if (TdlsDataFrameSend_SETUP_RSP(prAdapter,
prStaRec,
prCmd->aucPeer,
prCmd->ucActionCode,
prCmd->ucDialogToken,
prCmd->u2StatusCode,
(uint8_t *) (prCmd->aucSecBuf),
prCmd->u4SecBufLen)
!= TDLS_STATUS_SUCCESS) {
return -1;
}
break;
case TDLS_FRM_ACTION_DISCOVERY_RSP:
if (TdlsDataFrameSend_DISCOVERY_RSP(prAdapter,
prStaRec,
prCmd->aucPeer,
prCmd->ucActionCode,
prCmd->ucDialogToken,
prCmd->u2StatusCode,
(uint8_t *) (prCmd->aucSecBuf),
prCmd->u4SecBufLen)
!= TDLS_STATUS_SUCCESS) {
return -1;
}
break;
case TDLS_FRM_ACTION_CONFIRM:
if (TdlsDataFrameSend_CONFIRM(prAdapter,
prStaRec,
prCmd->aucPeer,
prCmd->ucActionCode,
prCmd->ucDialogToken,
prCmd->u2StatusCode,
(uint8_t *) (prCmd->aucSecBuf),
prCmd->u4SecBufLen)
!= TDLS_STATUS_SUCCESS) {
return -1;
}
break;
case TDLS_FRM_ACTION_TEARDOWN:
prStaRec = cnmGetTdlsPeerByAddress(prAdapter,
prAdapter->prAisBssInfo->ucBssIndex,
prCmd->aucPeer);
if (prCmd->u2StatusCode == TDLS_REASON_CODE_UNREACHABLE)
g_arTdlsLink[prStaRec->ucTdlsIndex] = 0;
if (TdlsDataFrameSend_TearDown(prAdapter,
prStaRec,
prCmd->aucPeer,
prCmd->ucActionCode,
prCmd->ucDialogToken,
prCmd->u2StatusCode,
(uint8_t *) (prCmd->aucSecBuf),
prCmd->u4SecBufLen)
!= TDLS_STATUS_SUCCESS) {
return -1;
}
break;
default:
return -EINVAL;
}
return 0;
}
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is called to hadel TDLS link mgt from nl80211.
*
* \param[in] pvAdapter Pointer to the Adapter structure.
* \param[in]
* \param[in]
* \param[in] buf includes RSN IE + FT IE + Lifetimeout IE
*
* \retval WLAN_STATUS_SUCCESS
* \retval WLAN_STATUS_INVALID_LENGTH
*/
/*----------------------------------------------------------------------------*/
uint32_t TdlsexLinkOper(struct ADAPTER *prAdapter,
void *pvSetBuffer, uint32_t u4SetBufferLen,
uint32_t *pu4SetInfoLen)
{
/* from supplicant -- wpa_supplicant_tdls_peer_addset() */
uint16_t i;
struct STA_RECORD *prStaRec;
struct TDLS_CMD_LINK_OPER *prCmd;
prCmd = (struct TDLS_CMD_LINK_OPER *) pvSetBuffer;
DBGLOG(TDLS, INFO, "prCmd->oper=%d, u4SetBufferLen=%d",
prCmd->oper, u4SetBufferLen);
switch (prCmd->oper) {
case TDLS_ENABLE_LINK:
for (i = 0; i < MAXNUM_TDLS_PEER; i++) {
if (!g_arTdlsLink[i]) {
g_arTdlsLink[i] = 1;
prStaRec =
cnmGetTdlsPeerByAddress(prAdapter,
prAdapter->prAisBssInfo->ucBssIndex,
prCmd->aucPeerMac);
prStaRec->ucTdlsIndex = i;
break;
}
}
break;
case TDLS_DISABLE_LINK:
prStaRec = cnmGetTdlsPeerByAddress(prAdapter,
prAdapter->prAisBssInfo->ucBssIndex,
prCmd->aucPeerMac);
g_arTdlsLink[prStaRec->ucTdlsIndex] = 0;
if (IS_DLS_STA(prStaRec))
cnmStaRecFree(prAdapter, prStaRec);
break;
default:
return 0;
}
return 0;
}
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is called to append general IEs.
*
* \param[in] pvAdapter Pointer to the Adapter structure.
* \param[in]
*
* \retval append length
*/
/*----------------------------------------------------------------------------*/
uint32_t TdlsFrameGeneralIeAppend(struct ADAPTER *prAdapter,
struct STA_RECORD *prStaRec, uint8_t *pPkt)
{
struct GLUE_INFO *prGlueInfo;
struct BSS_INFO *prBssInfo;
struct PM_PROFILE_SETUP_INFO *prPmProfSetupInfo;
uint32_t u4NonHTPhyType;
uint16_t u2SupportedRateSet;
uint8_t aucAllSupportedRates[RATE_NUM_SW] = { 0 };
uint8_t ucAllSupportedRatesLen;
uint8_t ucSupRatesLen;
uint8_t ucExtSupRatesLen;
uint32_t u4PktLen, u4IeLen;
/* init */
prGlueInfo = (struct GLUE_INFO *) prAdapter->prGlueInfo;
prBssInfo = prAdapter->prAisBssInfo; /* AIS only */
prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo;
u4PktLen = 0;
/* 3. Frame Formation - (5) Supported Rates element */
/* use all sup rate we can support */
u4NonHTPhyType = prStaRec->ucNonHTBasicPhyType;
u2SupportedRateSet =
rNonHTPhyAttributes[u4NonHTPhyType].u2SupportedRateSet;
rateGetDataRatesFromRateSet(u2SupportedRateSet, 0,
aucAllSupportedRates,
&ucAllSupportedRatesLen);
ucSupRatesLen = ((ucAllSupportedRatesLen >
ELEM_MAX_LEN_SUP_RATES) ?
ELEM_MAX_LEN_SUP_RATES : ucAllSupportedRatesLen);
ucExtSupRatesLen = ucAllSupportedRatesLen - ucSupRatesLen;
if (ucSupRatesLen) {
SUP_RATES_IE(pPkt)->ucId = ELEM_ID_SUP_RATES;
SUP_RATES_IE(pPkt)->ucLength = ucSupRatesLen;
kalMemCopy(SUP_RATES_IE(pPkt)->aucSupportedRates,
aucAllSupportedRates, ucSupRatesLen);
u4IeLen = IE_SIZE(pPkt);
pPkt += u4IeLen;
u4PktLen += u4IeLen;
}
/* 3. Frame Formation - (7) Extended sup rates element */
if (ucExtSupRatesLen) {
EXT_SUP_RATES_IE(pPkt)->ucId = ELEM_ID_EXTENDED_SUP_RATES;
EXT_SUP_RATES_IE(pPkt)->ucLength = ucExtSupRatesLen;
kalMemCopy(EXT_SUP_RATES_IE(pPkt)->aucExtSupportedRates,
&aucAllSupportedRates[ucSupRatesLen],
ucExtSupRatesLen);
u4IeLen = IE_SIZE(pPkt);
pPkt += u4IeLen;
u4PktLen += u4IeLen;
}
/* 3. Frame Formation - (8) Supported channels element */
SUPPORTED_CHANNELS_IE(pPkt)->ucId = ELEM_ID_SUP_CHS;
SUPPORTED_CHANNELS_IE(pPkt)->ucLength = 2;
SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[0] = 1;
SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[1] = 13;
if (prAdapter->fgEnable5GBand == TRUE) {
SUPPORTED_CHANNELS_IE(pPkt)->ucLength = 10;
SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[2] = 36;
SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[3] = 4;
SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[4] = 52;
SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[5] = 4;
SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[6] = 149;
SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[7] = 4;
SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[8] = 165;
SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[9] = 1;
}
u4IeLen = IE_SIZE(pPkt);
pPkt += u4IeLen;
u4PktLen += u4IeLen;
return u4PktLen;
}
/*!
* \brief This routine is called to transmit a TDLS data frame.
*
* \param[in] pvAdapter Pointer to the Adapter structure.
* \param[in]
* \param[in]
* \param[in] buf includes RSN IE + FT IE + Lifetimeout IE
*
* \retval WLAN_STATUS_SUCCESS
* \retval WLAN_STATUS_INVALID_LENGTH
*/
/*----------------------------------------------------------------------------*/
uint32_t
TdlsDataFrameSend_TearDown(struct ADAPTER *prAdapter,
struct STA_RECORD *prStaRec,
uint8_t *pPeerMac,
uint8_t ucActionCode,
uint8_t ucDialogToken, uint16_t u2StatusCode,
uint8_t *pAppendIe, uint32_t AppendIeLen)
{
struct GLUE_INFO *prGlueInfo;
struct BSS_INFO *prBssInfo;
struct PM_PROFILE_SETUP_INFO *prPmProfSetupInfo;
struct sk_buff *prMsduInfo;
uint8_t *pPkt;
uint32_t u4PktLen, u4IeLen;
uint16_t ReasonCode;
/* allocate/init packet */
prGlueInfo = (struct GLUE_INFO *) prAdapter->prGlueInfo;
prBssInfo = prAdapter->prAisBssInfo; /* AIS only */
prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo;
u4PktLen = 0;
prMsduInfo = kalPacketAllocWithHeadroom(prGlueInfo, 1600,
&pPkt);
if (prMsduInfo == NULL)
return TDLS_STATUS_RESOURCES;
prMsduInfo->dev = prGlueInfo->prDevHandler;
if (prMsduInfo->dev == NULL) {
kalPacketFree(prGlueInfo, prMsduInfo);
return TDLS_STATUS_FAIL;
}
/* make up frame content */
/* 1. 802.3 header */
kalMemCopy(pPkt, pPeerMac, TDLS_FME_MAC_ADDR_LEN);
pPkt += TDLS_FME_MAC_ADDR_LEN;
kalMemCopy(pPkt, prBssInfo->aucOwnMacAddr,
TDLS_FME_MAC_ADDR_LEN);
pPkt += TDLS_FME_MAC_ADDR_LEN;
*(uint16_t *) pPkt = htons(TDLS_FRM_PROT_TYPE);
pPkt += 2;
u4PktLen += TDLS_FME_MAC_ADDR_LEN * 2 + 2;
/* 2. payload type */
*pPkt = TDLS_FRM_PAYLOAD_TYPE;
pPkt++;
u4PktLen++;
/* 3. Frame Formation - (1) Category */
*pPkt = TDLS_FRM_CATEGORY;
pPkt++;
u4PktLen++;
/* 3. Frame Formation - (2) Action */
*pPkt = ucActionCode;
pPkt++;
u4PktLen++;
/* 3. Frame Formation - status code */
ReasonCode = u2StatusCode;
kalMemCopy(pPkt, &ReasonCode, 2);
pPkt = pPkt + 2;
u4PktLen = u4PktLen + 2;
if (pAppendIe != NULL) {
if ((ucActionCode != TDLS_FRM_ACTION_TEARDOWN) ||
((ucActionCode == TDLS_FRM_ACTION_TEARDOWN)
&& (prStaRec != NULL))) {
kalMemCopy(pPkt, pAppendIe, AppendIeLen);
LR_TDLS_FME_FIELD_FILL(AppendIeLen);
}
}
/* 7. Append Supported Operating Classes IE */
if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) {
/* Note: if we do not put the IE, Marvell STA will
* decline our TDLS setup request
*/
u4IeLen = rlmDomainSupOperatingClassIeFill(pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
}
/* 3. Frame Formation - (16) Link identifier element */
TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId =
ELEM_ID_LINK_IDENTIFIER;
TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = 18;
kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID,
prBssInfo->aucBSSID, 6);
kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator,
prBssInfo->aucOwnMacAddr, 6);
kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder,
pPeerMac, 6);
u4IeLen = IE_SIZE(pPkt);
pPkt += u4IeLen;
u4PktLen += u4IeLen;
/* 5. Update packet length */
prMsduInfo->len = u4PktLen;
/* if(u2StatusCode == UNREACH_ABLE ){ */
/* g_arTdlsLink[prStaRec->ucTdlsIndex] = FALSE; */
/* } */
/* 5. send the data frame */
wlanHardStartXmit(prMsduInfo, prMsduInfo->dev);
return TDLS_STATUS_SUCCESS;
}
/*!
* \brief This routine is called to transmit a TDLS data frame.
*
* \param[in] pvAdapter Pointer to the Adapter structure.
* \param[in]
* \param[in]
* \param[in] buf includes RSN IE + FT IE + Lifetimeout IE
*
* \retval WLAN_STATUS_SUCCESS
* \retval WLAN_STATUS_INVALID_LENGTH
*/
/*----------------------------------------------------------------------------*/
uint32_t /* TDLS_STATUS */
TdlsDataFrameSend_SETUP_REQ(struct ADAPTER *prAdapter,
struct STA_RECORD *prStaRec,
uint8_t *pPeerMac,
uint8_t ucActionCode,
uint8_t ucDialogToken, uint16_t u2StatusCode,
uint8_t *pAppendIe, uint32_t AppendIeLen)
{
struct GLUE_INFO *prGlueInfo;
struct BSS_INFO *prBssInfo;
struct PM_PROFILE_SETUP_INFO *prPmProfSetupInfo;
struct sk_buff *prMsduInfo;
uint8_t *pPkt;
uint32_t u4PktLen, u4IeLen;
uint16_t u2CapInfo;
/* allocate/init packet */
prGlueInfo = (struct GLUE_INFO *) prAdapter->prGlueInfo;
prBssInfo = prAdapter->prAisBssInfo;
prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo;
u4PktLen = 0;
if (prStaRec == NULL)
return TDLS_STATUS_FAIL;
prMsduInfo = kalPacketAllocWithHeadroom(prGlueInfo, 512, &pPkt);
if (prMsduInfo == NULL)
return TDLS_STATUS_RESOURCES;
prMsduInfo->dev = prGlueInfo->prDevHandler;
if (prMsduInfo->dev == NULL) {
kalPacketFree(prGlueInfo, prMsduInfo);
return TDLS_STATUS_FAIL;
}
/* make up frame content */
/* 1. 802.3 header */
kalMemCopy(pPkt, pPeerMac, TDLS_FME_MAC_ADDR_LEN);
LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN);
kalMemCopy(pPkt, prBssInfo->aucOwnMacAddr, TDLS_FME_MAC_ADDR_LEN);
LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN);
*(uint16_t *) pPkt = htons(TDLS_FRM_PROT_TYPE);
LR_TDLS_FME_FIELD_FILL(2);
/* 2. payload type */
*pPkt = TDLS_FRM_PAYLOAD_TYPE;
LR_TDLS_FME_FIELD_FILL(1);
/*
* 3.1 Category
* 3.2 Action
* 3.3 Dialog Token
* 3.4 Capability
* 3.5 Supported rates
* 3.6 Country
* 3.7 Extended supported rates
* 3.8 Supported Channels (optional)
* 3.9 RSNIE (optional)
* 3.10 Extended Capabilities
* 3.11 QoS Capability
* 3.12 FTIE (optional)
* 3.13 Timeout Interval (optional)
* 3.14 Supported Regulatory Classes (optional)
* 3.15 HT Capabilities
* 3.16 20/40 BSS Coexistence
* 3.17 Link Identifier
*/
/* 3.1 Category */
*pPkt = TDLS_FRM_CATEGORY;
LR_TDLS_FME_FIELD_FILL(1);
/* 3.2 Action */
*pPkt = ucActionCode;
LR_TDLS_FME_FIELD_FILL(1);
/* 3.3 Dialog Token */
*pPkt = ucDialogToken;
LR_TDLS_FME_FIELD_FILL(1);
/* 3.4 Capability */
u2CapInfo = assocBuildCapabilityInfo(prAdapter, prStaRec);
WLAN_SET_FIELD_16(pPkt, u2CapInfo);
LR_TDLS_FME_FIELD_FILL(2);
/*
* 3.5 Supported rates
* 3.7 Extended supported rates
* 3.8 Supported Channels (optional)
*/
u4IeLen = TdlsFrameGeneralIeAppend(prAdapter, prStaRec, pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
/* 3.6 Country */
/* 3.14 Supported Regulatory Classes (optional) */
/* Note: if we do not put the IE, Marvell STA will decline
* our TDLS setup request
*/
u4IeLen = rlmDomainSupOperatingClassIeFill(pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
/* 3.10 Extended Capabilities */
EXT_CAP_IE(pPkt)->ucId = ELEM_ID_EXTENDED_CAP;
EXT_CAP_IE(pPkt)->ucLength = 5;
EXT_CAP_IE(pPkt)->aucCapabilities[0] = 0x00; /* bit0 ~ bit7 */
EXT_CAP_IE(pPkt)->aucCapabilities[1] = 0x00; /* bit8 ~ bit15 */
EXT_CAP_IE(pPkt)->aucCapabilities[2] = 0x00; /* bit16 ~ bit23 */
EXT_CAP_IE(pPkt)->aucCapabilities[3] = 0x00; /* bit24 ~ bit31 */
EXT_CAP_IE(pPkt)->aucCapabilities[4] = 0x00; /* bit32 ~ bit39 */
EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((28 - 24));
EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((30 - 24));
EXT_CAP_IE(pPkt)->aucCapabilities[4] |= BIT((37 - 32));
u4IeLen = IE_SIZE(pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
/* Append extra IEs */
/*
* 3.9 RSNIE (optional)
* 3.12 FTIE (optional)
* 3.13 Timeout Interval (optional)
*/
if (pAppendIe != NULL) {
kalMemCopy(pPkt, pAppendIe, AppendIeLen);
LR_TDLS_FME_FIELD_FILL(AppendIeLen);
}
/* 3.11 QoS Capability */
/* HT WMM IE append */
if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucQoS)) {
u4IeLen = mqmGenerateWmmInfoIEByStaRec(prAdapter, prBssInfo,
prStaRec, pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
u4IeLen = mqmGenerateWmmParamIEByParam(prAdapter, prBssInfo,
pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
}
/* 3.15 HT Capabilities */
if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet &
PHY_TYPE_SET_802_11N)) {
u4IeLen = rlmFillHtCapIEByAdapter(prAdapter, prBssInfo, pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
}
#if CFG_SUPPORT_802_11AC
if (prAdapter->rWifiVar.ucAvailablePhyTypeSet &
PHY_TYPE_SET_802_11AC) {
u4IeLen = rlmFillVhtCapIEByAdapter(prAdapter, prBssInfo, pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
}
#endif
/* 3.16 20/40 BSS Coexistence */
BSS_20_40_COEXIST_IE(pPkt)->ucId = ELEM_ID_20_40_BSS_COEXISTENCE;
BSS_20_40_COEXIST_IE(pPkt)->ucLength = 1;
BSS_20_40_COEXIST_IE(pPkt)->ucData = 0x01;
LR_TDLS_FME_FIELD_FILL(3);
/* 3.17 Link Identifier */
TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER;
TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = 18;
kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID,
prBssInfo->aucBSSID, 6);
kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator,
prBssInfo->aucOwnMacAddr, 6);
kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder,
pPeerMac, 6);
u4IeLen = IE_SIZE(pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
/* 4. Update packet length */
prMsduInfo->len = u4PktLen;
DBGLOG(TDLS, INFO, "wlanHardStartXmit, u4PktLen=%d", u4PktLen);
/* 5. send the data frame */
wlanHardStartXmit(prMsduInfo, prMsduInfo->dev);
return TDLS_STATUS_SUCCESS;
}
uint32_t
TdlsDataFrameSend_SETUP_RSP(struct ADAPTER *prAdapter,
struct STA_RECORD *prStaRec,
uint8_t *pPeerMac,
uint8_t ucActionCode,
uint8_t ucDialogToken, uint16_t u2StatusCode,
uint8_t *pAppendIe, uint32_t AppendIeLen)
{
struct GLUE_INFO *prGlueInfo;
struct BSS_INFO *prBssInfo;
struct PM_PROFILE_SETUP_INFO *prPmProfSetupInfo;
struct sk_buff *prMsduInfo;
uint8_t *pPkt;
uint32_t u4PktLen, u4IeLen;
uint16_t u2CapInfo;
/* allocate/init packet */
prGlueInfo = (struct GLUE_INFO *) prAdapter->prGlueInfo;
prBssInfo = prAdapter->prAisBssInfo;
prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo;
u4PktLen = 0;
if (prStaRec == NULL)
return TDLS_STATUS_FAIL;
prMsduInfo = kalPacketAllocWithHeadroom(prGlueInfo, 512, &pPkt);
if (prMsduInfo == NULL)
return TDLS_STATUS_RESOURCES;
prMsduInfo->dev = prGlueInfo->prDevHandler;
if (prMsduInfo->dev == NULL) {
kalPacketFree(prGlueInfo, prMsduInfo);
return TDLS_STATUS_FAIL;
}
/* make up frame content */
/* 1. 802.3 header */
kalMemCopy(pPkt, pPeerMac, TDLS_FME_MAC_ADDR_LEN);
LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN);
kalMemCopy(pPkt, prBssInfo->aucOwnMacAddr, TDLS_FME_MAC_ADDR_LEN);
LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN);
*(uint16_t *) pPkt = htons(TDLS_FRM_PROT_TYPE);
LR_TDLS_FME_FIELD_FILL(2);
/* 2. payload type */
*pPkt = TDLS_FRM_PAYLOAD_TYPE;
LR_TDLS_FME_FIELD_FILL(1);
/*
* 3.1 Category
* 3.2 Action
* 3.3 Status Code
* 3.4 Dialog Token
*** Below IE should be only included for Status Code=0 (Successful)
* 3.5 Capability
* 3.6 Supported rates
* 3.7 Country
* 3.8 Extended supported rates
* 3.9 Supported Channels (optional)
* 3.10 RSNIE (optional)
* 3.11 Extended Capabilities
* 3.12 QoS Capability
* 3.13 FTIE (optional)
* 3.14 Timeout Interval (optional)
* 3.15 Supported Regulatory Classes (optional)
* 3.16 HT Capabilities
* 3.17 20/40 BSS Coexistence
* 3.18 Link Identifier
*/
/* 3.1 Category */
*pPkt = TDLS_FRM_CATEGORY;
LR_TDLS_FME_FIELD_FILL(1);
/* 3.2 Action */
*pPkt = ucActionCode;
LR_TDLS_FME_FIELD_FILL(1);
/* 3.3 Status Code */
kalMemCopy(pPkt, &u2StatusCode, 2);
LR_TDLS_FME_FIELD_FILL(2);
/* 3.4 Dialog Token */
*pPkt = ucDialogToken;
LR_TDLS_FME_FIELD_FILL(1);
if (u2StatusCode == 0) {
/* 3.5 Capability */
u2CapInfo = assocBuildCapabilityInfo(prAdapter, prStaRec);
WLAN_SET_FIELD_16(pPkt, u2CapInfo);
LR_TDLS_FME_FIELD_FILL(2);
/*
* 3.6 Supported rates
* 3.8 Extended supported rates
* 3.9 Supported Channels (optional)
*/
u4IeLen = TdlsFrameGeneralIeAppend(prAdapter, prStaRec, pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
/* 3.7 Country */
/* 3.15 Supported Regulatory Classes (optional) */
/* Note: if we do not put the IE, Marvell STA will decline
* our TDLS setup request
*/
u4IeLen = rlmDomainSupOperatingClassIeFill(pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
/* 3.11 Extended Capabilities */
EXT_CAP_IE(pPkt)->ucId = ELEM_ID_EXTENDED_CAP;
EXT_CAP_IE(pPkt)->ucLength = 5;
EXT_CAP_IE(pPkt)->aucCapabilities[0] = 0x00; /* bit0 ~ bit7 */
EXT_CAP_IE(pPkt)->aucCapabilities[1] = 0x00; /* bit8 ~ bit15 */
EXT_CAP_IE(pPkt)->aucCapabilities[2] = 0x00; /* bit16 ~ bit23 */
EXT_CAP_IE(pPkt)->aucCapabilities[3] = 0x00; /* bit24 ~ bit31 */
EXT_CAP_IE(pPkt)->aucCapabilities[4] = 0x00; /* bit32 ~ bit39 */
EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((28 - 24));
EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((30 - 24));
EXT_CAP_IE(pPkt)->aucCapabilities[4] |= BIT((37 - 32));
u4IeLen = IE_SIZE(pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
/* 3.12 QoS Capability */
if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucQoS)) {
/* Add WMM IE *//* try to reuse p2p path */
u4IeLen = mqmGenerateWmmInfoIEByStaRec(prAdapter,
prBssInfo, prStaRec, pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
u4IeLen = mqmGenerateWmmParamIEByParam(prAdapter,
prBssInfo, pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
}
/* 3.16 HT Capabilities */
if (prAdapter->rWifiVar.ucAvailablePhyTypeSet &
PHY_TYPE_SET_802_11N) {
u4IeLen = rlmFillHtCapIEByAdapter(prAdapter, prBssInfo,
pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
}
#if CFG_SUPPORT_802_11AC
if (prAdapter->rWifiVar.ucAvailablePhyTypeSet &
PHY_TYPE_SET_802_11AC) {
u4IeLen = rlmFillVhtCapIEByAdapter(prAdapter, prBssInfo,
pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
}
#endif
/* 3.17 20/40 BSS Coexistence */
BSS_20_40_COEXIST_IE(pPkt)->ucId =
ELEM_ID_20_40_BSS_COEXISTENCE;
BSS_20_40_COEXIST_IE(pPkt)->ucLength = 1;
BSS_20_40_COEXIST_IE(pPkt)->ucData = 0x01;
LR_TDLS_FME_FIELD_FILL(3);
/* 3.18 Link Identifier */
TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER;
TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = 18;
kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID,
prBssInfo->aucBSSID, 6);
kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator,
pPeerMac, 6);
kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder,
prBssInfo->aucOwnMacAddr, 6);
u4IeLen = IE_SIZE(pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
/* Append extra IEs */
/*
* 3.10 RSNIE (optional)
* 3.13 FTIE (optional)
* 3.14 Timeout Interval (optional)
*/
if (pAppendIe != NULL) {
kalMemCopy(pPkt, pAppendIe, AppendIeLen);
LR_TDLS_FME_FIELD_FILL(AppendIeLen);
}
}
/* 4. Update packet length */
prMsduInfo->len = u4PktLen;
/* 5. send the data frame */
wlanHardStartXmit(prMsduInfo, prMsduInfo->dev);
return TDLS_STATUS_SUCCESS;
}
uint32_t
TdlsDataFrameSend_CONFIRM(struct ADAPTER *prAdapter,
struct STA_RECORD *prStaRec,
uint8_t *pPeerMac,
uint8_t ucActionCode,
uint8_t ucDialogToken, uint16_t u2StatusCode,
uint8_t *pAppendIe, uint32_t AppendIeLen)
{
struct GLUE_INFO *prGlueInfo;
struct BSS_INFO *prBssInfo;
struct PM_PROFILE_SETUP_INFO *prPmProfSetupInfo;
struct sk_buff *prMsduInfo;
uint8_t *pPkt;
uint32_t u4PktLen, u4IeLen;
/* allocate/init packet */
prGlueInfo = (struct GLUE_INFO *) prAdapter->prGlueInfo;
prBssInfo = prAdapter->prAisBssInfo;
prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo;
u4PktLen = 0;
prMsduInfo = kalPacketAllocWithHeadroom(prGlueInfo, 512, &pPkt);
if (prMsduInfo == NULL)
return TDLS_STATUS_RESOURCES;
prMsduInfo->dev = prGlueInfo->prDevHandler;
if (prMsduInfo->dev == NULL) {
kalPacketFree(prGlueInfo, prMsduInfo);
return TDLS_STATUS_FAIL;
}
/* make up frame content */
/* 1. 802.3 header */
kalMemCopy(pPkt, pPeerMac, TDLS_FME_MAC_ADDR_LEN);
LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN);
kalMemCopy(pPkt, prBssInfo->aucOwnMacAddr, TDLS_FME_MAC_ADDR_LEN);
LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN);
*(uint16_t *) pPkt = htons(TDLS_FRM_PROT_TYPE);
LR_TDLS_FME_FIELD_FILL(2);
/* 2. payload type */
*pPkt = TDLS_FRM_PAYLOAD_TYPE;
LR_TDLS_FME_FIELD_FILL(1);
/*
* 3.1 Category
* 3.2 Action
* 3.3 Status Code
* 3.4 Dialog Token
*** 3.5 - 3.9 should be only included for Status Code=0 (Successful)
* 3.5 RSNIE (optional)
* 3.6 EDCA Parameter Set
* 3.7 FTIE (optional)
* 3.8 Timeout Interval (optional)
* 3.9 HT Operation (optional)
* 3.10 Link Identifier
*/
/* 3.1 Category */
*pPkt = TDLS_FRM_CATEGORY;
LR_TDLS_FME_FIELD_FILL(1);
/* 3.2 Action */
*pPkt = ucActionCode;
LR_TDLS_FME_FIELD_FILL(1);
/* 3.3 Status Code */
kalMemCopy(pPkt, &u2StatusCode, 2);
LR_TDLS_FME_FIELD_FILL(2);
/* 3.4 Dialog Token */
*pPkt = ucDialogToken;
LR_TDLS_FME_FIELD_FILL(1);
if (u2StatusCode == 0) {
/*
* 3.5 RSNIE (optional)
* 3.7 FTIE (optional)
* 3.8 Timeout Interval (optional)
*/
if (pAppendIe) {
kalMemCopy(pPkt, pAppendIe, AppendIeLen);
LR_TDLS_FME_FIELD_FILL(AppendIeLen);
}
/* 3.6 EDCA Parameter Set */
/* HT WMM IE append */
if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucQoS)) {
u4IeLen = mqmGenerateWmmInfoIEByStaRec(prAdapter,
prBssInfo, prStaRec, pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
u4IeLen = mqmGenerateWmmParamIEByParam(prAdapter,
prBssInfo, pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
}
}
/* 3.10 Link Identifier */
TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER;
TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = 18;
kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID,
prBssInfo->aucBSSID, 6);
kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator,
prBssInfo->aucOwnMacAddr, 6);
kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder,
pPeerMac, 6);
u4IeLen = IE_SIZE(pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
/* 4. Update packet length */
prMsduInfo->len = u4PktLen;
/* 5. send the data frame */
wlanHardStartXmit(prMsduInfo, prMsduInfo->dev);
return TDLS_STATUS_SUCCESS;
}
/*
* \brief This routine is called to transmit a TDLS data frame.
*
* \param[in] pvAdapter Pointer to the Adapter structure.
* \param[in]
* \param[in]
* \param[in] buf includes RSN IE + FT IE + Lifetimeout IE
*
* \retval WLAN_STATUS_SUCCESS
* \retval WLAN_STATUS_INVALID_LENGTH
*/
/*----------------------------------------------------------------------------*/
uint32_t /* TDLS_STATUS */
TdlsDataFrameSend_DISCOVERY_REQ(struct ADAPTER *prAdapter,
struct STA_RECORD *prStaRec,
uint8_t *pPeerMac,
uint8_t ucActionCode,
uint8_t ucDialogToken, uint16_t u2StatusCode,
uint8_t *pAppendIe, uint32_t AppendIeLen)
{
struct GLUE_INFO *prGlueInfo;
struct BSS_INFO *prBssInfo;
struct PM_PROFILE_SETUP_INFO *prPmProfSetupInfo;
struct sk_buff *prMsduInfo;
struct MSDU_INFO *prMsduInfoMgmt;
uint8_t *pPkt, *pucInitiator, *pucResponder;
uint32_t u4PktLen, u4IeLen;
prGlueInfo = (struct GLUE_INFO *) prAdapter->prGlueInfo;
if (prStaRec != NULL)
prBssInfo = prAdapter->prAisBssInfo;
else
return TDLS_STATUS_FAIL;
/* allocate/init packet */
prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo;
u4PktLen = 0;
prMsduInfo = NULL;
prMsduInfoMgmt = NULL;
/* make up frame content */
prMsduInfo = kalPacketAllocWithHeadroom(prGlueInfo, 512, &pPkt);
if (prMsduInfo == NULL)
return TDLS_STATUS_RESOURCES;
prMsduInfo->dev = prGlueInfo->prDevHandler;
if (prMsduInfo->dev == NULL) {
kalPacketFree(prGlueInfo, prMsduInfo);
return TDLS_STATUS_FAIL;
}
/* 1. 802.3 header */
kalMemCopy(pPkt, pPeerMac, TDLS_FME_MAC_ADDR_LEN);
LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN);
kalMemCopy(pPkt, prBssInfo->aucOwnMacAddr, TDLS_FME_MAC_ADDR_LEN);
LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN);
*(uint16_t *) pPkt = htons(TDLS_FRM_PROT_TYPE);
LR_TDLS_FME_FIELD_FILL(2);
/* 2. payload type */
*pPkt = TDLS_FRM_PAYLOAD_TYPE;
LR_TDLS_FME_FIELD_FILL(1);
/*
* 3.1 Category
* 3.2 Action
* 3.3 Dialog Token
* 3.4 Link Identifier
*/
/* 3.1 Category */
*pPkt = TDLS_FRM_CATEGORY;
LR_TDLS_FME_FIELD_FILL(1);
/* 3.2 Action */
*pPkt = ucActionCode;
LR_TDLS_FME_FIELD_FILL(1);
/* 3.3 Dialog Token */
*pPkt = ucDialogToken;
LR_TDLS_FME_FIELD_FILL(1);
/* 3.4 Link Identifier */
TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER;
TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = 18;
kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID,
prBssInfo->aucBSSID, 6);
pucInitiator = prBssInfo->aucOwnMacAddr;
pucResponder = pPeerMac;
prStaRec->flgTdlsIsInitiator = TRUE;
kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, pucInitiator, 6);
kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, pucResponder, 6);
u4IeLen = IE_SIZE(pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
/* 4. Update packet length */
prMsduInfo->len = u4PktLen;
/* 5. send the data frame */
wlanHardStartXmit(prMsduInfo, prMsduInfo->dev);
return TDLS_STATUS_SUCCESS;
}
uint32_t
TdlsDataFrameSend_DISCOVERY_RSP(struct ADAPTER *prAdapter,
struct STA_RECORD *prStaRec,
uint8_t *pPeerMac,
uint8_t ucActionCode,
uint8_t ucDialogToken, uint16_t u2StatusCode,
uint8_t *pAppendIe, uint32_t AppendIeLen)
{
struct GLUE_INFO *prGlueInfo;
struct BSS_INFO *prBssInfo;
struct PM_PROFILE_SETUP_INFO *prPmProfSetupInfo;
struct MSDU_INFO *prMsduInfoMgmt;
uint8_t *pPkt, *pucInitiator, *pucResponder;
uint32_t u4PktLen, u4IeLen;
uint16_t u2CapInfo;
struct WLAN_MAC_HEADER *prHdr;
prGlueInfo = (struct GLUE_INFO *) prAdapter->prGlueInfo;
/* sanity check */
if (prStaRec != NULL)
prBssInfo = prAdapter->prAisBssInfo;
else
return TDLS_STATUS_FAIL;
/* allocate/init packet */
prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo;
u4PktLen = 0;
prMsduInfoMgmt = NULL;
/* make up frame content */
prMsduInfoMgmt = (struct MSDU_INFO *) cnmMgtPktAlloc(prAdapter,
PUBLIC_ACTION_MAX_LEN);
if (prMsduInfoMgmt == NULL)
return TDLS_STATUS_RESOURCES;
pPkt = (uint8_t *) prMsduInfoMgmt->prPacket;
prHdr = (struct WLAN_MAC_HEADER *) pPkt;
/* 1. 802.11 header */
prHdr->u2FrameCtrl = MAC_FRAME_ACTION;
prHdr->u2DurationID = 0;
kalMemCopy(prHdr->aucAddr1, pPeerMac, TDLS_FME_MAC_ADDR_LEN);
kalMemCopy(prHdr->aucAddr2, prBssInfo->aucOwnMacAddr,
TDLS_FME_MAC_ADDR_LEN);
kalMemCopy(prHdr->aucAddr3, prBssInfo->aucBSSID, TDLS_FME_MAC_ADDR_LEN);
prHdr->u2SeqCtrl = 0;
LR_TDLS_FME_FIELD_FILL(sizeof(struct WLAN_MAC_HEADER));
/*
* 3.1 Category
* 3.2 Action
* 3.3 Dialog Token
* 3.4 Capability
* 3.5 Supported rates
* 3.6 Extended supported rates
* 3.7 Supported Channels (optional)
* 3.8 RSNIE
* 3.9 Extended Capabilities
* 3.10 FTIE
* 3.11 Timeout Interval (optional)
* 3.12 Supported Regulatory Classes (optional)
* 3.13 HT Capabilities
* 3.14 20/40 BSS Coexistence
* 3.15 Link Identifier
*/
/* 3.1 Category */
*pPkt = CATEGORY_PUBLIC_ACTION;
LR_TDLS_FME_FIELD_FILL(1);
/* 3.2 Action */
*pPkt = ucActionCode;
LR_TDLS_FME_FIELD_FILL(1);
/* 3.3 Dialog Token */
*pPkt = ucDialogToken;
LR_TDLS_FME_FIELD_FILL(1);
/* 3.4 Capability */
u2CapInfo = assocBuildCapabilityInfo(prAdapter, prStaRec);
WLAN_SET_FIELD_16(pPkt, u2CapInfo);
LR_TDLS_FME_FIELD_FILL(2);
/*
* 3.5 Supported rates
* 3.6 Extended supported rates
* 3.7 Supported Channels (optional)
*/
u4IeLen = TdlsFrameGeneralIeAppend(prAdapter, prStaRec, pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
/* 3.9 Extended Capabilities */
EXT_CAP_IE(pPkt)->ucId = ELEM_ID_EXTENDED_CAP;
EXT_CAP_IE(pPkt)->ucLength = 5;
EXT_CAP_IE(pPkt)->aucCapabilities[0] = 0x00; /* bit0 ~ bit7 */
EXT_CAP_IE(pPkt)->aucCapabilities[1] = 0x00; /* bit8 ~ bit15 */
EXT_CAP_IE(pPkt)->aucCapabilities[2] = 0x00; /* bit16 ~ bit23 */
EXT_CAP_IE(pPkt)->aucCapabilities[3] = 0x00; /* bit24 ~ bit31 */
EXT_CAP_IE(pPkt)->aucCapabilities[4] = 0x00; /* bit32 ~ bit39 */
/* bit 28 TDLS_EX_CAP_PEER_UAPSD */
EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((28 - 24));
/* bit 30 TDLS_EX_CAP_CHAN_SWITCH */
EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((30 - 24));
/* bit 37 TDLS_EX_CAP_TDLS */
EXT_CAP_IE(pPkt)->aucCapabilities[4] |= BIT((37 - 32));
u4IeLen = IE_SIZE(pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
/*
* 3.8 RSNIE
* 3.10 FTIE
* 3.11 Timeout Interval (optional)
*/
if (pAppendIe != NULL) {
kalMemCopy(pPkt, pAppendIe, AppendIeLen);
LR_TDLS_FME_FIELD_FILL(AppendIeLen);
}
/* 3.12 Supported Regulatory Classes (optional) */
/* Note: if we do not put the IE, Marvell STA will
* decline our TDLS setup request
*/
u4IeLen = rlmDomainSupOperatingClassIeFill(pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
/* 3.13 HT Capabilities */
if (prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11N) {
u4IeLen = rlmFillHtCapIEByAdapter(prAdapter, prBssInfo, pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
}
#if CFG_SUPPORT_802_11AC
if (prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11AC) {
u4IeLen = rlmFillVhtCapIEByAdapter(prAdapter, prBssInfo, pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
}
#endif
/* 3.14 20/40 BSS Coexistence */
BSS_20_40_COEXIST_IE(pPkt)->ucId = ELEM_ID_20_40_BSS_COEXISTENCE;
BSS_20_40_COEXIST_IE(pPkt)->ucLength = 1;
BSS_20_40_COEXIST_IE(pPkt)->ucData = 0x01;
LR_TDLS_FME_FIELD_FILL(3);
/* 3.15 Link Identifier */
TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER;
TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = 18;
kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID,
prBssInfo->aucBSSID, 6);
kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator,
pPeerMac, 6);
kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder,
prBssInfo->aucOwnMacAddr, 6);
u4IeLen = IE_SIZE(pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
pucInitiator = pPeerMac;
pucResponder = prBssInfo->aucOwnMacAddr;
if (prStaRec != NULL)
prStaRec->flgTdlsIsInitiator = FALSE;
if (prMsduInfoMgmt != NULL) {
prMsduInfoMgmt->ucPacketType = TX_PACKET_TYPE_MGMT;
prMsduInfoMgmt->ucStaRecIndex =
prBssInfo->prStaRecOfAP->ucIndex;
prMsduInfoMgmt->ucBssIndex = prBssInfo->ucBssIndex;
prMsduInfoMgmt->ucMacHeaderLength =
WLAN_MAC_MGMT_HEADER_LEN;
prMsduInfoMgmt->fgIs802_1x = FALSE;
prMsduInfoMgmt->fgIs802_11 = TRUE;
prMsduInfoMgmt->u2FrameLength = u4PktLen;
prMsduInfoMgmt->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter);
prMsduInfoMgmt->pfTxDoneHandler = NULL;
/* Send them to HW queue */
nicTxEnqueueMsdu(prAdapter, prMsduInfoMgmt);
}
return TDLS_STATUS_SUCCESS;
}
/*----------------------------------------------------------------------------*/
/*! \brief This routine is called to send a command to TDLS module.
*
* \param[in] prGlueInfo Pointer to the Adapter structure
* \param[in] prInBuf A pointer to the command string buffer
* \param[in] u4InBufLen The length of the buffer
* \param[out] None
*
* \retval None
*/
/*----------------------------------------------------------------------------*/
void TdlsexEventHandle(struct GLUE_INFO *prGlueInfo,
uint8_t *prInBuf, uint32_t u4InBufLen)
{
uint32_t u4EventId;
DBGLOG(TDLS, INFO, "TdlsexEventHandle\n");
/* sanity check */
if ((prGlueInfo == NULL) || (prInBuf == NULL))
return; /* shall not be here */
/* handle */
u4EventId = *(uint32_t *) prInBuf;
u4InBufLen -= 4;
switch (u4EventId) {
case TDLS_HOST_EVENT_TEAR_DOWN:
DBGLOG(TDLS, INFO, "TDLS_HOST_EVENT_TEAR_DOWN\n");
TdlsEventTearDown(prGlueInfo, prInBuf + 4, u4InBufLen);
break;
case TDLS_HOST_EVENT_TX_DONE:
break;
}
}
/*----------------------------------------------------------------------------*/
/*! \brief This routine is called to do tear down.
*
* \param[in] prGlueInfo Pointer to the Adapter structure
* \param[in] prInBuf A pointer to the command string buffer,
* from u4EventSubId
* \param[in] u4InBufLen The length of the buffer
* \param[out] None
*
* \retval None
*
*/
/*----------------------------------------------------------------------------*/
void TdlsEventTearDown(struct GLUE_INFO *prGlueInfo,
uint8_t *prInBuf, uint32_t u4InBufLen)
{
struct STA_RECORD *prStaRec;
uint16_t u2ReasonCode = TDLS_REASON_CODE_NONE;
uint32_t u4TearDownSubId;
uint8_t *pMac, aucZeroMac[6];
/* init */
u4TearDownSubId = *(uint32_t *) prInBuf;
kalMemZero(aucZeroMac, sizeof(aucZeroMac));
pMac = aucZeroMac;
prStaRec = cnmGetStaRecByIndex(prGlueInfo->prAdapter,
*(prInBuf + 4));
/* sanity check */
if (prStaRec == NULL)
return;
pMac = prStaRec->aucMacAddr;
if (fgIsPtiTimeoutSkip == TRUE) {
/* skip PTI timeout event */
if (u4TearDownSubId == TDLS_HOST_EVENT_TD_PTI_TIMEOUT)
return;
}
if (u4TearDownSubId == TDLS_HOST_EVENT_TD_PTI_TIMEOUT) {
DBGLOG(TDLS, INFO,
"TDLS_HOST_EVENT_TD_PTI_TIMEOUT TDLS_REASON_CODE_UNSPECIFIED\n");
u2ReasonCode = TDLS_REASON_CODE_UNSPECIFIED;
cfg80211_tdls_oper_request(prGlueInfo->prDevHandler,
prStaRec->aucMacAddr,
NL80211_TDLS_TEARDOWN,
WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE,
GFP_ATOMIC);
}
if (u4TearDownSubId == TDLS_HOST_EVENT_TD_AGE_TIMEOUT) {
DBGLOG(TDLS, INFO,
"TDLS_HOST_EVENT_TD_AGE_TIMEOUT TDLS_REASON_CODE_UNREACHABLE\n");
u2ReasonCode = TDLS_REASON_CODE_UNREACHABLE;
cfg80211_tdls_oper_request(prGlueInfo->prDevHandler,
prStaRec->aucMacAddr, NL80211_TDLS_TEARDOWN,
WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE,
GFP_ATOMIC);
}
DBGLOG(TDLS, INFO, "\n\n u2ReasonCode = %u\n\n",
u2ReasonCode);
}
void TdlsBssExtCapParse(struct STA_RECORD *prStaRec,
uint8_t *pucIE)
{
uint8_t *pucIeExtCap;
/* sanity check */
if ((prStaRec == NULL) || (pucIE == NULL))
return;
if (IE_ID(pucIE) != ELEM_ID_EXTENDED_CAP)
return;
/*
* from bit0 ~
* bit 38: TDLS Prohibited
* The TDLS Prohibited subfield indicates whether the use of TDLS is
* prohibited.
* The field is set to 1 to indicate that TDLS is prohibited
* and to 0 to indicate that TDLS is allowed.
*/
if (IE_LEN(pucIE) < 5)
return; /* we need 39/8 = 5 bytes */
/* init */
prStaRec->fgTdlsIsProhibited = FALSE;
prStaRec->fgTdlsIsChSwProhibited = FALSE;
/* parse */
pucIeExtCap = pucIE + 2;
pucIeExtCap += 4; /* shift to the byte we care about */
if ((*pucIeExtCap) & BIT(38 - 32))
prStaRec->fgTdlsIsProhibited = TRUE;
if ((*pucIeExtCap) & BIT(39 - 32))
prStaRec->fgTdlsIsChSwProhibited = TRUE;
}
/*----------------------------------------------------------------------------*/
/*!
* \brief Generate CMD_ID_SET_TDLS_CH_SW command
*
* \param[in]
*
* \return none
*/
/*----------------------------------------------------------------------------*/
uint32_t
TdlsSendChSwControlCmd(struct ADAPTER *prAdapter,
void *pvSetBuffer, uint32_t u4SetBufferLen,
uint32_t *pu4SetInfoLen)
{
struct CMD_TDLS_CH_SW rCmdTdlsChSwCtrl;
ASSERT(prAdapter);
/* send command packet for scan */
kalMemZero(&rCmdTdlsChSwCtrl,
sizeof(struct CMD_TDLS_CH_SW));
rCmdTdlsChSwCtrl.fgIsTDLSChSwProhibit =
prAdapter->prAisBssInfo->fgTdlsIsChSwProhibited;
wlanSendSetQueryCmd(prAdapter,
CMD_ID_SET_TDLS_CH_SW,
TRUE,
FALSE, FALSE, NULL, NULL,
sizeof(struct CMD_TDLS_CH_SW),
(uint8_t *)&rCmdTdlsChSwCtrl, NULL, 0);
return TDLS_STATUS_SUCCESS;
}
uint32_t
TdlsTxCtrl(struct ADAPTER *prAdapter,
struct BSS_INFO *prBssInfo, u_int8_t fgEnable)
{
int i;
struct STA_RECORD *prStaRec;
for (i = 0; i < CFG_STA_REC_NUM; i++) {
prStaRec = &prAdapter->arStaRec[i];
if (prStaRec->eStaType != STA_TYPE_DLS_PEER)
continue;
if (prStaRec->fgIsInUse && prStaRec->ucBssIndex
== prBssInfo->ucBssIndex) {
qmSetStaRecTxAllowed(prAdapter, prStaRec, fgEnable);
DBGLOG(TDLS, EVENT, "TDLS STA[%d], TX ctrl=%d\n",
i, fgEnable);
}
}
return TDLS_STATUS_SUCCESS;
}
#endif /* CFG_SUPPORT_TDLS */
/* End of tdls.c */