blob: 25d93febc41ec8a5387e236df00ab5ce683e2e1e [file] [log] [blame]
/******************************************************************************
*
* 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
********************************************************************************
*/
/* The list of valid data rates. */
/* The list of valid data rates. */
/*******************************************************************************
* F U N C T I O N D E C L A R A T I O N S
********************************************************************************
*/
/*******************************************************************************
* P R I V A T E D A T A
********************************************************************************
*/
static BOOLEAN fgIsPtiTimeoutSkip = FALSE;
/*******************************************************************************
* P R I V A T E F U N C T I O N 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
UINT_8 g_arTdlsLink[MAXNUM_TDLS_PEER] = {
0,
0,
0,
0
};
/*----------------------------------------------------------------------------*/
/*!
* \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
*/
/*----------------------------------------------------------------------------*/
UINT_32 TdlsexLinkMgt(P_ADAPTER_T prAdapter, PVOID pvSetBuffer, UINT_32 u4SetBufferLen, PUINT_32 pu4SetInfoLen)
{
/* from supplicant -- wpa_supplicant_tdls_peer_addset() */
STA_RECORD_T *prStaRec;
P_BSS_INFO_T prBssInfo;
TDLS_CMD_LINK_MGT_T *prCmd;
prCmd = (TDLS_CMD_LINK_MGT_T *) pvSetBuffer;
prBssInfo = prAdapter->prAisBssInfo;
/* printk("\n\n\n TdlsexLinkMgt\n\n\n"); */
#if 1
/* AIS only */
if (prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) {
prStaRec = prBssInfo->prStaRecOfAP;
if (prStaRec == NULL)
return 0;
} else {
return -EINVAL;
}
#endif
switch (prCmd->ucActionCode) {
case TDLS_FRM_ACTION_DISCOVERY_REQ:
/* printk("\n\n\n TDLS_FRM_ACTION_DISCOVERY_REQ\n\n\n"); */
if (TdlsDataFrameSend_DISCOVERY_REQ(prAdapter,
prStaRec,
prCmd->aucPeer,
prCmd->ucActionCode,
prCmd->ucDialogToken,
prCmd->u2StatusCode,
(UINT_8 *) (prCmd->aucSecBuf),
prCmd->u4SecBufLen) != TDLS_STATUS_SUCCESS) {
return -1;
}
break;
case TDLS_FRM_ACTION_SETUP_REQ:
/* printk("\n\n\n TDLS_FRM_ACTION_SETUP_REQ\n\n\n"); */
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,
(UINT_8 *) (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;
/* printk("\n\n\n TDLS_FRM_ACTION_SETUP_RSP\n\n\n"); */
if (TdlsDataFrameSend_SETUP_RSP(prAdapter,
prStaRec,
prCmd->aucPeer,
prCmd->ucActionCode,
prCmd->ucDialogToken,
prCmd->u2StatusCode,
(UINT_8 *) (prCmd->aucSecBuf),
prCmd->u4SecBufLen) != TDLS_STATUS_SUCCESS) {
return -1;
}
break;
case TDLS_FRM_ACTION_DISCOVERY_RSP:
/* printk("\n\n\n TDLS_FRM_ACTION_DISCOVERY_RSP\n\n\n"); */
if (TdlsDataFrameSend_DISCOVERY_RSP(prAdapter,
prStaRec,
prCmd->aucPeer,
prCmd->ucActionCode,
prCmd->ucDialogToken,
prCmd->u2StatusCode,
(UINT_8 *) (prCmd->aucSecBuf),
prCmd->u4SecBufLen) != TDLS_STATUS_SUCCESS) {
return -1;
}
break;
case TDLS_FRM_ACTION_CONFIRM:
/* printk("\n\n\n TDLS_FRM_ACTION_CONFIRM\n\n\n"); */
if (TdlsDataFrameSend_CONFIRM(prAdapter,
prStaRec,
prCmd->aucPeer,
prCmd->ucActionCode,
prCmd->ucDialogToken,
prCmd->u2StatusCode,
(UINT_8 *) (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) {
/* printk("\n\n\n u2StatusCode == TDLS_REASON_CODE_UNREACHABLE\n\n\n"); */
g_arTdlsLink[prStaRec->ucTdlsIndex] = 0;
}
/* printk("\n\n\n TDLS_FRM_ACTION_TEARDOWN\n\n\n"); */
if (TdlsDataFrameSend_TearDown(prAdapter,
prStaRec,
prCmd->aucPeer,
prCmd->ucActionCode,
prCmd->ucDialogToken,
prCmd->u2StatusCode,
(UINT_8 *) (prCmd->aucSecBuf),
prCmd->u4SecBufLen) != TDLS_STATUS_SUCCESS) {
/* printk("\n teardown frrame send failure\n"); */
return -1;
}
break;
default:
/* printk("\n\n\n default\n\n\n"); */
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
*/
/*----------------------------------------------------------------------------*/
UINT_32 TdlsexLinkOper(P_ADAPTER_T prAdapter, PVOID pvSetBuffer, UINT_32 u4SetBufferLen, PUINT_32 pu4SetInfoLen)
{
/* printk("TdlsexLinkOper\n"); */
/* from supplicant -- wpa_supplicant_tdls_peer_addset() */
UINT_16 i;
STA_RECORD_T *prStaRec;
TDLS_CMD_LINK_OPER_T *prCmd;
prCmd = (TDLS_CMD_LINK_OPER_T *) pvSetBuffer;
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;
}
}
/* printk("TDLS_ENABLE_LINK %d\n", i); */
break;
case TDLS_DISABLE_LINK:
prStaRec = cnmGetTdlsPeerByAddress(prAdapter, prAdapter->prAisBssInfo->ucBssIndex, prCmd->aucPeerMac);
/* printk("TDLS_ENABLE_LINK %d\n", prStaRec->ucTdlsIndex); */
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
*/
/*----------------------------------------------------------------------------*/
UINT_32 TdlsFrameGeneralIeAppend(ADAPTER_T *prAdapter, STA_RECORD_T *prStaRec, UINT_8 *pPkt)
{
GLUE_INFO_T *prGlueInfo;
BSS_INFO_T *prBssInfo;
PM_PROFILE_SETUP_INFO_T *prPmProfSetupInfo;
UINT_32 u4NonHTPhyType;
UINT_16 u2SupportedRateSet;
UINT_8 aucAllSupportedRates[RATE_NUM_SW] = { 0 }; /* 6628 RATE_NUM -> 6630 RATE_NUM_SW */
UINT_8 ucAllSupportedRatesLen;
UINT_8 ucSupRatesLen;
UINT_8 ucExtSupRatesLen;
UINT_32 u4PktLen, u4IeLen;
/* init */
prGlueInfo = (GLUE_INFO_T *) 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;
}
/*******************************************************************************
* P U B L I C F U N C T I O N S
********************************************************************************
*/
/*!
* \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
*/
/*----------------------------------------------------------------------------*/
WLAN_STATUS
TdlsDataFrameSend_TearDown(ADAPTER_T *prAdapter,
STA_RECORD_T *prStaRec,
UINT_8 *pPeerMac,
UINT_8 ucActionCode,
UINT_8 ucDialogToken, UINT_16 u2StatusCode, UINT_8 *pAppendIe, UINT_32 AppendIeLen)
{
GLUE_INFO_T *prGlueInfo;
BSS_INFO_T *prBssInfo;
PM_PROFILE_SETUP_INFO_T *prPmProfSetupInfo;
struct sk_buff *prMsduInfo;
UINT_8 *pPkt;
UINT_32 u4PktLen, u4IeLen;
UINT_16 ReasonCode;
/* allocate/init packet */
prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo;
prBssInfo = prAdapter->prAisBssInfo; /* AIS only */
prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo;
u4PktLen = 0;
prMsduInfo = kalPacketAlloc(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);
pPkt += TDLS_FME_MAC_ADDR_LEN;
kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN);
pPkt += TDLS_FME_MAC_ADDR_LEN;
*(UINT_16 *) 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;
/* printk("\n\n ReasonCode = %u\n\n",ReasonCode ); */
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, prAdapter->rMyMacAddr, 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; */
/* } */
/* printk(" TdlsDataFrameSend_TearDown !!\n"); */
/* 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
*/
/*----------------------------------------------------------------------------*/
WLAN_STATUS /* TDLS_STATUS */
TdlsDataFrameSend_SETUP_REQ(ADAPTER_T *prAdapter,
STA_RECORD_T *prStaRec,
UINT_8 *pPeerMac,
UINT_8 ucActionCode,
UINT_8 ucDialogToken, UINT_16 u2StatusCode, UINT_8 *pAppendIe, UINT_32 AppendIeLen)
{
GLUE_INFO_T *prGlueInfo;
BSS_INFO_T *prBssInfo;
PM_PROFILE_SETUP_INFO_T *prPmProfSetupInfo;
struct sk_buff *prMsduInfo;
UINT_8 *pPkt;
UINT_32 u4PktLen, u4IeLen;
BOOLEAN fg40mAllowed;
UINT_16 u2CapInfo;
/* allocate/init packet */
prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo;
prBssInfo = prAdapter->prAisBssInfo; /* AIS only */
prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo;
u4PktLen = 0;
prMsduInfo = kalPacketAlloc(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);
pPkt += TDLS_FME_MAC_ADDR_LEN;
kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN);
pPkt += TDLS_FME_MAC_ADDR_LEN;
*(UINT_16 *) 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 - (3) Dialog token */
*pPkt = ucDialogToken;
pPkt++;
u4PktLen++;
/* 3. Frame Formation - (4) Capability */
u2CapInfo = assocBuildCapabilityInfo(prAdapter, prStaRec);
WLAN_SET_FIELD_16(pPkt, u2CapInfo);
pPkt = pPkt + 2;
u4PktLen = u4PktLen + 2;
/* 4. Append general IEs */
u4IeLen = TdlsFrameGeneralIeAppend(prAdapter, prStaRec, pPkt);
pPkt += u4IeLen;
u4PktLen += u4IeLen;
/* 4. Append extra IEs */
kalMemCopy(pPkt, pAppendIe, AppendIeLen);
pPkt += AppendIeLen;
u4PktLen += AppendIeLen;
/* 3. Frame Formation - (10) Extended capabilities element */
EXT_CAP_IE(pPkt)->ucId = ELEM_ID_EXTENDED_CAP;
EXT_CAP_IE(pPkt)->ucLength = 5;
/* 0320 !! */
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] = 0xFF; /* 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));
/* EXT_CAP_IE(pPkt)->aucCapabilities[3] = 0x00; *//* bit24 ~ bit31 */
u4IeLen = IE_SIZE(pPkt);
pPkt += u4IeLen;
u4PktLen += u4IeLen;
/* HT capability IE append 0122 */
HT_CAP_IE(pPkt)->ucId = ELEM_ID_HT_CAP;
HT_CAP_IE(pPkt)->ucLength = 26;
/* 3. Frame Formation - (14) HT capabilities element */
if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11N)) {
/* TODO: prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode */
if (cnmBss40mBwPermitted(prAdapter, prBssInfo->ucBssIndex))
fg40mAllowed = TRUE;
else
fg40mAllowed = FALSE;
/* Add HT IE *//* try to reuse p2p path */
u4IeLen = rlmFillHtCapIEByAdapter(prAdapter, prBssInfo, pPkt);
pPkt += u4IeLen;
u4PktLen += u4IeLen;
/* 0320 !! check newest driver !!! */
}
/* check */
/* 3. Frame Formation - (12) Timeout interval element (TPK Key Lifetime) */
TIMEOUT_INTERVAL_IE(pPkt)->ucId = ELEM_ID_TIMEOUT_INTERVAL;
TIMEOUT_INTERVAL_IE(pPkt)->ucLength = 5;
TIMEOUT_INTERVAL_IE(pPkt)->ucType = 2; /* IE_TIMEOUT_INTERVAL_TYPE_KEY_LIFETIME; */
TIMEOUT_INTERVAL_IE(pPkt)->u4Value = TDLS_KEY_TIMEOUT_INTERVAL; /* htonl(prCmd->u4Timeout); */
u4IeLen = IE_SIZE(pPkt);
pPkt += u4IeLen;
u4PktLen += u4IeLen;
if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) {
/*
* bit0 = 1: The Information Request field is used to indicate that a
* transmitting STA is requesting the recipient to transmit a 20/40 BSS
* Coexistence Management frame with the transmitting STA as the
* recipient.
* bit1 = 0: The Forty MHz Intolerant field is set to 1 to prohibit an AP
* that receives this information or reports of this information from
* operating a 20/40 MHz BSS.
* bit2 = 0: The 20 MHz BSS Width Request field is set to 1 to prohibit
* a receiving AP from operating its BSS as a 20/40 MHz BSS.
*/
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);
}
if (pAppendIe != 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, prAdapter->rMyMacAddr, 6);
kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, pPeerMac, 6);
u4IeLen = IE_SIZE(pPkt);
pPkt += u4IeLen;
u4PktLen += u4IeLen;
/* 3. Frame Formation - (17) WMM Information element */
/* HT WMM IE append */
if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucQoS)) {
/* Add WMM IE *//* try to reuse p2p path */
u4IeLen = mqmGenerateWmmInfoIEByStaRec(prAdapter, prBssInfo, prStaRec, pPkt);
pPkt += u4IeLen;
u4PktLen += u4IeLen;
}
if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucQoS)) {
u4IeLen = mqmGenerateWmmParamIEByParam(prAdapter, prBssInfo, pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
}
#if CFG_SUPPORT_802_11AC
if (prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11AC) {
/* Add VHT IE *//* try to reuse p2p path */
u4IeLen = rlmFillVhtCapIEByAdapter(prAdapter, prBssInfo, pPkt);
pPkt += u4IeLen;
u4PktLen += u4IeLen;
}
#endif
/* 5. Update packet length */
prMsduInfo->len = u4PktLen;
DBGLOG(TDLS, INFO, "\n\n\n wlanHardStartXmit\n\n\n");
/* 5. send the data frame */
wlanHardStartXmit(prMsduInfo, prMsduInfo->dev);
/* wlanTx ??? */
return TDLS_STATUS_SUCCESS;
}
WLAN_STATUS
TdlsDataFrameSend_SETUP_RSP(ADAPTER_T *prAdapter,
STA_RECORD_T *prStaRec,
UINT_8 *pPeerMac,
UINT_8 ucActionCode,
UINT_8 ucDialogToken, UINT_16 u2StatusCode, UINT_8 *pAppendIe, UINT_32 AppendIeLen)
{
GLUE_INFO_T *prGlueInfo;
BSS_INFO_T *prBssInfo;
PM_PROFILE_SETUP_INFO_T *prPmProfSetupInfo;
struct sk_buff *prMsduInfo;
UINT_8 *pPkt;
UINT_32 u4PktLen, u4IeLen;
UINT_16 u2CapInfo;
UINT_16 StatusCode;
BOOLEAN fg40mAllowed;
/* allocate/init packet */
prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo;
prBssInfo = prAdapter->prAisBssInfo; /* AIS only */
prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo;
u4PktLen = 0;
prMsduInfo = kalPacketAlloc(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);
pPkt += TDLS_FME_MAC_ADDR_LEN;
kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN);
pPkt += TDLS_FME_MAC_ADDR_LEN;
*(UINT_16 *) 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 */
StatusCode = u2StatusCode;
kalMemCopy(pPkt, &StatusCode, 2);
pPkt = pPkt + 2;
u4PktLen = u4PktLen + 2;
/* 3. Frame Formation - (3) Dialog token */
*pPkt = ucDialogToken;
pPkt++;
u4PktLen++;
/* 3. Frame Formation - (4) Capability */
u2CapInfo = assocBuildCapabilityInfo(prAdapter, prStaRec);
WLAN_SET_FIELD_16(pPkt, u2CapInfo);
pPkt = pPkt + 2;
u4PktLen = u4PktLen + 2;
/* 4. Append general IEs */
u4IeLen = TdlsFrameGeneralIeAppend(prAdapter, prStaRec, pPkt);
pPkt += u4IeLen;
u4PktLen += u4IeLen;
/* 4. Append extra IEs */
kalMemCopy(pPkt, pAppendIe, AppendIeLen);
pPkt += AppendIeLen;
u4PktLen += AppendIeLen;
/* 3. Frame Formation - (10) Extended capabilities element */
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] = 0xFF; /* 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));
/* EXT_CAP_IE(pPkt)->aucCapabilities[3] = 0x00; *//* bit24 ~ bit31 */
u4IeLen = IE_SIZE(pPkt);
pPkt += u4IeLen;
u4PktLen += u4IeLen;
/* HT capability IE append */
HT_CAP_IE(pPkt)->ucId = ELEM_ID_HT_CAP;
HT_CAP_IE(pPkt)->ucLength = 26;
/* 3. Frame Formation - (14) HT capabilities element */
if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11N)) {
/* TODO: prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode */
if (cnmBss40mBwPermitted(prAdapter, prBssInfo->ucBssIndex))
fg40mAllowed = TRUE;
else
fg40mAllowed = FALSE;
/* Add HT IE *//* try to reuse p2p path */
u4IeLen = rlmFillHtCapIEByAdapter(prAdapter, prBssInfo, pPkt);
pPkt += u4IeLen;
u4PktLen += u4IeLen;
}
/* 3. Frame Formation - (12) Timeout interval element (TPK Key Lifetime) */
TIMEOUT_INTERVAL_IE(pPkt)->ucId = ELEM_ID_TIMEOUT_INTERVAL;
TIMEOUT_INTERVAL_IE(pPkt)->ucLength = 5;
TIMEOUT_INTERVAL_IE(pPkt)->ucType = 2; /* IE_TIMEOUT_INTERVAL_TYPE_KEY_LIFETIME; */
TIMEOUT_INTERVAL_IE(pPkt)->u4Value = TDLS_KEY_TIMEOUT_INTERVAL; /* htonl(prCmd->u4Timeout); */
u4IeLen = IE_SIZE(pPkt);
pPkt += u4IeLen;
u4PktLen += u4IeLen;
if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) {
/*
* bit0 = 1: The Information Request field is used to indicate that a
* transmitting STA is requesting the recipient to transmit a 20/40 BSS
* Coexistence Management frame with the transmitting STA as the
* recipient.
* bit1 = 0: The Forty MHz Intolerant field is set to 1 to prohibit an AP
* that receives this information or reports of this information from
* operating a 20/40 MHz BSS.
* bit2 = 0: The 20 MHz BSS Width Request field is set to 1 to prohibit
* a receiving AP from operating its BSS as a 20/40 MHz BSS.
*/
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);
}
if (pAppendIe != NULL) {
if ((ucActionCode != TDLS_FRM_ACTION_TEARDOWN) ||
((ucActionCode == TDLS_FRM_ACTION_TEARDOWN))) {
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, pPeerMac, 6); /* prAdapter->rMyMacAddr */
kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, prAdapter->rMyMacAddr, 6); /* pPeerMac */
u4IeLen = IE_SIZE(pPkt);
pPkt += u4IeLen;
u4PktLen += u4IeLen;
/* HT WMM IE append */
/* HT WMM IE append */
if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucQoS)) {
/* Add WMM IE *//* try to reuse p2p path */
u4IeLen = mqmGenerateWmmInfoIEByStaRec(prAdapter, prBssInfo, prStaRec, pPkt);
pPkt += u4IeLen;
u4PktLen += u4IeLen;
}
if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucQoS)) {
u4IeLen = mqmGenerateWmmParamIEByParam(prAdapter, prBssInfo, pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
}
#if CFG_SUPPORT_802_11AC
if (prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11AC) {
/* Add VHT IE *//* try to reuse p2p path */
u4IeLen = rlmFillVhtCapIEByAdapter(prAdapter, prBssInfo, pPkt);
pPkt += u4IeLen;
u4PktLen += u4IeLen;
}
#endif
/* 5. Update packet length */
prMsduInfo->len = u4PktLen;
/* 5. send the data frame */
wlanHardStartXmit(prMsduInfo, prMsduInfo->dev);
return TDLS_STATUS_SUCCESS;
}
WLAN_STATUS
TdlsDataFrameSend_CONFIRM(ADAPTER_T *prAdapter,
STA_RECORD_T *prStaRec,
UINT_8 *pPeerMac,
UINT_8 ucActionCode,
UINT_8 ucDialogToken, UINT_16 u2StatusCode, UINT_8 *pAppendIe, UINT_32 AppendIeLen)
{
GLUE_INFO_T *prGlueInfo;
BSS_INFO_T *prBssInfo;
PM_PROFILE_SETUP_INFO_T *prPmProfSetupInfo;
struct sk_buff *prMsduInfo;
UINT_8 *pPkt;
UINT_32 u4PktLen, u4IeLen;
UINT_16 StatusCode;
/* allocate/init packet */
prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo;
prBssInfo = prAdapter->prAisBssInfo; /* AIS only */
prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo;
u4PktLen = 0;
prMsduInfo = kalPacketAlloc(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);
pPkt += TDLS_FME_MAC_ADDR_LEN;
kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN);
pPkt += TDLS_FME_MAC_ADDR_LEN;
*(UINT_16 *) 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 */
StatusCode = u2StatusCode; /* 0; //u2StatusCode; //ahiu 0224 */
kalMemCopy(pPkt, &StatusCode, 2);
pPkt = pPkt + 2;
u4PktLen = u4PktLen + 2;
/* 3. Frame Formation - (3) Dialog token */
*pPkt = ucDialogToken;
pPkt++;
u4PktLen++;
/* 4. Append extra IEs */
kalMemCopy(pPkt, pAppendIe, AppendIeLen);
pPkt += AppendIeLen;
u4PktLen += AppendIeLen;
/* 3. Frame Formation - (12) Timeout interval element (TPK Key Lifetime) */
TIMEOUT_INTERVAL_IE(pPkt)->ucId = ELEM_ID_TIMEOUT_INTERVAL;
TIMEOUT_INTERVAL_IE(pPkt)->ucLength = 5;
TIMEOUT_INTERVAL_IE(pPkt)->ucType = 2;
TIMEOUT_INTERVAL_IE(pPkt)->u4Value = TDLS_KEY_TIMEOUT_INTERVAL; /* htonl(prCmd->u4Timeout); */
u4IeLen = IE_SIZE(pPkt);
pPkt += u4IeLen;
u4PktLen += u4IeLen;
if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) {
/*
* bit0 = 1: The Information Request field is used to indicate that a
* transmitting STA is requesting the recipient to transmit a 20/40 BSS
* Coexistence Management frame with the transmitting STA as the
* recipient.
* bit1 = 0: The Forty MHz Intolerant field is set to 1 to prohibit an AP
* that receives this information or reports of this information from
* operating a 20/40 MHz BSS.
* bit2 = 0: The 20 MHz BSS Width Request field is set to 1 to prohibit
* a receiving AP from operating its BSS as a 20/40 MHz BSS.
*/
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);
}
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, prAdapter->rMyMacAddr, 6);
kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, pPeerMac, 6);
u4IeLen = IE_SIZE(pPkt);
pPkt += u4IeLen;
u4PktLen += u4IeLen;
/* HT WMM IE append */
if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucQoS)) {
/* Add WMM IE *//* try to reuse p2p path */
u4IeLen = mqmGenerateWmmInfoIEByStaRec(prAdapter, prBssInfo, prStaRec, pPkt);
pPkt += u4IeLen;
u4PktLen += u4IeLen;
}
if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucQoS)) {
u4IeLen = mqmGenerateWmmParamIEByParam(prAdapter, prBssInfo, pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
}
/* 5. 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
*/
/*----------------------------------------------------------------------------*/
WLAN_STATUS /* TDLS_STATUS */
TdlsDataFrameSend_DISCOVERY_REQ(ADAPTER_T *prAdapter,
STA_RECORD_T *prStaRec,
UINT_8 *pPeerMac,
UINT_8 ucActionCode,
UINT_8 ucDialogToken, UINT_16 u2StatusCode, UINT_8 *pAppendIe, UINT_32 AppendIeLen)
{
GLUE_INFO_T *prGlueInfo;
BSS_INFO_T *prBssInfo;
PM_PROFILE_SETUP_INFO_T *prPmProfSetupInfo;
struct sk_buff *prMsduInfo;
MSDU_INFO_T *prMsduInfoMgmt;
UINT_8 *pPkt, *pucInitiator, *pucResponder;
UINT_32 u4PktLen, u4IeLen;
UINT_16 u2CapInfo;
prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo;
if (prStaRec != NULL)
prBssInfo = prAdapter->prAisBssInfo; /* AIS only */
else
return TDLS_STATUS_FAIL;
/* allocate/init packet */
prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo;
u4PktLen = 0;
prMsduInfo = NULL;
prMsduInfoMgmt = NULL;
/* make up frame content */
if (ucActionCode != TDLS_FRM_ACTION_DISCOVERY_RSP) {
/* TODO: reduce 1600 to correct size */
prMsduInfo = kalPacketAlloc(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);
*(UINT_16 *) 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. Frame Formation - (1) Category */
*pPkt = TDLS_FRM_CATEGORY;
LR_TDLS_FME_FIELD_FILL(1);
} else {
WLAN_MAC_HEADER_T *prHdr;
prMsduInfoMgmt = (MSDU_INFO_T *)
cnmMgtPktAlloc(prAdapter, PUBLIC_ACTION_MAX_LEN);
if (prMsduInfoMgmt == NULL)
return TDLS_STATUS_RESOURCES;
pPkt = (UINT_8 *) prMsduInfoMgmt->prPacket;
prHdr = (WLAN_MAC_HEADER_T *) 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(WLAN_MAC_HEADER_T));
/* Frame Formation - (1) Category */
*pPkt = CATEGORY_PUBLIC_ACTION;
LR_TDLS_FME_FIELD_FILL(1);
}
/* 3. Frame Formation - (2) Action */
*pPkt = ucActionCode;
LR_TDLS_FME_FIELD_FILL(1);
/* 3. Frame Formation - Status Code */
switch (ucActionCode) {
case TDLS_FRM_ACTION_SETUP_RSP:
case TDLS_FRM_ACTION_CONFIRM:
case TDLS_FRM_ACTION_TEARDOWN:
WLAN_SET_FIELD_16(pPkt, u2StatusCode);
LR_TDLS_FME_FIELD_FILL(2);
break;
}
/* 3. Frame Formation - (3) Dialog token */
if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) {
*pPkt = ucDialogToken;
LR_TDLS_FME_FIELD_FILL(1);
}
/* Fill elements */
if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) {
/*
* Capability
* Support Rates
* Extended Support Rates
* Supported Channels
* HT Capabilities
* WMM Information Element
* Extended Capabilities
* Link Identifier
* RSNIE
* FTIE
* Timeout Interval
*/
if (ucActionCode != TDLS_FRM_ACTION_CONFIRM && ucActionCode != TDLS_FRM_ACTION_DISCOVERY_REQ) {
/* 3. Frame Formation - (4) Capability: 0x31 0x04, privacy bit will be set */
u2CapInfo = assocBuildCapabilityInfo(prAdapter, prStaRec);
WLAN_SET_FIELD_16(pPkt, u2CapInfo);
LR_TDLS_FME_FIELD_FILL(2);
}
if (ucActionCode != TDLS_FRM_ACTION_CONFIRM) {
/* 4. Append general IEs */
/*
* TODO check HT: prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode
* must be CONFIG_BW_20_40M.
* TODO check HT: HT_CAP_INFO_40M_INTOLERANT must be clear if
* Tdls 20/40 is enabled.
*/
u4IeLen = TdlsFrameGeneralIeAppend(prAdapter, prStaRec, pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
/* 5. Frame Formation - Extended capabilities element */
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 */
/* if (prCmd->ucExCap & TDLS_EX_CAP_PEER_UAPSD) */
EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((28 - 24));
/* if (prCmd->ucExCap & TDLS_EX_CAP_CHAN_SWITCH) */
EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((30 - 24));
/* if (prCmd->ucExCap & TDLS_EX_CAP_TDLS) */
EXT_CAP_IE(pPkt)->aucCapabilities[4] |= BIT((37 - 32));
u4IeLen = IE_SIZE(pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
} else {
/* 5. Frame Formation - WMM Information element */
if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucQoS)) {
/* Add WMM IE *//* try to reuse p2p path */
u4IeLen = mqmGenerateWmmInfoIEByStaRec(prAdapter, prBssInfo, prStaRec, pPkt);
pPkt += u4IeLen;
u4PktLen += u4IeLen;
}
}
}
/* 6. Frame Formation - 20/40 BSS Coexistence */
/*
* Follow WiFi test plan, add 20/40 element to request/response/confirm.
*/
#if 0
if (prGlueInfo->fgTdlsIs2040Supported == TRUE) {
/*
* bit0 = 1: The Information Request field is used to indicate that a
* transmitting STA is requesting the recipient to transmit a 20/40 BSS
* Coexistence Management frame with the transmitting STA as the
* recipient.
* bit1 = 0: The Forty MHz Intolerant field is set to 1 to prohibit an AP
* that receives this information or reports of this information from
* operating a 20/40 MHz BSS.
* bit2 = 0: The 20 MHz BSS Width Request field is set to 1 to prohibit
* a receiving AP from operating its BSS as a 20/40 MHz BSS.
*/
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);
}
#endif
/* 6. Frame Formation - HT Operation element */
/* u4IeLen = rlmFillHtOpIeBody(prBssInfo, pPkt); */
/* LR_TDLS_FME_FIELD_FILL(u4IeLen); */
/* 7. Frame Formation - Link identifier element */
/* Note: Link ID sequence must be correct; Or the calculated MIC will be error */
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);
switch (ucActionCode) {
case TDLS_FRM_ACTION_SETUP_REQ:
case TDLS_FRM_ACTION_CONFIRM:
case TDLS_FRM_ACTION_DISCOVERY_RSP:
default:
/* we are initiator */
pucInitiator = prBssInfo->aucOwnMacAddr;
pucResponder = pPeerMac;
prStaRec->flgTdlsIsInitiator = TRUE;
break;
case TDLS_FRM_ACTION_SETUP_RSP:
/* peer is initiator */
pucInitiator = pPeerMac;
pucResponder = prBssInfo->aucOwnMacAddr;
prStaRec->flgTdlsIsInitiator = FALSE;
break;
case TDLS_FRM_ACTION_TEARDOWN:
if (prStaRec->flgTdlsIsInitiator == TRUE) {
/* we are initiator */
pucInitiator = prBssInfo->aucOwnMacAddr;
pucResponder = pPeerMac;
} else {
/* peer is initiator */
pucInitiator = pPeerMac;
pucResponder = prBssInfo->aucOwnMacAddr;
}
break;
}
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);
/* 8. Append security IEs */
if ((ucActionCode != TDLS_FRM_ACTION_TEARDOWN) && (pAppendIe != NULL)) {
kalMemCopy(pPkt, pAppendIe, AppendIeLen);
LR_TDLS_FME_FIELD_FILL(AppendIeLen);
}
/* 10. send the data or management frame */
if (ucActionCode != TDLS_FRM_ACTION_DISCOVERY_RSP) {
/* 9. Update packet length */
prMsduInfo->len = u4PktLen;
wlanHardStartXmit(prMsduInfo, prMsduInfo->dev);
} else {
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;
}
WLAN_STATUS
TdlsDataFrameSend_DISCOVERY_RSP(ADAPTER_T *prAdapter,
STA_RECORD_T *prStaRec,
UINT_8 *pPeerMac,
UINT_8 ucActionCode,
UINT_8 ucDialogToken, UINT_16 u2StatusCode, UINT_8 *pAppendIe, UINT_32 AppendIeLen)
{
GLUE_INFO_T *prGlueInfo;
BSS_INFO_T *prBssInfo;
PM_PROFILE_SETUP_INFO_T *prPmProfSetupInfo;
struct sk_buff *prMsduInfo;
MSDU_INFO_T *prMsduInfoMgmt;
UINT_8 *pPkt, *pucInitiator, *pucResponder;
UINT_32 u4PktLen, u4IeLen;
UINT_16 u2CapInfo;
WLAN_MAC_HEADER_T *prHdr;
prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo;
/* sanity check */
if (prStaRec != NULL)
prBssInfo = prAdapter->prAisBssInfo; /* AIS only */
else
return TDLS_STATUS_FAIL;
/* allocate/init packet */
prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo;
u4PktLen = 0;
prMsduInfo = NULL;
prMsduInfoMgmt = NULL;
/* make up frame content */
prMsduInfoMgmt = (MSDU_INFO_T *)
cnmMgtPktAlloc(prAdapter, PUBLIC_ACTION_MAX_LEN);
if (prMsduInfoMgmt == NULL) {
DBGLOG(TDLS, ERROR, "cnmMgtPktAlloc for prMsduInfoMgmt failed!\n");
return TDLS_STATUS_RESOURCES;
}
pPkt = (UINT_8 *) prMsduInfoMgmt->prPacket;
prHdr = (WLAN_MAC_HEADER_T *) 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(WLAN_MAC_HEADER_T));
/* Frame Formation - (1) Category */
*pPkt = CATEGORY_PUBLIC_ACTION;
LR_TDLS_FME_FIELD_FILL(1);
/* 3. Frame Formation - (2) Action */
*pPkt = ucActionCode;
LR_TDLS_FME_FIELD_FILL(1);
/* 3. Frame Formation - (3) Dialog token */
*pPkt = ucDialogToken;
LR_TDLS_FME_FIELD_FILL(1);
/* Fill elements */
/*
* Capability
* Support Rates
* Extended Support Rates
* Supported Channels
* HT Capabilities
* WMM Information Element
* Extended Capabilities
* Link Identifier
* RSNIE
* FTIE
* Timeout Interval
*/
/* 3. Frame Formation - (4) Capability: 0x31 0x04, privacy bit will be set */
u2CapInfo = assocBuildCapabilityInfo(prAdapter, prStaRec);
WLAN_SET_FIELD_16(pPkt, u2CapInfo);
LR_TDLS_FME_FIELD_FILL(2);
/* 4. Append general IEs */
/*
* TODO check HT: prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode
* must be CONFIG_BW_20_40M.
* TODO check HT: HT_CAP_INFO_40M_INTOLERANT must be clear if
* Tdls 20/40 is enabled.
*/
u4IeLen = TdlsFrameGeneralIeAppend(prAdapter, prStaRec, pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
/* 5. Frame Formation - Extended capabilities element */
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 */
/* if (prCmd->ucExCap & TDLS_EX_CAP_PEER_UAPSD) */
EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((28 - 24));
/* if (prCmd->ucExCap & TDLS_EX_CAP_CHAN_SWITCH) */
EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((30 - 24));
/* if (prCmd->ucExCap & TDLS_EX_CAP_TDLS) */
EXT_CAP_IE(pPkt)->aucCapabilities[4] |= BIT((37 - 32));
u4IeLen = IE_SIZE(pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
/* 6. Frame Formation - 20/40 BSS Coexistence */
/*
* Follow WiFi test plan, add 20/40 element to request/response/confirm.
*/
#if 0
if (prGlueInfo->fgTdlsIs2040Supported == TRUE) {
/*
* bit0 = 1: The Information Request field is used to indicate that a
* transmitting STA is requesting the recipient to transmit a 20/40 BSS
* Coexistence Management frame with the transmitting STA as the
* recipient.
* bit1 = 0: The Forty MHz Intolerant field is set to 1 to prohibit an AP
* that receives this information or reports of this information from
* operating a 20/40 MHz BSS.
* bit2 = 0: The 20 MHz BSS Width Request field is set to 1 to prohibit
* a receiving AP from operating its BSS as a 20/40 MHz BSS.
*/
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);
}
#endif
/* 6. Frame Formation - HT Operation element */
/* u4IeLen = rlmFillHtOpIeBody(prBssInfo, pPkt); */
/* LR_TDLS_FME_FIELD_FILL(u4IeLen); */
/* 7. Frame Formation - Link identifier element */
/* Note: Link ID sequence must be correct; Or the calculated MIC will be error */
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);
/* peer is initiator */
pucInitiator = pPeerMac;
pucResponder = prBssInfo->aucOwnMacAddr;
if (prStaRec != NULL)
prStaRec->flgTdlsIsInitiator = FALSE;
/* 3. Frame Formation - (12) Timeout interval element (TPK Key Lifetime) */
TIMEOUT_INTERVAL_IE(pPkt)->ucId = ELEM_ID_TIMEOUT_INTERVAL;
TIMEOUT_INTERVAL_IE(pPkt)->ucLength = 5;
TIMEOUT_INTERVAL_IE(pPkt)->ucType = 2; /* IE_TIMEOUT_INTERVAL_TYPE_KEY_LIFETIME; */
TIMEOUT_INTERVAL_IE(pPkt)->u4Value = TDLS_KEY_TIMEOUT_INTERVAL; /* htonl(prCmd->u4Timeout); */
u4IeLen = IE_SIZE(pPkt);
pPkt += u4IeLen;
u4PktLen += u4IeLen;
/*
* bit0 = 1: The Information Request field is used to indicate that a
* transmitting STA is requesting the recipient to transmit a 20/40 BSS
* Coexistence Management frame with the transmitting STA as the
* recipient.
* bit1 = 0: The Forty MHz Intolerant field is set to 1 to prohibit an AP
* that receives this information or reports of this information from
* operating a 20/40 MHz BSS.
* bit2 = 0: The 20 MHz BSS Width Request field is set to 1 to prohibit
* a receiving AP from operating its BSS as a 20/40 MHz BSS.
*/
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);
if (pAppendIe != NULL) {
kalMemCopy(pPkt, pAppendIe, AppendIeLen);
LR_TDLS_FME_FIELD_FILL(AppendIeLen);
}
/* 7. Append Supported Operating Classes IE */
/* 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, pPeerMac, 6); /* prAdapter->rMyMacAddr */
kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, prAdapter->rMyMacAddr, 6); /* pPeerMac */
u4IeLen = IE_SIZE(pPkt);
pPkt += u4IeLen;
u4PktLen += u4IeLen;
/* HT WMM IE append */
/* HT WMM IE append */
if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucQoS)) {
/* Add WMM IE *//* try to reuse p2p path */
u4IeLen = mqmGenerateWmmInfoIEByStaRec(prAdapter, prBssInfo, prStaRec, pPkt);
pPkt += u4IeLen;
u4PktLen += u4IeLen;
}
if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucQoS)) {
u4IeLen = mqmGenerateWmmParamIEByParam(prAdapter, prBssInfo, pPkt);
LR_TDLS_FME_FIELD_FILL(u4IeLen);
}
#if CFG_SUPPORT_802_11AC
if (prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11AC) {
/* Add VHT IE *//* try to reuse p2p path */
u4IeLen = rlmFillVhtCapIEByAdapter(prAdapter, prBssInfo, pPkt);
pPkt += u4IeLen;
u4PktLen += u4IeLen;
}
#endif
/* 8. Append security IEs */
if (pAppendIe != NULL) {
kalMemCopy(pPkt, pAppendIe, AppendIeLen);
LR_TDLS_FME_FIELD_FILL(AppendIeLen);
}
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(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen)
{
UINT_32 u4EventId;
DBGLOG(TDLS, INFO, "TdlsexEventHandle\n");
/* sanity check */
if ((prGlueInfo == NULL) || (prInBuf == NULL))
return; /* shall not be here */
/* handle */
u4EventId = *(UINT_32 *) 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(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen)
{
STA_RECORD_T *prStaRec;
UINT_16 u2ReasonCode;
UINT_32 u4TearDownSubId;
UINT_8 *pMac, aucZeroMac[6];
/* init */
u4TearDownSubId = *(UINT_32 *) prInBuf;
kalMemZero(aucZeroMac, sizeof(aucZeroMac));
pMac = aucZeroMac;
prStaRec = cnmGetStaRecByIndex(prGlueInfo->prAdapter, *(prInBuf + 4));
if (prStaRec != NULL)
pMac = prStaRec->aucMacAddr;
/* handle */
/* sanity check */
if (prStaRec == NULL)
return;
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);
}
/*
* modify the value when supplicant sends tear down to us in TdlsexMgmtCtrl(), not here
* we want to send tear down to AP (not peer) if PTI timeout or AGE timeout.
*/
/* 16 Nov 21:49 2012 http://permalink.gmane.org/gmane.linux.kernel.wireless.general/99712 */
}
#if 0
/*----------------------------------------------------------------------------*/
/*! \brief This routine is called to send a TDLS event to supplicant.
*
* \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 tdls_oper_request(struct net_device *dev, const u8 *peer, u16 oper, u16 reason_code, gfp_t gfp)
{
GLUE_INFO_T *prGlueInfo;
ADAPTER_T *prAdapter;
struct sk_buff *prMsduInfo;
UINT_8 *pPkt;
UINT_32 u4PktLen;
/* sanity check */
if ((dev == NULL) || (peer == NULL))
return; /* shall not be here */
/* init */
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(dev));
prAdapter = prGlueInfo->prAdapter;
u4PktLen = 0;
/* allocate/init packet */
prMsduInfo = kalPacketAlloc(prGlueInfo, 1600, &pPkt);
if (prMsduInfo == NULL)
return;
prMsduInfo->dev = dev;
/* make up frame content */
/* 1. 802.3 header */
kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN);
LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN);
kalMemCopy(pPkt, peer, TDLS_FME_MAC_ADDR_LEN);
LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN);
*(UINT_16 *) 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. Frame Formation - (1) Category */
*pPkt = TDLS_FRM_CATEGORY;
LR_TDLS_FME_FIELD_FILL(1);
/* 3. Frame Formation - (2) Action */
*pPkt = TDLS_FRM_ACTION_EVENT_TEAR_DOWN_TO_SUPPLICANT;
LR_TDLS_FME_FIELD_FILL(1);
/* 3. Frame Formation - (3) Operation */
*pPkt = oper;
LR_TDLS_FME_FIELD_FILL(1);
/* 3. Frame Formation - (4) Reason Code */
*pPkt = reason_code;
*(pPkt + 1) = 0x00;
LR_TDLS_FME_FIELD_FILL(2);
/* 3. Frame Formation - (5) Peer MAC */
kalMemCopy(pPkt, peer, 6);
LR_TDLS_FME_FIELD_FILL(6);
/* 4. Update packet length */
prMsduInfo->len = u4PktLen;
/* pass to OS */
TdlsCmdTestRxIndicatePkts(prGlueInfo, prMsduInfo);
}
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is called to indicate packets to upper layer.
*
* \param[in] prGlueInfo Pointer to the Adapter structure
* \param[in] prSkb A pointer to the received packet
*
* \retval None
*
*/
/*----------------------------------------------------------------------------*/
VOID TdlsCmdTestRxIndicatePkts(GLUE_INFO_T *prGlueInfo, struct sk_buff *prSkb)
{
struct net_device *prNetDev;
/* init */
prNetDev = prGlueInfo->prDevHandler;
prGlueInfo->rNetDevStats.rx_bytes += prSkb->len;
prGlueInfo->rNetDevStats.rx_packets++;
/* pass to upper layer */
prNetDev->last_rx = jiffies;
prSkb->protocol = eth_type_trans(prSkb, prNetDev);
prSkb->dev = prNetDev;
if (!in_interrupt())
netif_rx_ni(prSkb); /* only in non-interrupt context */
else
netif_rx(prSkb);
}
#endif
VOID TdlsBssExtCapParse(P_STA_RECORD_T prStaRec, P_UINT_8 pucIE)
{
UINT_8 *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
*/
/*----------------------------------------------------------------------------*/
WLAN_STATUS
TdlsSendChSwControlCmd(P_ADAPTER_T prAdapter, PVOID pvSetBuffer, UINT_32 u4SetBufferLen, PUINT_32 pu4SetInfoLen)
{
CMD_TDLS_CH_SW_T rCmdTdlsChSwCtrl;
ASSERT(prAdapter);
/* send command packet for scan */
kalMemZero(&rCmdTdlsChSwCtrl, sizeof(CMD_TDLS_CH_SW_T));
rCmdTdlsChSwCtrl.fgIsTDLSChSwProhibit = prAdapter->prAisBssInfo->fgTdlsIsChSwProhibited;
wlanSendSetQueryCmd(prAdapter,
CMD_ID_SET_TDLS_CH_SW,
TRUE,
FALSE, FALSE, NULL, NULL, sizeof(CMD_TDLS_CH_SW_T), (PUINT_8)&rCmdTdlsChSwCtrl, NULL, 0);
return TDLS_STATUS_SUCCESS;
}
WLAN_STATUS
TdlsTxCtrl(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, BOOLEAN fgEnable)
{
int i;
P_STA_RECORD_T 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 */