blob: 74e8ec638f9dd8c6282e33001a8868f104289c17 [file]
/*******************************************************************************
*
* 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: @(#) gl_cfg80211.c@@
*/
/*! \file gl_cfg80211.c
* \brief Main routines for supporintg MT6620 cfg80211 control interface
*
* This file contains the support routines of Linux driver for MediaTek Inc.
* 802.11 Wireless LAN Adapters.
*/
/*******************************************************************************
* 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 "gl_os.h"
#include "debug.h"
#include "wlan_lib.h"
#include "gl_wext.h"
#include "precomp.h"
#include <linux/can/netlink.h>
#include <net/netlink.h>
#include <net/cfg80211.h>
#include "gl_cfg80211.h"
#include "gl_vendor.h"
#include "gl_p2p_os.h"
/*******************************************************************************
* C O N S T A N T S
*******************************************************************************
*/
#if CFG_SUPPORT_WAPI
#define KEY_BUF_SIZE 1024
#endif
/*******************************************************************************
* D A T A T Y P E S
*******************************************************************************
*/
/*******************************************************************************
* P U B L I C D A T A
*******************************************************************************
*/
/*******************************************************************************
* P R I V A T E D A T A
*******************************************************************************
*/
/*******************************************************************************
* M A C R O S
*******************************************************************************
*/
/*******************************************************************************
* 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 responsible for change STA type between
* 1. Infrastructure Client (Non-AP STA)
* 2. Ad-Hoc IBSS
*
* @param
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
int
mtk_cfg80211_change_iface(struct wiphy *wiphy,
struct net_device *ndev, enum nl80211_iftype type,
u32 *flags, struct vif_params *params)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint32_t rStatus = WLAN_STATUS_SUCCESS;
enum ENUM_PARAM_OP_MODE eOpMode;
uint32_t u4BufLen;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
DBGLOG(REQ, INFO, "mtk_cfg80211_change_iface\n");
if (type == NL80211_IFTYPE_STATION)
eOpMode = NET_TYPE_INFRA;
else if (type == NL80211_IFTYPE_ADHOC)
eOpMode = NET_TYPE_IBSS;
else
return -EINVAL;
rStatus = kalIoctl(prGlueInfo, wlanoidSetInfrastructureMode, &eOpMode,
sizeof(eOpMode), FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
DBGLOG(REQ, WARN, "set infrastructure mode error:%x\n",
rStatus);
/* reset wpa info */
prGlueInfo->rWpaInfo.u4WpaVersion =
IW_AUTH_WPA_VERSION_DISABLED;
prGlueInfo->rWpaInfo.u4KeyMgmt = 0;
prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_NONE;
prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE;
prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM;
#if CFG_SUPPORT_802_11W
prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED;
prGlueInfo->rWpaInfo.ucRSNMfpCap = 0;
prGlueInfo->rWpaInfo.u4CipherGroupMgmt = IW_AUTH_CIPHER_NONE;
#endif
ndev->ieee80211_ptr->iftype = type;
return 0;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for adding key
*
* @param
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
int
mtk_cfg80211_add_key(struct wiphy *wiphy,
struct net_device *ndev,
u8 key_index, bool pairwise, const u8 *mac_addr,
struct key_params *params)
{
struct PARAM_KEY rKey;
struct GLUE_INFO *prGlueInfo = NULL;
uint32_t rStatus = WLAN_STATUS_SUCCESS;
int32_t i4Rslt = -EINVAL;
uint32_t u4BufLen = 0;
uint8_t tmp1[8], tmp2[8];
#if CFG_SUPPORT_REPLAY_DETECTION
struct GL_DETECT_REPLAY_INFO *prDetRplyInfo = NULL;
uint8_t ucCheckZeroKey = 0;
uint8_t i = 0;
#endif
const uint8_t aucBCAddr[] = BC_MAC_ADDR;
/* const UINT_8 aucZeroMacAddr[] = NULL_MAC_ADDR; */
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
DBGLOG(RSN, INFO, "mtk_cfg80211_add_key\n");
#if DBG
if (mac_addr) {
DBGLOG(RSN, INFO,
"keyIdx = %d pairwise = %d mac = " MACSTR "\n",
key_index, pairwise, MAC2STR(mac_addr));
} else {
DBGLOG(RSN, INFO, "keyIdx = %d pairwise = %d null mac\n",
key_index, pairwise);
}
DBGLOG(RSN, INFO, "Cipher = %x\n", params->cipher);
DBGLOG_MEM8(RSN, INFO, params->key, params->key_len);
#endif
kalMemZero(&rKey, sizeof(struct PARAM_KEY));
rKey.u4KeyIndex = key_index;
if (params->cipher) {
switch (params->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
rKey.ucCipher = CIPHER_SUITE_WEP40;
break;
case WLAN_CIPHER_SUITE_WEP104:
rKey.ucCipher = CIPHER_SUITE_WEP104;
break;
#if 0
case WLAN_CIPHER_SUITE_WEP128:
rKey.ucCipher = CIPHER_SUITE_WEP128;
break;
#endif
case WLAN_CIPHER_SUITE_TKIP:
rKey.ucCipher = CIPHER_SUITE_TKIP;
break;
case WLAN_CIPHER_SUITE_CCMP:
rKey.ucCipher = CIPHER_SUITE_CCMP;
break;
#if 0
case WLAN_CIPHER_SUITE_GCMP:
rKey.ucCipher = CIPHER_SUITE_GCMP;
break;
case WLAN_CIPHER_SUITE_CCMP_256:
rKey.ucCipher = CIPHER_SUITE_CCMP256;
break;
#endif
case WLAN_CIPHER_SUITE_SMS4:
rKey.ucCipher = CIPHER_SUITE_WPI;
break;
case WLAN_CIPHER_SUITE_AES_CMAC:
rKey.ucCipher = CIPHER_SUITE_BIP;
break;
default:
ASSERT(FALSE);
}
}
if (pairwise) {
ASSERT(mac_addr);
rKey.u4KeyIndex |= BIT(31);
rKey.u4KeyIndex |= BIT(30);
COPY_MAC_ADDR(rKey.arBSSID, mac_addr);
/* reset KCK, KEK, EAPOL Replay counter */
kalMemZero(prGlueInfo->rWpaInfo.aucKek, NL80211_KEK_LEN);
kalMemZero(prGlueInfo->rWpaInfo.aucKck, NL80211_KCK_LEN);
kalMemZero(prGlueInfo->rWpaInfo.aucReplayCtr,
NL80211_REPLAY_CTR_LEN);
} else { /* Group key */
COPY_MAC_ADDR(rKey.arBSSID, aucBCAddr);
}
if (params->key) {
if (params->key_len > sizeof(rKey.aucKeyMaterial))
return -EINVAL;
#if CFG_SUPPORT_REPLAY_DETECTION
for (i = 0; i < params->key_len; i++) {
if (params->key[i] == 0x00)
ucCheckZeroKey++;
}
if (ucCheckZeroKey == params->key_len)
return 0;
#endif
kalMemCopy(rKey.aucKeyMaterial, params->key,
params->key_len);
if (rKey.ucCipher == CIPHER_SUITE_TKIP) {
kalMemCopy(tmp1, &params->key[16], 8);
kalMemCopy(tmp2, &params->key[24], 8);
kalMemCopy(&rKey.aucKeyMaterial[16], tmp2, 8);
kalMemCopy(&rKey.aucKeyMaterial[24], tmp1, 8);
}
}
rKey.ucBssIdx =
prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex;
rKey.u4KeyLength = params->key_len;
rKey.u4Length = ((unsigned long) &(((struct PARAM_KEY *)
0)->aucKeyMaterial)) + rKey.u4KeyLength;
#if CFG_SUPPORT_REPLAY_DETECTION
prDetRplyInfo = &prGlueInfo->prDetRplyInfo;
if ((!pairwise) &&
((params->cipher == WLAN_CIPHER_SUITE_TKIP) ||
(params->cipher == WLAN_CIPHER_SUITE_CCMP))) {
if ((prDetRplyInfo->ucCurKeyId == key_index) &&
(!kalMemCmp(prDetRplyInfo->aucKeyMaterial,
params->key, params->key_len))) {
DBGLOG(RSN, TRACE,
"M3/G1, KeyID and KeyValue equal.\n");
DBGLOG(RSN, TRACE,
"gtk reinstall, so no update BC/MC PN.\n");
} else {
kalMemCopy(
prDetRplyInfo->arReplayPNInfo[key_index].auPN,
params->seq, params->seq_len);
prDetRplyInfo->ucCurKeyId = key_index;
prDetRplyInfo->u4KeyLength = params->key_len;
kalMemCopy(prDetRplyInfo->aucKeyMaterial,
params->key, params->key_len);
}
prDetRplyInfo->fgKeyRscFresh = TRUE;
}
#endif
rStatus = kalIoctl(prGlueInfo, wlanoidSetAddKey, &rKey,
rKey.u4Length, FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus == WLAN_STATUS_SUCCESS)
i4Rslt = 0;
return i4Rslt;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for getting key for specified STA
*
* @param
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
int
mtk_cfg80211_get_key(struct wiphy *wiphy,
struct net_device *ndev,
u8 key_index,
bool pairwise,
const u8 *mac_addr, void *cookie,
void (*callback)(void *cookie, struct key_params *)
)
{
struct GLUE_INFO *prGlueInfo = NULL;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
#if 1
DBGLOG(INIT, INFO, "--> %s()\n", __func__);
#endif
/* not implemented */
return -EINVAL;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for removing key for specified STA
*
* @param
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
int mtk_cfg80211_del_key(struct wiphy *wiphy,
struct net_device *ndev, u8 key_index, bool pairwise,
const u8 *mac_addr)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint32_t rStatus = WLAN_STATUS_SUCCESS;
struct PARAM_REMOVE_KEY rRemoveKey;
uint32_t u4BufLen = 0;
int32_t i4Rslt = -EINVAL;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
if (g_u4HaltFlag) {
DBGLOG(RSN, WARN, "wlan is halt, skip key deletion\n");
return WLAN_STATUS_FAILURE;
}
DBGLOG(RSN, TRACE, "mtk_cfg80211_del_key\n");
#if DBG
if (mac_addr) {
DBGLOG(RSN, TRACE,
"keyIdx = %d pairwise = %d mac = " MACSTR "\n",
key_index, pairwise, MAC2STR(mac_addr));
} else {
DBGLOG(RSN, TRACE, "keyIdx = %d pairwise = %d null mac\n",
key_index, pairwise);
}
#endif
kalMemZero(&rRemoveKey, sizeof(struct PARAM_REMOVE_KEY));
rRemoveKey.u4KeyIndex = key_index;
rRemoveKey.u4Length = sizeof(struct PARAM_REMOVE_KEY);
if (mac_addr) {
COPY_MAC_ADDR(rRemoveKey.arBSSID, mac_addr);
rRemoveKey.u4KeyIndex |= BIT(30);
}
if ((prGlueInfo->prAdapter == NULL)
|| (prGlueInfo->prAdapter->prAisBssInfo == NULL))
return i4Rslt;
rRemoveKey.ucBssIdx =
prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex;
rStatus = kalIoctl(prGlueInfo, wlanoidSetRemoveKey, &rRemoveKey,
rRemoveKey.u4Length, FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
DBGLOG(RSN, WARN, "remove key error:%x\n", rStatus);
else
i4Rslt = 0;
return i4Rslt;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for setting default key on an interface
*
* @param
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
int
mtk_cfg80211_set_default_key(struct wiphy *wiphy,
struct net_device *ndev, u8 key_index, bool unicast,
bool multicast)
{
struct GLUE_INFO *prGlueInfo = NULL;
struct PARAM_DEFAULT_KEY rDefaultKey;
uint32_t rStatus = WLAN_STATUS_SUCCESS;
int32_t i4Rst = -EINVAL;
uint32_t u4BufLen = 0;
u_int8_t fgDef = FALSE, fgMgtDef = FALSE;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
/* For STA, should wep set the default key !! */
DBGLOG(RSN, INFO, "mtk_cfg80211_set_default_key\n");
#if DBG
DBGLOG(RSN, INFO,
"keyIdx = %d unicast = %d multicast = %d\n", key_index,
unicast, multicast);
#endif
rDefaultKey.ucKeyID = key_index;
rDefaultKey.ucUnicast = unicast;
rDefaultKey.ucMulticast = multicast;
if (rDefaultKey.ucUnicast && !rDefaultKey.ucMulticast)
return WLAN_STATUS_SUCCESS;
if (rDefaultKey.ucUnicast && rDefaultKey.ucMulticast)
fgDef = TRUE;
if (!rDefaultKey.ucUnicast && rDefaultKey.ucMulticast)
fgMgtDef = TRUE;
rDefaultKey.ucBssIdx =
prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex;
rStatus = kalIoctl(prGlueInfo, wlanoidSetDefaultKey, &rDefaultKey,
sizeof(struct PARAM_DEFAULT_KEY),
FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus == WLAN_STATUS_SUCCESS)
i4Rst = 0;
return i4Rst;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for getting station information such as
* RSSI
*
* @param
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
#if KERNEL_VERSION(3, 16, 0) <= CFG80211_VERSION_CODE
int mtk_cfg80211_get_station(struct wiphy *wiphy,
struct net_device *ndev, const u8 *mac,
struct station_info *sinfo)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint32_t rStatus;
uint8_t arBssid[PARAM_MAC_ADDR_LEN];
uint32_t u4BufLen, u4Rate;
int32_t i4Rssi;
struct PARAM_GET_STA_STATISTICS rQueryStaStatistics;
uint32_t u4TotalError;
struct net_device_stats *prDevStats;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
DBGLOG(REQ, TRACE, "mtk_cfg80211_get_station\n");
kalMemZero(arBssid, MAC_ADDR_LEN);
wlanQueryInformation(prGlueInfo->prAdapter, wlanoidQueryBssid,
&arBssid[0], sizeof(arBssid), &u4BufLen);
/* 1. check input MAC address */
/* On Android O, this might be wlan0 address */
if (UNEQUAL_MAC_ADDR(arBssid, mac)
&& UNEQUAL_MAC_ADDR(
prGlueInfo->prAdapter->rWifiVar.aucMacAddress, mac)) {
/* wrong MAC address */
DBGLOG(REQ, WARN,
"incorrect BSSID: [" MACSTR
"] currently connected BSSID["
MACSTR "]\n",
MAC2STR(mac), MAC2STR(arBssid));
return -ENOENT;
}
/* 2. fill TX rate */
if (prGlueInfo->eParamMediaStateIndicated !=
PARAM_MEDIA_STATE_CONNECTED) {
/* not connected */
DBGLOG(REQ, WARN, "not yet connected\n");
return 0;
}
rStatus = kalIoctl(prGlueInfo, wlanoidQueryLinkSpeed, &u4Rate,
sizeof(u4Rate), TRUE, FALSE, FALSE, &u4BufLen);
#if KERNEL_VERSION(4, 0, 0) <= CFG80211_VERSION_CODE
sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
#else
sinfo->filled |= STATION_INFO_TX_BITRATE;
#endif
if ((rStatus != WLAN_STATUS_SUCCESS) || (u4Rate == 0)) {
/* unable to retrieve link speed */
DBGLOG(REQ, WARN, "last link speed\n");
sinfo->txrate.legacy = prGlueInfo->u4LinkSpeedCache;
} else {
/* convert from 100bps to 100kbps */
sinfo->txrate.legacy = u4Rate / 1000;
prGlueInfo->u4LinkSpeedCache = u4Rate / 1000;
}
/* 3. fill RSSI */
rStatus = kalIoctl(prGlueInfo, wlanoidQueryRssi, &i4Rssi,
sizeof(i4Rssi), TRUE, FALSE, FALSE, &u4BufLen);
#if KERNEL_VERSION(4, 0, 0) <= CFG80211_VERSION_CODE
sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
#else
sinfo->filled |= STATION_INFO_SIGNAL;
#endif
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(REQ, WARN,
"Query RSSI failed, use last RSSI %d\n",
prGlueInfo->i4RssiCache);
sinfo->signal = prGlueInfo->i4RssiCache ?
prGlueInfo->i4RssiCache :
PARAM_WHQL_RSSI_INITIAL_DBM;
} else if (i4Rssi == PARAM_WHQL_RSSI_MIN_DBM ||
i4Rssi == PARAM_WHQL_RSSI_MAX_DBM) {
DBGLOG(REQ, WARN,
"RSSI abnormal, use last RSSI %d\n",
prGlueInfo->i4RssiCache);
sinfo->signal = prGlueInfo->i4RssiCache ?
prGlueInfo->i4RssiCache : i4Rssi;
} else {
sinfo->signal = i4Rssi; /* dBm */
prGlueInfo->i4RssiCache = i4Rssi;
}
/* Get statistics from net_dev */
prDevStats = (struct net_device_stats *)kalGetStats(ndev);
if (prDevStats) {
/* 4. fill RX_PACKETS */
#if KERNEL_VERSION(4, 0, 0) <= CFG80211_VERSION_CODE
sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES64);
#else
sinfo->filled |= STATION_INFO_RX_PACKETS;
sinfo->filled |= NL80211_STA_INFO_RX_BYTES64;
#endif
sinfo->rx_packets = prDevStats->rx_packets;
sinfo->rx_bytes = prDevStats->rx_bytes;
/* 5. fill TX_PACKETS */
#if KERNEL_VERSION(4, 0, 0) <= CFG80211_VERSION_CODE
sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES64);
#else
sinfo->filled |= STATION_INFO_TX_PACKETS;
sinfo->filled |= NL80211_STA_INFO_TX_BYTES64;
#endif
sinfo->tx_packets = prDevStats->tx_packets;
sinfo->tx_bytes = prDevStats->tx_bytes;
/* 6. fill TX_FAILED */
kalMemZero(&rQueryStaStatistics,
sizeof(rQueryStaStatistics));
COPY_MAC_ADDR(rQueryStaStatistics.aucMacAddr, arBssid);
rQueryStaStatistics.ucReadClear = TRUE;
rStatus = kalIoctl(prGlueInfo, wlanoidQueryStaStatistics,
&rQueryStaStatistics,
sizeof(rQueryStaStatistics),
TRUE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(REQ, WARN,
"link speed=%u, rssi=%d, unable to retrieve link speed,status=%u\n",
sinfo->txrate.legacy, sinfo->signal, rStatus);
} else {
DBGLOG(REQ, TRACE,
"link speed=%u, rssi=%d, BSSID:[" MACSTR
"], TxFail=%u, TxTimeOut=%u, TxOK=%u, RxOK=%u\n",
sinfo->txrate.legacy, sinfo->signal,
MAC2STR(arBssid),
rQueryStaStatistics.u4TxFailCount,
rQueryStaStatistics.u4TxLifeTimeoutCount,
sinfo->tx_packets, sinfo->rx_packets);
u4TotalError = rQueryStaStatistics.u4TxFailCount +
rQueryStaStatistics.u4TxLifeTimeoutCount;
prDevStats->tx_errors += u4TotalError;
}
#if KERNEL_VERSION(4, 0, 0) <= CFG80211_VERSION_CODE
sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED);
#else
sinfo->filled |= STATION_INFO_TX_FAILED;
#endif
sinfo->tx_failed = prDevStats->tx_errors;
}
return 0;
}
#else
int mtk_cfg80211_get_station(struct wiphy *wiphy,
struct net_device *ndev, u8 *mac,
struct station_info *sinfo)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint32_t rStatus;
uint8_t arBssid[PARAM_MAC_ADDR_LEN];
uint32_t u4BufLen, u4Rate;
int32_t i4Rssi;
struct PARAM_GET_STA_STATISTICS rQueryStaStatistics;
uint32_t u4TotalError;
struct net_device_stats *prDevStats;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
DBGLOG(REQ, TRACE, "mtk_cfg80211_get_station\n");
kalMemZero(arBssid, MAC_ADDR_LEN);
wlanQueryInformation(prGlueInfo->prAdapter, wlanoidQueryBssid,
&arBssid[0], sizeof(arBssid), &u4BufLen);
/* 1. check BSSID */
if (UNEQUAL_MAC_ADDR(arBssid, mac)) {
/* wrong MAC address */
DBGLOG(REQ, WARN,
"incorrect BSSID: [" MACSTR
"] currently connected BSSID["
MACSTR "]\n",
MAC2STR(mac), MAC2STR(arBssid));
return -ENOENT;
}
/* 2. fill TX rate */
if (prGlueInfo->eParamMediaStateIndicated !=
PARAM_MEDIA_STATE_CONNECTED) {
/* not connected */
DBGLOG(REQ, WARN, "not yet connected\n");
} else {
rStatus = kalIoctl(prGlueInfo, wlanoidQueryLinkSpeed, &u4Rate,
sizeof(u4Rate), TRUE, FALSE, FALSE, &u4BufLen);
sinfo->filled |= STATION_INFO_TX_BITRATE;
if ((rStatus != WLAN_STATUS_SUCCESS) || (u4Rate == 0)) {
/* unable to retrieve link speed */
DBGLOG(REQ, WARN, "last link speed\n");
sinfo->txrate.legacy = prGlueInfo->u4LinkSpeedCache;
} else {
/* convert from 100bps to 100kbps */
sinfo->txrate.legacy = u4Rate / 1000;
prGlueInfo->u4LinkSpeedCache = u4Rate / 1000;
}
}
/* 3. fill RSSI */
if (prGlueInfo->eParamMediaStateIndicated !=
PARAM_MEDIA_STATE_CONNECTED) {
/* not connected */
DBGLOG(REQ, WARN, "not yet connected\n");
} else {
rStatus = kalIoctl(prGlueInfo, wlanoidQueryRssi, &i4Rssi,
sizeof(i4Rssi), TRUE, FALSE, FALSE, &u4BufLen);
sinfo->filled |= STATION_INFO_SIGNAL;
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(REQ, WARN,
"Query RSSI failed, use last RSSI %d\n",
prGlueInfo->i4RssiCache);
sinfo->signal = prGlueInfo->i4RssiCache ?
prGlueInfo->i4RssiCache :
PARAM_WHQL_RSSI_INITIAL_DBM;
} else if (i4Rssi == PARAM_WHQL_RSSI_MIN_DBM ||
i4Rssi == PARAM_WHQL_RSSI_MAX_DBM) {
DBGLOG(REQ, WARN,
"RSSI abnormal, use last RSSI %d\n",
prGlueInfo->i4RssiCache);
sinfo->signal = prGlueInfo->i4RssiCache ?
prGlueInfo->i4RssiCache : i4Rssi;
} else {
sinfo->signal = i4Rssi; /* dBm */
prGlueInfo->i4RssiCache = i4Rssi;
}
}
/* Get statistics from net_dev */
prDevStats = (struct net_device_stats *)kalGetStats(ndev);
if (prDevStats) {
/* 4. fill RX_PACKETS */
sinfo->filled |= STATION_INFO_RX_PACKETS;
sinfo->rx_packets = prDevStats->rx_packets;
/* 5. fill TX_PACKETS */
sinfo->filled |= STATION_INFO_TX_PACKETS;
sinfo->tx_packets = prDevStats->tx_packets;
/* 6. fill TX_FAILED */
kalMemZero(&rQueryStaStatistics,
sizeof(rQueryStaStatistics));
COPY_MAC_ADDR(rQueryStaStatistics.aucMacAddr, arBssid);
rQueryStaStatistics.ucReadClear = TRUE;
rStatus = kalIoctl(prGlueInfo, wlanoidQueryStaStatistics,
&rQueryStaStatistics,
sizeof(rQueryStaStatistics),
TRUE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(REQ, WARN,
"link speed=%u, rssi=%d, unable to get sta statistics: status=%u\n",
sinfo->txrate.legacy, sinfo->signal, rStatus);
} else {
DBGLOG(REQ, INFO,
"link speed=%u, rssi=%d, BSSID=[" MACSTR
"], TxFailCount=%d, LifeTimeOut=%d\n",
sinfo->txrate.legacy, sinfo->signal,
MAC2STR(arBssid),
rQueryStaStatistics.u4TxFailCount,
rQueryStaStatistics.u4TxLifeTimeoutCount);
u4TotalError = rQueryStaStatistics.u4TxFailCount +
rQueryStaStatistics.u4TxLifeTimeoutCount;
prDevStats->tx_errors += u4TotalError;
}
sinfo->filled |= STATION_INFO_TX_FAILED;
sinfo->tx_failed = prDevStats->tx_errors;
}
return 0;
}
#endif
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for getting statistics for Link layer
* statistics
*
* @param
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
int mtk_cfg80211_get_link_statistics(struct wiphy *wiphy,
struct net_device *ndev, u8 *mac,
struct station_info *sinfo)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint32_t rStatus;
uint8_t arBssid[PARAM_MAC_ADDR_LEN];
uint32_t u4BufLen;
int32_t i4Rssi;
struct PARAM_GET_STA_STATISTICS rQueryStaStatistics;
struct PARAM_GET_BSS_STATISTICS rQueryBssStatistics;
struct net_device_stats *prDevStats;
struct NETDEV_PRIVATE_GLUE_INFO *prNetDevPrivate =
(struct NETDEV_PRIVATE_GLUE_INFO *) NULL;
uint8_t ucBssIndex;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
kalMemZero(arBssid, MAC_ADDR_LEN);
wlanQueryInformation(prGlueInfo->prAdapter, wlanoidQueryBssid,
&arBssid[0], sizeof(arBssid), &u4BufLen);
/* 1. check BSSID */
if (UNEQUAL_MAC_ADDR(arBssid, mac)) {
/* wrong MAC address */
DBGLOG(REQ, WARN,
"incorrect BSSID: [" MACSTR
"] currently connected BSSID["
MACSTR "]\n",
MAC2STR(mac), MAC2STR(arBssid));
return -ENOENT;
}
/* 2. fill RSSI */
if (prGlueInfo->eParamMediaStateIndicated !=
PARAM_MEDIA_STATE_CONNECTED) {
/* not connected */
DBGLOG(REQ, WARN, "not yet connected\n");
} else {
rStatus = kalIoctl(prGlueInfo, wlanoidQueryRssi, &i4Rssi,
sizeof(i4Rssi), TRUE, FALSE, FALSE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
DBGLOG(REQ, WARN, "unable to retrieve rssi\n");
}
/* Get statistics from net_dev */
prDevStats = (struct net_device_stats *)kalGetStats(ndev);
/*3. get link layer statistics from Driver and FW */
if (prDevStats) {
/* 3.1 get per-STA link statistics */
kalMemZero(&rQueryStaStatistics,
sizeof(rQueryStaStatistics));
COPY_MAC_ADDR(rQueryStaStatistics.aucMacAddr, arBssid);
rQueryStaStatistics.ucLlsReadClear =
FALSE; /* dont clear for get BSS statistic */
rStatus = kalIoctl(prGlueInfo, wlanoidQueryStaStatistics,
&rQueryStaStatistics,
sizeof(rQueryStaStatistics),
TRUE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
DBGLOG(REQ, WARN,
"unable to retrieve per-STA link statistics\n");
/*3.2 get per-BSS link statistics */
if (rStatus == WLAN_STATUS_SUCCESS) {
/* get Bss Index from ndev */
prNetDevPrivate = (struct NETDEV_PRIVATE_GLUE_INFO *)
netdev_priv(ndev);
ASSERT(prNetDevPrivate->prGlueInfo == prGlueInfo);
ucBssIndex = prNetDevPrivate->ucBssIdx;
kalMemZero(&rQueryBssStatistics,
sizeof(rQueryBssStatistics));
rQueryBssStatistics.ucBssIndex = ucBssIndex;
rStatus = kalIoctl(prGlueInfo,
wlanoidQueryBssStatistics,
&rQueryBssStatistics,
sizeof(rQueryBssStatistics),
TRUE, FALSE, TRUE, &u4BufLen);
} else {
DBGLOG(REQ, WARN,
"unable to retrieve per-BSS link statistics\n");
}
}
return 0;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for requesting to do a scan
*
* @param
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
int mtk_cfg80211_scan(struct wiphy *wiphy,
struct cfg80211_scan_request *request)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint32_t rStatus;
uint32_t i, j, u4BufLen;
struct PARAM_SCAN_REQUEST_ADV *prScanRequest;
uint32_t num_ssid = 0;
uint32_t old_num_ssid = 0;
uint32_t u4ValidIdx = 0;
uint32_t wildcard_flag = 0;
#if (CFG_SUPPORT_QA_TOOL == 1) || (CFG_SUPPORT_LOWLATENCY_MODE == 1)
struct ADAPTER *prAdapter = NULL;
#endif
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!prGlueInfo) {
DBGLOG(REQ, ERROR, "prGlueInfo is NULL");
return -EINVAL;
}
DBGLOG(REQ, TRACE, "mtk_cfg80211_scan\n");
#if (CFG_SUPPORT_QA_TOOL == 1) || (CFG_SUPPORT_LOWLATENCY_MODE == 1)
prAdapter = prGlueInfo->prAdapter;
if (prGlueInfo->prAdapter == NULL) {
DBGLOG(REQ, ERROR, "prGlueInfo->prAdapter is NULL");
return -EINVAL;
}
#endif
#if CFG_SUPPORT_QA_TOOL
if (prAdapter->fgIcapMode) {
DBGLOG(REQ, ERROR, "prAdapter->fgIcapMode == TRUE\n");
return -EBUSY;
}
#endif
kalScanReqLog(request);
/* check if there is any pending scan/sched_scan not yet finished */
if (prGlueInfo->prScanRequest != NULL) {
DBGLOG(REQ, ERROR, "prGlueInfo->prScanRequest != NULL\n");
return -EBUSY;
}
#if CFG_SUPPORT_LOWLATENCY_MODE
if (!prGlueInfo->prAdapter->fgEnCfg80211Scan
&& PARAM_MEDIA_STATE_CONNECTED
== kalGetMediaStateIndicated(prGlueInfo)) {
DBGLOG(REQ, INFO,
"mtk_cfg80211_scan LowLatency reject scan\n");
return -EBUSY;
}
#endif /* CFG_SUPPORT_LOWLATENCY_MODE */
#if CFG_SUPPORT_SCAN_CACHE_RESULT
prGlueInfo->scanCache.prGlueInfo = prGlueInfo;
prGlueInfo->scanCache.prRequest = request;
prGlueInfo->scanCache.n_channels = (uint32_t) request->n_channels;
if (isScanCacheDone(&prGlueInfo->scanCache) == TRUE)
return 0;
#endif /* CFG_SUPPORT_SCAN_CACHE_RESULT */
prScanRequest = kalMemAlloc(sizeof(struct PARAM_SCAN_REQUEST_ADV),
VIR_MEM_TYPE);
if (prScanRequest == NULL) {
DBGLOG(REQ, ERROR, "alloc scan request fail\n");
return -ENOMEM;
}
kalMemZero(prScanRequest,
sizeof(struct PARAM_SCAN_REQUEST_ADV));
if (request->n_ssids == 0) {
prScanRequest->u4SsidNum = 0;
prScanRequest->ucScanType = SCAN_TYPE_PASSIVE_SCAN;
} else if ((request->ssids) && (request->n_ssids > 0)
&& (request->n_ssids <= (SCN_SSID_MAX_NUM + 1))) {
num_ssid = (uint32_t)request->n_ssids;
old_num_ssid = (uint32_t)request->n_ssids;
u4ValidIdx = 0;
for (i = 0; i < request->n_ssids; i++) {
if ((request->ssids[i].ssid[0] == 0)
|| (request->ssids[i].ssid_len == 0)) {
/* remove if this is a wildcard scan */
num_ssid--;
wildcard_flag |= (1 << i);
DBGLOG(REQ, TRACE, "i=%d, wildcard scan\n", i);
continue;
}
COPY_SSID(prScanRequest->rSsid[u4ValidIdx].aucSsid,
prScanRequest->rSsid[u4ValidIdx].u4SsidLen,
request->ssids[i].ssid,
request->ssids[i].ssid_len);
if (prScanRequest->rSsid[u4ValidIdx].u4SsidLen >
ELEM_MAX_LEN_SSID) {
prScanRequest->rSsid[u4ValidIdx].u4SsidLen =
ELEM_MAX_LEN_SSID;
}
DBGLOG(REQ, INFO,
"i=%d, u4ValidIdx=%d, Ssid=%s, SsidLen=%d\n",
i, u4ValidIdx,
prScanRequest->rSsid[u4ValidIdx].aucSsid,
prScanRequest->rSsid[u4ValidIdx].u4SsidLen);
u4ValidIdx++;
if (u4ValidIdx == SCN_SSID_MAX_NUM) {
DBGLOG(REQ, TRACE, "SCN_SSID_MAX_NUM\n");
break;
}
}
/* real SSID number to firmware */
prScanRequest->u4SsidNum = u4ValidIdx;
prScanRequest->ucScanType = SCAN_TYPE_ACTIVE_SCAN;
} else {
DBGLOG(REQ, ERROR, "request->n_ssids:%d\n",
request->n_ssids);
kalMemFree(prScanRequest,
sizeof(struct PARAM_SCAN_REQUEST_ADV), VIR_MEM_TYPE);
return -EINVAL;
}
DBGLOG(REQ, INFO,
"mtk_cfg80211_scan(), n_ssids=%d, num_ssid=(%u->%u), wildcard=0x%X\n",
request->n_ssids, old_num_ssid, num_ssid, wildcard_flag);
/* Set channel info */
if (request->n_channels > MAXIMUM_OPERATION_CHANNEL_LIST) {
prScanRequest->u4ChannelNum = 0;
DBGLOG(REQ, INFO,
"Channel list %u exceed maximum support.\n",
request->n_channels);
} else {
j = 0;
for (i = 0; i < request->n_channels; i++) {
uint32_t u4channel =
nicFreq2ChannelNum(request->channels[i]->center_freq *
1000);
if (u4channel == 0) {
DBGLOG(REQ, WARN, "Wrong Channel[%d] freq=%u\n",
i, request->channels[i]->center_freq);
continue;
}
prScanRequest->arChannel[j].ucChannelNum = u4channel;
switch ((request->channels[i])->band) {
case KAL_BAND_2GHZ:
prScanRequest->arChannel[j].eBand = BAND_2G4;
break;
case KAL_BAND_5GHZ:
prScanRequest->arChannel[j].eBand = BAND_5G;
break;
default:
DBGLOG(REQ, WARN, "UNKNOWN Band %d(chnl=%u)\n",
request->channels[i]->band,
u4channel);
prScanRequest->arChannel[j].eBand = BAND_NULL;
break;
}
j++;
}
prScanRequest->u4ChannelNum = j;
}
DBGLOG(REQ, INFO, "n_ssids(%d==>%u) n_channel(%u==>%u)\n",
request->n_ssids, num_ssid, request->n_channels,
prScanRequest->u4ChannelNum);
if (kalScanParseRandomMac(request->wdev->netdev,
request, prScanRequest->aucRandomMac)) {
prScanRequest->ucScnFuncMask |= ENUM_SCN_RANDOM_MAC_EN;
}
if (request->ie_len > 0) {
prScanRequest->u4IELength = request->ie_len;
prScanRequest->pucIE = (uint8_t *) (request->ie);
}
prGlueInfo->prScanRequest = request;
rStatus = kalIoctl(prGlueInfo, wlanoidSetBssidListScanAdv,
prScanRequest, sizeof(struct PARAM_SCAN_REQUEST_ADV),
FALSE, FALSE, FALSE, &u4BufLen);
kalMemFree(prScanRequest,
sizeof(struct PARAM_SCAN_REQUEST_ADV), VIR_MEM_TYPE);
if (rStatus != WLAN_STATUS_SUCCESS) {
prGlueInfo->prScanRequest = NULL;
DBGLOG(REQ, WARN, "scan error:%x\n", rStatus);
return -EINVAL;
}
return 0;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for abort an ongoing scan. The driver
* shall indicate the status of the scan through cfg80211_scan_done()
*
* @param wiphy - pointer of wireless hardware description
* wdev - pointer of wireless device state
*
*/
/*----------------------------------------------------------------------------*/
void mtk_cfg80211_abort_scan(struct wiphy *wiphy,
struct wireless_dev *wdev)
{
uint32_t u4SetInfoLen = 0;
uint32_t rStatus;
struct GLUE_INFO *prGlueInfo = NULL;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
scanlog_dbg(LOG_SCAN_ABORT_REQ_K2D, INFO, "mtk_cfg80211_abort_scan\n");
rStatus = kalIoctl(prGlueInfo,
wlanoidAbortScan,
NULL, 1, FALSE, FALSE, TRUE, &u4SetInfoLen);
if (rStatus != WLAN_STATUS_SUCCESS)
DBGLOG(REQ, ERROR, "wlanoidAbortScan fail 0x%x\n", rStatus);
}
#if CFG_SUPPORT_CFG80211_AUTH
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for requesting auth to
* the ESS with the specified parameters
*
* @param
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
int mtk_cfg80211_auth(struct wiphy *wiphy, struct net_device *ndev,
struct cfg80211_auth_request *req)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint32_t rStatus;
uint32_t u4BufLen;
struct PARAM_CONNECT rNewSsid;
enum ENUM_PARAM_OP_MODE eOpMode;
struct CONNECTION_SETTINGS *prConnSettings = NULL;
#if CFG_SUPPORT_REPLAY_DETECTION
struct GL_DETECT_REPLAY_INFO *prDetRplyInfo = NULL;
#endif
struct PARAM_WEP *prWepKey = NULL;
int ret = 0;
/*Is auth parameter needed to be updated to AIS.*/
uint8_t fgNewAuthParam = FALSE;
#if CFG_SUPPORT_802_11R
uint32_t u4InfoBufLen = 0;
#endif
const struct cfg80211_bss_ies *ies;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
#if KERNEL_VERSION(4, 10, 0) > CFG80211_VERSION_CODE
if (req->sae_data_len != 0)
DBGLOG(REQ, INFO, "[wlan] mtk_cfg80211_auth %p %zu\n",
req->sae_data, req->sae_data_len);
#else
if (req->auth_data_len != 0)
DBGLOG(REQ, INFO, "[wlan] mtk_cfg80211_auth %p %zu\n",
req->auth_data, req->auth_data_len);
#endif
DBGLOG(REQ, INFO, "auth to BSS [" MACSTR "]\n",
MAC2STR((uint8_t *)req->bss->bssid));
DBGLOG(REQ, INFO, "auth_type:%d\n", req->auth_type);
prConnSettings = &prGlueInfo->prAdapter->rWifiVar.rConnSettings;
/* <1>Set OP mode */
if (prGlueInfo->prAdapter->rWifiVar.rConnSettings.eOPMode >
NET_TYPE_AUTO_SWITCH)
eOpMode = NET_TYPE_AUTO_SWITCH;
else
eOpMode = prGlueInfo->prAdapter->rWifiVar.rConnSettings.eOPMode;
rStatus = kalIoctl(prGlueInfo, wlanoidSetInfrastructureMode, &eOpMode,
sizeof(eOpMode), FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, INFO, "wlanoidSetInfrastructureMode fail 0x%x\n",
rStatus);
return -EFAULT;
}
/*<2> Set Auth data */
prConnSettings->ucAuthDataLen = 0;
#if KERNEL_VERSION(4, 10, 0) > CFG80211_VERSION_CODE
if (req->sae_data_len != 0) {
if (req->sae_data_len > AUTH_DATA_MAX_LEN) {
DBGLOG(INIT, WARN,
"request auth with unexpected length:%d\n",
req->sae_data_len);
return -EFAULT;
}
kalMemCopy(prConnSettings->aucAuthData, req->sae_data,
req->sae_data_len);
prConnSettings->ucAuthDataLen = req->sae_data_len;
DBGLOG(INIT, INFO,
"Dump auth data in connectSettings, auth len:%d\n",
prConnSettings->ucAuthDataLen);
DBGLOG_MEM8(REQ, INFO, prConnSettings->aucAuthData,
req->sae_data_len);
}
#else
if (req->auth_data_len != 0) {
if (req->auth_data_len > AUTH_DATA_MAX_LEN) {
DBGLOG(INIT, WARN,
"request auth with unexpected length:%d\n",
req->auth_data_len);
return -EFAULT;
}
kalMemCopy(prConnSettings->aucAuthData, req->auth_data,
req->auth_data_len);
prConnSettings->ucAuthDataLen = req->auth_data_len;
DBGLOG(INIT, INFO,
"Dump auth data in connectSettings, auth len:%d\n",
prConnSettings->ucAuthDataLen);
DBGLOG_MEM8(REQ, INFO, prConnSettings->aucAuthData,
req->auth_data_len);
}
#endif
/*<3> Set ChannelNum */
if (req->bss->channel->center_freq) {
prConnSettings->ucChannelNum =
nicFreq2ChannelNum(
req->bss->channel->center_freq * 1000);
DBGLOG(RSN, INFO,
"set prConnSettings->ucChannelNum:%d\n",
prConnSettings->ucChannelNum);
} else {
prConnSettings->ucChannelNum = 0;
DBGLOG(RSN, INFO,
"req->bss->channel->center_freq is NULL.\n");
}
#if CFG_SUPPORT_REPLAY_DETECTION
/* reset Detect replay information */
prDetRplyInfo = &prGlueInfo->prDetRplyInfo;
kalMemZero(prDetRplyInfo, sizeof(struct GL_DETECT_REPLAY_INFO));
#endif
switch (req->auth_type) {
case NL80211_AUTHTYPE_OPEN_SYSTEM:
if (!(prGlueInfo->rWpaInfo.u4AuthAlg & AUTH_TYPE_OPEN_SYSTEM))
fgNewAuthParam = TRUE;
prGlueInfo->rWpaInfo.u4AuthAlg = 0;
prGlueInfo->rWpaInfo.u4AuthAlg |= AUTH_TYPE_OPEN_SYSTEM;
break;
case NL80211_AUTHTYPE_SHARED_KEY:
if (!(prGlueInfo->rWpaInfo.u4AuthAlg & AUTH_TYPE_SHARED_KEY))
fgNewAuthParam = TRUE;
prGlueInfo->rWpaInfo.u4AuthAlg = 0;
prGlueInfo->rWpaInfo.u4AuthAlg |= AUTH_TYPE_SHARED_KEY;
break;
case NL80211_AUTHTYPE_SAE:
if (!(prGlueInfo->rWpaInfo.u4AuthAlg & AUTH_TYPE_SAE))
fgNewAuthParam = TRUE;
prGlueInfo->rWpaInfo.u4AuthAlg = 0;
prGlueInfo->rWpaInfo.u4AuthAlg |= AUTH_TYPE_SAE;
break;
#if CFG_SUPPORT_802_11R
case NL80211_AUTHTYPE_FT:
if (!(prGlueInfo->rWpaInfo.u4AuthAlg
& AUTH_TYPE_FAST_BSS_TRANSITION))
fgNewAuthParam = TRUE;
prGlueInfo->rWpaInfo.u4AuthAlg = 0;
prGlueInfo->rWpaInfo.u4AuthAlg |= AUTH_TYPE_FAST_BSS_TRANSITION;
break;
#endif
default:
DBGLOG(REQ, WARN,
"Auth type: %ld not support, use default OPEN system\n",
req->auth_type);
prGlueInfo->rWpaInfo.u4AuthAlg = 0;
prGlueInfo->rWpaInfo.u4AuthAlg |= AUTH_TYPE_OPEN_SYSTEM;
break;
}
DBGLOG(REQ, INFO, "Auth Algorithm : %ld\n",
prGlueInfo->rWpaInfo.u4AuthAlg);
DBGLOG(REQ, INFO, "fgNewAuthParam %d\n",
fgNewAuthParam);
if (req->key_len != 0) {
/* NL80211 only set the Tx wep key while connect,
* the max 4 wep key set prior via add key cmd
*/
if (!(prGlueInfo->rWpaInfo.u4AuthAlg & AUTH_TYPE_SHARED_KEY))
DBGLOG(REQ, WARN, "Auth Algorithm : %ld with wep key\n",
prGlueInfo->rWpaInfo.u4AuthAlg);
prWepKey = (struct PARAM_WEP *)kalMemAlloc(
sizeof(struct PARAM_WEP), VIR_MEM_TYPE);
if (prWepKey == NULL) {
DBGLOG(REQ, ERROR, "alloc buffer fail\n");
return -ENOMEM;
}
kalMemZero(prWepKey, sizeof(struct PARAM_WEP));
prWepKey->u4Length =
OFFSET_OF(struct PARAM_WEP, aucKeyMaterial) +
req->key_len;
prWepKey->u4KeyLength = (uint32_t) req->key_len;
prWepKey->u4KeyIndex = (uint32_t) req->key_idx;
prWepKey->u4KeyIndex |= IS_TRANSMIT_KEY;
if (prWepKey->u4KeyLength > MAX_KEY_LEN) {
DBGLOG(REQ, WARN, "Too long key length (%u)\n",
prWepKey->u4KeyLength);
ret = -EINVAL;
goto freeBuf;
}
kalMemCopy(prWepKey->aucKeyMaterial, req->key,
prWepKey->u4KeyLength);
rStatus = kalIoctl(prGlueInfo, wlanoidSetAddWep, prWepKey,
prWepKey->u4Length, FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, INFO, "wlanoidSetAddWep fail 0x%x\n",
rStatus);
ret = -EFAULT;
goto freeBuf;
}
}
kalMemZero(&rNewSsid, sizeof(struct PARAM_CONNECT));
rNewSsid.pucBssid = (uint8_t *)req->bss->bssid;
if (!EQUAL_MAC_ADDR(rNewSsid.pucBssid, prConnSettings->aucBSSID)) {
DBGLOG(REQ, INFO, "previous connect bssid is " MACSTR "\n",
MAC2STR((uint8_t *)prConnSettings->aucBSSID));
fgNewAuthParam = TRUE;
}
#if CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT || CFG_SUPPORT_802_11R
ies = rcu_access_pointer(req->bss->ies);
if (ies != NULL && ies->len != 0 &&
IE_ID(ies->data) == ELEM_ID_SSID) {
rNewSsid.pucSsid = SSID_IE(ies->data)->aucSSID;
rNewSsid.u4SsidLen = SSID_IE(ies->data)->ucLength;
DBGLOG(REQ, STATE, "SSID len %d, ssid %s, %d\n",
ies->len, SSID_IE(ies->data)->aucSSID,
SSID_IE(ies->data)->ucLength);
}
#endif
#if CFG_SUPPORT_802_11R
if (req->auth_type == NL80211_AUTHTYPE_FT) {
rStatus = kalIoctl(prGlueInfo, wlanoidUpdateFtIes,
(void *)(uint8_t *)req->ie, req->ie_len,
FALSE, FALSE, FALSE, &u4InfoBufLen);
DBGLOG(REQ, TRACE,
"wlanoidUpdateFtIes rStatus 0x%x\n", rStatus);
}
#endif
DBGLOG(REQ, INFO, "auth to BSS [" MACSTR "],UpperReq [" MACSTR "]\n",
MAC2STR(rNewSsid.pucBssid),
MAC2STR((uint8_t *)req->bss->bssid));
prConnSettings->fgIsSendAssoc = FALSE;
if (!prConnSettings->fgIsConnInitialized || fgNewAuthParam) {
/* [TODO] to consider if bssid/auth_alg changed
* (need to update to AIS)
*/
if (fgNewAuthParam)
DBGLOG(REQ, WARN, "auth param update\n");
rStatus = kalIoctl(prGlueInfo, wlanoidSetConnect,
(void *)&rNewSsid, sizeof(struct PARAM_CONNECT),
FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(REQ, WARN, "set SSID:%x\n", rStatus);
ret = -EINVAL;
goto freeBuf;
}
} else {
rStatus = kalIoctl(prGlueInfo, wlanoidSendAuthAssoc,
(void *)req->bss->bssid, MAC_ADDR_LEN,
FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(REQ, WARN, "send auth failed:%x\n", rStatus);
ret = -EINVAL;
goto freeBuf;
}
}
freeBuf:
if (prWepKey)
kalMemFree(prWepKey, VIR_MEM_TYPE, sizeof(struct PARAM_WEP));
return ret;
}
#endif
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for requesting to connect to
* the ESS with the specified parameters
*
* @param
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
int mtk_cfg80211_connect(struct wiphy *wiphy,
struct net_device *ndev,
struct cfg80211_connect_params *sme)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint32_t rStatus;
uint32_t u4BufLen;
enum ENUM_WEP_STATUS eEncStatus;
enum ENUM_PARAM_AUTH_MODE eAuthMode;
uint32_t cipher;
struct PARAM_CONNECT rNewSsid;
u_int8_t fgCarryWPSIE = FALSE;
enum ENUM_PARAM_OP_MODE eOpMode;
uint32_t i, u4AkmSuite = 0;
struct DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY
*prEntry;
struct CONNECTION_SETTINGS *prConnSettings = NULL;
#if CFG_SUPPORT_REPLAY_DETECTION
struct GL_DETECT_REPLAY_INFO *prDetRplyInfo = NULL;
#endif
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
DBGLOG(REQ, STATE, "[wlan] mtk_cfg80211_connect %p %zu %d\n",
sme->ie, sme->ie_len, sme->auth_type);
prConnSettings =
&prGlueInfo->prAdapter->rWifiVar.rConnSettings;
if (prGlueInfo->prAdapter->rWifiVar.rConnSettings.eOPMode >
NET_TYPE_AUTO_SWITCH)
eOpMode = NET_TYPE_AUTO_SWITCH;
else
eOpMode = prGlueInfo->prAdapter->rWifiVar.rConnSettings.eOPMode;
rStatus = kalIoctl(prGlueInfo, wlanoidSetInfrastructureMode,
&eOpMode, sizeof(eOpMode), FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, INFO,
"wlanoidSetInfrastructureMode fail 0x%x\n", rStatus);
return -EFAULT;
}
/* after set operation mode, key table are cleared */
#if CFG_SUPPORT_REPLAY_DETECTION
/* reset Detect replay information */
prDetRplyInfo = &prGlueInfo->prDetRplyInfo;
kalMemZero(prDetRplyInfo,
sizeof(struct GL_DETECT_REPLAY_INFO));
#endif
/* <1> Reset WPA info */
prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED;
prGlueInfo->rWpaInfo.u4KeyMgmt = 0;
prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_NONE;
prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE;
prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM;
prGlueInfo->rWpaInfo.fgPrivacyInvoke = FALSE;
#if CFG_SUPPORT_802_11W
prGlueInfo->rWpaInfo.u4CipherGroupMgmt = IW_AUTH_CIPHER_NONE;
prGlueInfo->rWpaInfo.ucRSNMfpCap = RSN_AUTH_MFP_DISABLED;
prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED;
prGlueInfo->rWpaInfo.ucRSNMfpCap = RSN_AUTH_MFP_DISABLED;
#endif
if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_WPA;
else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
prGlueInfo->rWpaInfo.u4WpaVersion =
IW_AUTH_WPA_VERSION_WPA2;
else
prGlueInfo->rWpaInfo.u4WpaVersion =
IW_AUTH_WPA_VERSION_DISABLED;
switch (sme->auth_type) {
case NL80211_AUTHTYPE_OPEN_SYSTEM:
prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM;
break;
case NL80211_AUTHTYPE_SHARED_KEY:
prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_SHARED_KEY;
break;
case NL80211_AUTHTYPE_FT:
prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_FT;
break;
default:
/* NL80211 only set the Tx wep key while connect */
if (sme->key_len != 0)
prGlueInfo->rWpaInfo.u4AuthAlg =
IW_AUTH_ALG_OPEN_SYSTEM |
IW_AUTH_ALG_SHARED_KEY;
else
prGlueInfo->rWpaInfo.u4AuthAlg =
IW_AUTH_ALG_OPEN_SYSTEM;
break;
}
if (sme->crypto.n_ciphers_pairwise) {
DBGLOG(RSN, INFO, "[wlan] cipher pairwise (%x)\n",
sme->crypto.ciphers_pairwise[0]);
prGlueInfo->prAdapter->rWifiVar.rConnSettings.rRsnInfo
.au4PairwiseKeyCipherSuite[0] = sme->crypto.ciphers_pairwise[0];
switch (sme->crypto.ciphers_pairwise[0]) {
case WLAN_CIPHER_SUITE_WEP40:
prGlueInfo->rWpaInfo.u4CipherPairwise =
IW_AUTH_CIPHER_WEP40;
break;
case WLAN_CIPHER_SUITE_WEP104:
prGlueInfo->rWpaInfo.u4CipherPairwise =
IW_AUTH_CIPHER_WEP104;
break;
case WLAN_CIPHER_SUITE_TKIP:
prGlueInfo->rWpaInfo.u4CipherPairwise =
IW_AUTH_CIPHER_TKIP;
break;
case WLAN_CIPHER_SUITE_CCMP:
prGlueInfo->rWpaInfo.u4CipherPairwise =
IW_AUTH_CIPHER_CCMP;
break;
case WLAN_CIPHER_SUITE_AES_CMAC:
prGlueInfo->rWpaInfo.u4CipherPairwise =
IW_AUTH_CIPHER_CCMP;
break;
#if CFG_SUPPORT_SUITB
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
prGlueInfo->rWpaInfo.u4CipherPairwise =
IW_AUTH_CIPHER_GCMP256;
break;
case WLAN_CIPHER_SUITE_GCMP_256:
prGlueInfo->rWpaInfo.u4CipherPairwise =
IW_AUTH_CIPHER_GCMP256;
break;
#endif
default:
DBGLOG(REQ, WARN, "invalid cipher pairwise (%d)\n",
sme->crypto.ciphers_pairwise[0]);
return -EINVAL;
}
}
if (sme->crypto.cipher_group) {
prGlueInfo->prAdapter->rWifiVar.rConnSettings.rRsnInfo
.u4GroupKeyCipherSuite = sme->crypto.cipher_group;
switch (sme->crypto.cipher_group) {
case WLAN_CIPHER_SUITE_WEP40:
prGlueInfo->rWpaInfo.u4CipherGroup =
IW_AUTH_CIPHER_WEP40;
break;
case WLAN_CIPHER_SUITE_WEP104:
prGlueInfo->rWpaInfo.u4CipherGroup =
IW_AUTH_CIPHER_WEP104;
break;
case WLAN_CIPHER_SUITE_TKIP:
prGlueInfo->rWpaInfo.u4CipherGroup =
IW_AUTH_CIPHER_TKIP;
break;
case WLAN_CIPHER_SUITE_CCMP:
prGlueInfo->rWpaInfo.u4CipherGroup =
IW_AUTH_CIPHER_CCMP;
break;
case WLAN_CIPHER_SUITE_AES_CMAC:
prGlueInfo->rWpaInfo.u4CipherGroup =
IW_AUTH_CIPHER_CCMP;
break;
case WLAN_CIPHER_SUITE_NO_GROUP_ADDR:
break;
#if CFG_SUPPORT_SUITB
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
prGlueInfo->rWpaInfo.u4CipherGroup =
IW_AUTH_CIPHER_GCMP256;
break;
case WLAN_CIPHER_SUITE_GCMP_256:
prGlueInfo->rWpaInfo.u4CipherGroup =
IW_AUTH_CIPHER_GCMP256;
break;
#endif
default:
DBGLOG(REQ, WARN, "invalid cipher group (%d)\n",
sme->crypto.cipher_group);
return -EINVAL;
}
}
/* DBGLOG(SCN, INFO, ("akm_suites=%x\n", sme->crypto.akm_suites[0])); */
if (sme->crypto.n_akm_suites) {
prGlueInfo->prAdapter->rWifiVar.rConnSettings.rRsnInfo
.au4AuthKeyMgtSuite[0] = sme->crypto.akm_suites[0];
if (prGlueInfo->rWpaInfo.u4WpaVersion ==
IW_AUTH_WPA_VERSION_WPA) {
switch (sme->crypto.akm_suites[0]) {
case WLAN_AKM_SUITE_8021X:
eAuthMode = AUTH_MODE_WPA;
u4AkmSuite = WPA_AKM_SUITE_802_1X;
break;
case WLAN_AKM_SUITE_PSK:
eAuthMode = AUTH_MODE_WPA_PSK;
u4AkmSuite = WPA_AKM_SUITE_PSK;
break;
default:
DBGLOG(REQ, WARN, "invalid Akm Suite (%d)\n",
sme->crypto.akm_suites[0]);
return -EINVAL;
}
} else if (prGlueInfo->rWpaInfo.u4WpaVersion ==
IW_AUTH_WPA_VERSION_WPA2) {
switch (sme->crypto.akm_suites[0]) {
case WLAN_AKM_SUITE_8021X:
eAuthMode = AUTH_MODE_WPA2;
u4AkmSuite = RSN_AKM_SUITE_802_1X;
break;
case WLAN_AKM_SUITE_PSK:
eAuthMode = AUTH_MODE_WPA2_PSK;
u4AkmSuite = RSN_AKM_SUITE_PSK;
break;
#if CFG_SUPPORT_802_11R
case WLAN_AKM_SUITE_FT_8021X:
eAuthMode = AUTH_MODE_WPA2_FT;
u4AkmSuite = RSN_AKM_SUITE_FT_802_1X;
break;
case WLAN_AKM_SUITE_FT_PSK:
eAuthMode = AUTH_MODE_WPA2_FT_PSK;
u4AkmSuite = RSN_AKM_SUITE_FT_PSK;
break;
#endif
#if CFG_SUPPORT_802_11W
/* Notice:: Need kernel patch!! */
case WLAN_AKM_SUITE_8021X_SHA256:
eAuthMode = AUTH_MODE_WPA2;
u4AkmSuite = RSN_AKM_SUITE_802_1X_SHA256;
break;
case WLAN_AKM_SUITE_PSK_SHA256:
eAuthMode = AUTH_MODE_WPA2_PSK;
u4AkmSuite = RSN_AKM_SUITE_PSK_SHA256;
break;
#endif
#if CFG_SUPPORT_PASSPOINT
case WLAN_AKM_SUITE_OSEN:
eAuthMode = AUTH_MODE_WPA_OSEN;
u4AkmSuite = WFA_AKM_SUITE_OSEN;
break;
#endif
#if CFG_SUPPORT_SUITB
case WLAN_AKM_SUITE_8021X_SUITE_B:
eAuthMode = AUTH_MODE_WPA2_PSK;
u4AkmSuite = RSN_AKM_SUITE_8021X_SUITE_B_192;
break;
case WLAN_AKM_SUITE_8021X_SUITE_B_192:
eAuthMode = AUTH_MODE_WPA2_PSK;
u4AkmSuite = RSN_AKM_SUITE_8021X_SUITE_B_192;
break;
#endif
#if CFG_SUPPORT_OWE
case WLAN_AKM_SUITE_OWE:
eAuthMode = AUTH_MODE_WPA2_PSK;
u4AkmSuite = RSN_AKM_SUITE_OWE;
break;
#endif
#if CFG_SUPPORT_DPP
case WLAN_AKM_SUITE_DPP:
eAuthMode = AUTH_MODE_WPA2_PSK;
u4AkmSuite = RSN_AKM_SUITE_DPP;
break;
#endif
default:
DBGLOG(REQ, WARN, "invalid Akm Suite (%d)\n",
sme->crypto.akm_suites[0]);
return -EINVAL;
}
}
}
if (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_DISABLED) {
switch (prGlueInfo->rWpaInfo.u4AuthAlg) {
case IW_AUTH_ALG_OPEN_SYSTEM:
eAuthMode = AUTH_MODE_OPEN;
break;
case IW_AUTH_ALG_FT:
eAuthMode = AUTH_MODE_NON_RSN_FT;
break;
default:
eAuthMode = AUTH_MODE_AUTO_SWITCH;
break;
}
}
prGlueInfo->rWpaInfo.fgPrivacyInvoke = sme->privacy;
prGlueInfo->fgWpsActive = FALSE;
#if CFG_SUPPORT_PASSPOINT
prGlueInfo->fgConnectHS20AP = FALSE;
#endif /* CFG_SUPPORT_PASSPOINT */
prConnSettings->fgOkcEnabled = FALSE;
prConnSettings->fgOkcPmksaReady = FALSE;
prGlueInfo->non_wfa_vendor_ie_len = 0;
if (sme->ie && sme->ie_len > 0) {
uint32_t rStatus;
uint32_t u4BufLen;
uint8_t *prDesiredIE = NULL;
uint8_t *pucIEStart = (uint8_t *)sme->ie;
#if CFG_SUPPORT_WAPI
rStatus = kalIoctl(prGlueInfo, wlanoidSetWapiAssocInfo,
pucIEStart, sme->ie_len, FALSE, FALSE, FALSE,
&u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
DBGLOG(REQ, TRACE,
"[wapi] wapi not support due to set wapi assoc info error:%x\n",
rStatus);
#endif
#if CFG_SUPPORT_WPS2
if (wextSrchDesiredWPSIE(pucIEStart, sme->ie_len, 0xDD,
(uint8_t **) &prDesiredIE)) {
prGlueInfo->fgWpsActive = TRUE;
fgCarryWPSIE = TRUE;
rStatus = kalIoctl(prGlueInfo, wlanoidSetWSCAssocInfo,
prDesiredIE, IE_SIZE(prDesiredIE),
FALSE, FALSE, FALSE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
DBGLOG(SEC, WARN,
"[WSC] set WSC assoc info error:%x\n",
rStatus);
}
#endif
#if CFG_SUPPORT_PASSPOINT
if (wextSrchDesiredHS20IE(pucIEStart, sme->ie_len,
(uint8_t **) &prDesiredIE)) {
rStatus = kalIoctl(prGlueInfo, wlanoidSetHS20Info,
prDesiredIE, IE_SIZE(prDesiredIE),
FALSE, FALSE, TRUE, &u4BufLen);
#if 0
if (rStatus != WLAN_STATUS_SUCCESS)
DBGLOG(INIT, INFO,
"[HS20] set HS20 assoc info error:%x\n",
rStatus);
#endif
}
if (wextSrchDesiredInterworkingIE(pucIEStart, sme->ie_len,
(uint8_t **) &prDesiredIE)) {
rStatus = kalIoctl(prGlueInfo,
wlanoidSetInterworkingInfo, prDesiredIE,
IE_SIZE(prDesiredIE),
FALSE, FALSE, TRUE, &u4BufLen);
#if 0
if (rStatus != WLAN_STATUS_SUCCESS)
DBGLOG(INIT, INFO,
"[HS20] set Interworking assoc info error:%x\n"
, rStatus);
#endif
}
if (wextSrchDesiredRoamingConsortiumIE(pucIEStart, sme->ie_len,
(uint8_t **) &prDesiredIE)) {
rStatus = kalIoctl(prGlueInfo,
wlanoidSetRoamingConsortiumIEInfo, prDesiredIE,
IE_SIZE(prDesiredIE),
FALSE, FALSE, TRUE, &u4BufLen);
#if 0
if (rStatus != WLAN_STATUS_SUCCESS)
DBGLOG(INIT, INFO,
"[HS20] set RoamingConsortium assoc info error:%x\n",
rStatus);
#endif
}
#endif /* CFG_SUPPORT_PASSPOINT */
if (wextSrchDesiredWPAIE(pucIEStart, sme->ie_len, 0x30,
(uint8_t **) &prDesiredIE)) {
struct RSN_INFO rRsnInfo;
if (rsnParseRsnIE(prGlueInfo->prAdapter,
(struct RSN_INFO_ELEM *)prDesiredIE, &rRsnInfo)) {
#if CFG_SUPPORT_802_11W
if (rRsnInfo.u2RsnCap & ELEM_WPA_CAP_MFPC) {
prGlueInfo->rWpaInfo.u4CipherGroupMgmt
= rRsnInfo
.u4GroupMgmtKeyCipherSuite;
prGlueInfo->rWpaInfo.ucRSNMfpCap =
RSN_AUTH_MFP_OPTIONAL;
if (rRsnInfo.u2RsnCap &
ELEM_WPA_CAP_MFPR)
prGlueInfo->rWpaInfo
.ucRSNMfpCap =
RSN_AUTH_MFP_REQUIRED;
} else
prGlueInfo->rWpaInfo.ucRSNMfpCap =
RSN_AUTH_MFP_DISABLED;
#endif
}
}
/* Find non-wfa vendor specific ies set from upper layer */
if (cfg80211_get_non_wfa_vendor_ie(prGlueInfo, pucIEStart,
sme->ie_len) > 0) {
DBGLOG(RSN, INFO, "Found non-wfa vendor ie (len=%u)\n",
prGlueInfo->non_wfa_vendor_ie_len);
}
wextSrchOkcAndPMKID(pucIEStart, sme->ie_len,
(uint8_t **)&prDesiredIE,
&prConnSettings->fgOkcEnabled);
if (prConnSettings->fgOkcEnabled) {
uint16_t u2PmkIdCnt = 0;
if (prDesiredIE)
u2PmkIdCnt = *(uint16_t *)prDesiredIE;
DBGLOG(REQ, TRACE, "u2PmkIdCnt %d\n", u2PmkIdCnt);
if (u2PmkIdCnt != 0 && sme->bssid
&& !EQUAL_MAC_ADDR("\x0\x0\x0\x0\x0\x0",
sme->bssid) && IS_UCAST_MAC_ADDR(sme->bssid)) {
struct PARAM_PMKID rPmkid;
rPmkid.u4Length = (uint32_t)(sizeof(rPmkid)
| (1 << 31));
rPmkid.u4BSSIDInfoCount = 1;
kalMemCopy(rPmkid.arBSSIDInfo[0].arBSSID,
sme->bssid, MAC_ADDR_LEN);
kalMemCopy(rPmkid.arBSSIDInfo[0].arPMKID,
prDesiredIE + 2, IW_PMKID_LEN);
rStatus = kalIoctl(prGlueInfo, wlanoidSetPmkid,
(void *)&rPmkid, rPmkid.u4Length,
FALSE, FALSE, FALSE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
DBGLOG(REQ, WARN,
"failed to add OKC PMKID\n");
}
}
}
/* clear WSC Assoc IE buffer in case WPS IE is not detected */
if (fgCarryWPSIE == FALSE) {
kalMemZero(&prGlueInfo->aucWSCAssocInfoIE, 200);
prGlueInfo->u2WSCAssocInfoIELen = 0;
}
/* Fill WPA info - mfp setting */
/* Must put after paring RSNE from upper layer
* for prGlueInfo->rWpaInfo.ucRSNMfpCap assignment
*/
#if CFG_SUPPORT_802_11W
switch (sme->mfp) {
case NL80211_MFP_NO:
prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED;
/* Change Mfp parameter from DISABLED to OPTIONAL
* if upper layer set MFPC = 1 in RSNE
* since upper layer can't bring MFP OPTIONAL information
* to driver by sme->mfp
*/
if (prGlueInfo->rWpaInfo.ucRSNMfpCap == RSN_AUTH_MFP_OPTIONAL)
prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_OPTIONAL;
else if (prGlueInfo->rWpaInfo.ucRSNMfpCap ==
RSN_AUTH_MFP_REQUIRED)
DBGLOG(REQ, WARN,
"mfp parameter(DISABLED) conflict with mfp cap(REQUIRED)\n");
break;
case NL80211_MFP_REQUIRED:
prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_REQUIRED;
break;
default:
prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED;
break;
}
/* DBGLOG(REQ, INFO, ("MFP=%d\n", prGlueInfo->rWpaInfo.u4Mfp)); */
#endif
rStatus = kalIoctl(prGlueInfo, wlanoidSetAuthMode, &eAuthMode,
sizeof(eAuthMode), FALSE, FALSE, FALSE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
DBGLOG(REQ, WARN, "set auth mode error:%x\n", rStatus);
/* Enable the specific AKM suite only. */
for (i = 0; i < MAX_NUM_SUPPORTED_AKM_SUITES; i++) {
prEntry = &prGlueInfo->prAdapter->rMib
.dot11RSNAConfigAuthenticationSuitesTable[i];
if (prEntry->dot11RSNAConfigAuthenticationSuite ==
u4AkmSuite) {
prEntry->dot11RSNAConfigAuthenticationSuiteEnabled =
TRUE;
} else {
prEntry->dot11RSNAConfigAuthenticationSuiteEnabled =
FALSE;
}
}
cipher = prGlueInfo->rWpaInfo.u4CipherGroup |
prGlueInfo->rWpaInfo.u4CipherPairwise;
if (1 /* prGlueInfo->rWpaInfo.fgPrivacyInvoke */) {
#if CFG_SUPPORT_SUITB
if (cipher & IW_AUTH_CIPHER_GCMP256) {
eEncStatus = ENUM_ENCRYPTION4_ENABLED;
} else
#endif
if (cipher & IW_AUTH_CIPHER_CCMP) {
eEncStatus = ENUM_ENCRYPTION3_ENABLED;
} else if (cipher & IW_AUTH_CIPHER_TKIP) {
eEncStatus = ENUM_ENCRYPTION2_ENABLED;
} else if (cipher & (IW_AUTH_CIPHER_WEP104 |
IW_AUTH_CIPHER_WEP40)) {
eEncStatus = ENUM_ENCRYPTION1_ENABLED;
} else if (cipher & IW_AUTH_CIPHER_NONE) {
if (prGlueInfo->rWpaInfo.fgPrivacyInvoke)
eEncStatus = ENUM_ENCRYPTION1_ENABLED;
else
eEncStatus = ENUM_ENCRYPTION_DISABLED;
} else {
eEncStatus = ENUM_ENCRYPTION_DISABLED;
}
} else {
eEncStatus = ENUM_ENCRYPTION_DISABLED;
}
rStatus = kalIoctl(prGlueInfo, wlanoidSetEncryptionStatus, &eEncStatus,
sizeof(eEncStatus), FALSE, FALSE, FALSE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
DBGLOG(REQ, WARN, "set encryption mode error:%x\n",
rStatus);
if (sme->key_len != 0
&& prGlueInfo->rWpaInfo.u4WpaVersion ==
IW_AUTH_WPA_VERSION_DISABLED) {
/* NL80211 only set the Tx wep key while connect, the max 4 wep
* key set prior via add key cmd
*/
struct PARAM_WEP *prWepKey;
prWepKey = (struct PARAM_WEP *)kalMemAlloc(
sizeof(struct PARAM_WEP), VIR_MEM_TYPE);
if (prWepKey == NULL) {
DBGLOG(REQ, ERROR, "alloc buffer fail\n");
return -ENOMEM;
}
kalMemZero(prWepKey, sizeof(struct PARAM_WEP));
prWepKey->u4Length = OFFSET_OF(struct PARAM_WEP,
aucKeyMaterial) + sme->key_len;
prWepKey->u4KeyLength = (uint32_t) sme->key_len;
prWepKey->u4KeyIndex = (uint32_t) sme->key_idx;
prWepKey->u4KeyIndex |= IS_TRANSMIT_KEY;
if (prWepKey->u4KeyLength > MAX_KEY_LEN) {
DBGLOG(REQ, WARN, "Too long key length (%u)\n",
prWepKey->u4KeyLength);
if (prWepKey)
kalMemFree(prWepKey, VIR_MEM_TYPE,
sizeof(struct PARAM_WEP));
return -EINVAL;
}
kalMemCopy(prWepKey->aucKeyMaterial, sme->key,
prWepKey->u4KeyLength);
rStatus = kalIoctl(prGlueInfo, wlanoidSetAddWep, prWepKey,
prWepKey->u4Length,
FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, INFO, "wlanoidSetAddWep fail 0x%x\n",
rStatus);
if (prWepKey)
kalMemFree(prWepKey, VIR_MEM_TYPE,
sizeof(struct PARAM_WEP));
return -EFAULT;
}
if (prWepKey)
kalMemFree(prWepKey, VIR_MEM_TYPE,
sizeof(struct PARAM_WEP));
}
/* Avoid dangling pointer, set defatul all zero */
kalMemZero(&rNewSsid, sizeof(rNewSsid));
rNewSsid.u4CenterFreq = sme->channel ?
sme->channel->center_freq : 0;
rNewSsid.pucBssid = (uint8_t *)sme->bssid;
#if KERNEL_VERSION(3, 15, 0) <= CFG80211_VERSION_CODE
rNewSsid.pucBssidHint = (uint8_t *)sme->bssid_hint;
#endif
rNewSsid.pucSsid = (uint8_t *)sme->ssid;
rNewSsid.u4SsidLen = sme->ssid_len;
rStatus = kalIoctl(prGlueInfo, wlanoidSetConnect,
(void *)&rNewSsid, sizeof(struct PARAM_CONNECT),
FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(REQ, WARN, "set SSID:%x\n", rStatus);
return -EINVAL;
}
#if 0
if (sme->bssid != NULL
&& 1 /* prGlueInfo->fgIsBSSIDSet */) {
/* connect by BSSID */
if (sme->ssid_len > 0) {
struct CONNECTION_SETTINGS *prConnSettings = NULL;
prConnSettings = &
(prGlueInfo->prAdapter->rWifiVar.rConnSettings);
/* prGlueInfo->fgIsSSIDandBSSIDSet = TRUE; */
COPY_SSID(prConnSettings->aucSSID,
prConnSettings->ucSSIDLen,
sme->ssid, sme->ssid_len);
}
rStatus = kalIoctl(prGlueInfo, wlanoidSetBssid,
(void *) sme->bssid, MAC_ADDR_LEN,
FALSE, FALSE, TRUE, FALSE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(REQ, WARN, "set BSSID:%x\n", rStatus);
return -EINVAL;
}
} else if (sme->ssid_len > 0) {
/* connect by SSID */
COPY_SSID(rNewSsid.aucSsid, rNewSsid.u4SsidLen, sme->ssid,
sme->ssid_len);
rStatus = kalIoctl(prGlueInfo, wlanoidSetSsid,
(void *)&rNewSsid, sizeof(struct PARAM_SSID),
FALSE, FALSE, TRUE, FALSE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(REQ, WARN, "set SSID:%x\n", rStatus);
return -EINVAL;
}
}
#endif
return 0;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for requesting to disconnect from
* currently connected ESS
*
* @param
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
int mtk_cfg80211_disconnect(struct wiphy *wiphy,
struct net_device *ndev, u16 reason_code)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint32_t rStatus;
uint32_t u4BufLen;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
DBGLOG(REQ, STATE, "mtk_cfg80211_disconnect\n");
rStatus = kalIoctl(prGlueInfo, wlanoidSetDisassociate, NULL,
0, FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(REQ, WARN, "disassociate error:%x\n", rStatus);
return -EFAULT;
}
return 0;
}
#if CFG_SUPPORT_CFG80211_AUTH
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for requesting to deauth from
* currently connected ESS
*
* @param
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
int mtk_cfg80211_deauth(struct wiphy *wiphy, struct net_device *ndev,
struct cfg80211_deauth_request *req)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint32_t rStatus;
uint32_t u4BufLen;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
DBGLOG(REQ, INFO, "mtk_cfg80211_deauth\n");
rStatus = kalIoctl(prGlueInfo, wlanoidSetDisassociate, NULL, 0,
FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(REQ, WARN, "disassociate error:%x\n", rStatus);
return -EFAULT;
}
return 0;
}
#endif
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for requesting to join an IBSS group
*
* @param
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
int mtk_cfg80211_join_ibss(struct wiphy *wiphy,
struct net_device *ndev,
struct cfg80211_ibss_params *params)
{
struct PARAM_SSID rNewSsid;
struct GLUE_INFO *prGlueInfo = NULL;
uint32_t u4ChnlFreq; /* Store channel or frequency information */
uint32_t u4BufLen = 0, u4SsidLen = 0;
uint32_t rStatus;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
DBGLOG(REQ, INFO, "mtk_cfg80211_join_ibss\n");
/* set channel */
if (params->channel_fixed) {
u4ChnlFreq = params->chandef.center_freq1;
rStatus = kalIoctl(prGlueInfo, wlanoidSetFrequency,
&u4ChnlFreq, sizeof(u4ChnlFreq),
FALSE, FALSE, FALSE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
return -EFAULT;
}
/* set SSID */
if (params->ssid_len > PARAM_MAX_LEN_SSID)
u4SsidLen = PARAM_MAX_LEN_SSID;
else
u4SsidLen = params->ssid_len;
kalMemCopy(rNewSsid.aucSsid, params->ssid,
u4SsidLen);
rStatus = kalIoctl(prGlueInfo, wlanoidSetSsid, (void *)&rNewSsid,
sizeof(struct PARAM_SSID),
FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(REQ, WARN, "set SSID:%x\n", rStatus);
return -EFAULT;
}
return 0;
return -EINVAL;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for requesting to leave from IBSS group
*
* @param
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
int mtk_cfg80211_leave_ibss(struct wiphy *wiphy,
struct net_device *ndev)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint32_t rStatus;
uint32_t u4BufLen;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
DBGLOG(REQ, INFO, "%s\n", __func__);
rStatus = kalIoctl(prGlueInfo, wlanoidSetDisassociate, NULL,
0, FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(REQ, WARN, "disassociate error:%x\n", rStatus);
return -EFAULT;
}
return 0;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for requesting to configure
* WLAN power managemenet
*
* @param
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
int mtk_cfg80211_set_power_mgmt(struct wiphy *wiphy,
struct net_device *ndev, bool enabled, int timeout)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint32_t rStatus;
uint32_t u4BufLen;
struct PARAM_POWER_MODE_ rPowerMode;
struct WIFI_VAR *prWifiVar;
enum PARAM_POWER_MODE eEnforcePowerMode;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!prGlueInfo)
return -EFAULT;
if (!prGlueInfo->prAdapter->prAisBssInfo)
return -EFAULT;
prWifiVar = &prGlueInfo->prAdapter->rWifiVar;
DBGLOG(REQ, INFO, "%s: enabled=%d, timeout=%d\n", __func__,
enabled, timeout);
if (enabled &&
((prGlueInfo->prAdapter->prAisBssInfo->eBand == BAND_5G) ||
(!prWifiVar->ucEnforceCAM2G))) {
if (timeout == -1)
rPowerMode.ePowerMode = Param_PowerModeFast_PSP;
else
rPowerMode.ePowerMode = Param_PowerModeMAX_PSP;
} else {
rPowerMode.ePowerMode = Param_PowerModeCAM;
}
if (prWifiVar->fgActiveModeCam)
rPowerMode.ePowerMode = Param_PowerModeCAM;
rPowerMode.ucBssIdx =
prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex;
if ((prGlueInfo->prAdapter->prAisBssInfo->ePowerModeFromUser
!= rPowerMode.ePowerMode) &&
(prGlueInfo->prAdapter->rWifiVar.ucEnforcePSMode
< Param_PowerModeMax)) {
/*
* Store user's PS mode for restoring
* when we do not enforce power mode anymore
*/
DBGLOG(INIT, STATE, "Store user's PS mode:%d\n",
rPowerMode.ePowerMode);
prGlueInfo->prAdapter->prAisBssInfo->ePowerModeFromUser =
rPowerMode.ePowerMode;
}
eEnforcePowerMode =
(enum PARAM_POWER_MODE)
prGlueInfo->prAdapter->rWifiVar.ucEnforcePSMode;
if (eEnforcePowerMode < Param_PowerModeMax)
rPowerMode.ePowerMode = eEnforcePowerMode;
rStatus = kalIoctl(prGlueInfo, wlanoidSet802dot11PowerSaveProfile,
&rPowerMode, sizeof(struct PARAM_POWER_MODE_),
FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(REQ, WARN, "set_power_mgmt error:%x\n", rStatus);
return -EFAULT;
}
return 0;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for requesting to cache
* a PMKID for a BSSID
*
* @param
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
int mtk_cfg80211_set_pmksa(struct wiphy *wiphy,
struct net_device *ndev, struct cfg80211_pmksa *pmksa)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint32_t rStatus;
uint32_t u4BufLen;
struct PARAM_PMKID *prPmkid;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
prPmkid = (struct PARAM_PMKID *) kalMemAlloc(8 + sizeof(
struct PARAM_BSSID_INFO), VIR_MEM_TYPE);
DBGLOG(REQ, INFO, "mtk_cfg80211_set_pmksa\n");
if (!prPmkid) {
DBGLOG(INIT, INFO,
"Can not alloc memory for IW_PMKSA_ADD\n");
return -ENOMEM;
}
prPmkid->u4Length = 8 + sizeof(struct PARAM_BSSID_INFO);
prPmkid->u4BSSIDInfoCount = 1;
kalMemCopy(prPmkid->arBSSIDInfo->arBSSID, pmksa->bssid, 6);
kalMemCopy(prPmkid->arBSSIDInfo->arPMKID, pmksa->pmkid,
IW_PMKID_LEN);
rStatus = kalIoctl(prGlueInfo, wlanoidSetPmkid, prPmkid,
sizeof(struct PARAM_PMKID),
FALSE, FALSE, FALSE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
DBGLOG(INIT, INFO, "add pmkid error:%x\n", rStatus);
kalMemFree(prPmkid, VIR_MEM_TYPE,
8 + sizeof(struct PARAM_BSSID_INFO));
return 0;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for requesting to remove
* a cached PMKID for a BSSID
*
* @param
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
int mtk_cfg80211_del_pmksa(struct wiphy *wiphy,
struct net_device *ndev, struct cfg80211_pmksa *pmksa)
{
DBGLOG(REQ, INFO, "not support now\n");
return 0;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for requesting to flush
* all cached PMKID
*
* @param
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
int mtk_cfg80211_flush_pmksa(struct wiphy *wiphy,
struct net_device *ndev)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint32_t rStatus;
uint32_t u4BufLen;
struct PARAM_PMKID *prPmkid;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
prPmkid = (struct PARAM_PMKID *) kalMemAlloc(8,
VIR_MEM_TYPE);
DBGLOG(P2P, INFO, "mtk_cfg80211_flush_pmksa\n");
if (!prPmkid) {
DBGLOG(INIT, INFO,
"Can not alloc memory for IW_PMKSA_FLUSH\n");
return -ENOMEM;
}
prPmkid->u4Length = 8;
prPmkid->u4BSSIDInfoCount = 0;
rStatus = kalIoctl(prGlueInfo, wlanoidSetPmkid, prPmkid,
sizeof(struct PARAM_PMKID), FALSE, FALSE, FALSE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
DBGLOG(INIT, INFO, "flush pmkid error:%x\n", rStatus);
kalMemFree(prPmkid, VIR_MEM_TYPE, 8);
return 0;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for setting the rekey data
*
* @param
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
int mtk_cfg80211_set_rekey_data(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_gtk_rekey_data *data)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint32_t u4BufLen;
struct PARAM_GTK_REKEY_DATA *prGtkData;
uint32_t rStatus = WLAN_STATUS_SUCCESS;
int32_t i4Rslt = -EINVAL;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
/* if offload dis, store key data, and enable rekey offload when wow */
if (!prGlueInfo->prAdapter->rWifiVar.ucEapolOffload) {
kalMemZero(prGlueInfo->rWpaInfo.aucKek, NL80211_KEK_LEN);
kalMemZero(prGlueInfo->rWpaInfo.aucKck, NL80211_KCK_LEN);
kalMemZero(prGlueInfo->rWpaInfo.aucReplayCtr,
NL80211_REPLAY_CTR_LEN);
kalMemCopy(prGlueInfo->rWpaInfo.aucKek, data->kek,
NL80211_KEK_LEN);
kalMemCopy(prGlueInfo->rWpaInfo.aucKck, data->kck,
NL80211_KCK_LEN);
kalMemCopy(prGlueInfo->rWpaInfo.aucReplayCtr, data->replay_ctr,
NL80211_REPLAY_CTR_LEN);
return 0;
}
prGtkData =
(struct PARAM_GTK_REKEY_DATA *) kalMemAlloc(sizeof(
struct PARAM_GTK_REKEY_DATA), VIR_MEM_TYPE);
if (!prGtkData)
return WLAN_STATUS_SUCCESS;
DBGLOG(RSN, INFO, "cfg80211_set_rekey_data size(%d)\n",
(uint32_t) sizeof(struct cfg80211_gtk_rekey_data));
DBGLOG(RSN, TRACE, "kek\n");
DBGLOG_MEM8(RSN, TRACE, (uint8_t *)data->kek,
NL80211_KEK_LEN);
DBGLOG(RSN, TRACE, "kck\n");
DBGLOG_MEM8(RSN, TRACE, (uint8_t *)data->kck,
NL80211_KCK_LEN);
DBGLOG(RSN, TRACE, "replay count\n");
DBGLOG_MEM8(RSN, TRACE, (uint8_t *)data->replay_ctr,
NL80211_REPLAY_CTR_LEN);
#if 0
kalMemCopy(prGtkData, data, sizeof(*data));
#else
kalMemCopy(prGtkData->aucKek, data->kek, NL80211_KEK_LEN);
kalMemCopy(prGtkData->aucKck, data->kck, NL80211_KCK_LEN);
kalMemCopy(prGtkData->aucReplayCtr, data->replay_ctr,
NL80211_REPLAY_CTR_LEN);
#endif
prGtkData->ucBssIndex =
prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex;
prGtkData->u4Proto = NL80211_WPA_VERSION_2;
if (prGlueInfo->rWpaInfo.u4WpaVersion ==
IW_AUTH_WPA_VERSION_WPA)
prGtkData->u4Proto = NL80211_WPA_VERSION_1;
if (prGlueInfo->rWpaInfo.u4CipherPairwise ==
IW_AUTH_CIPHER_TKIP)
prGtkData->u4PairwiseCipher = BIT(3);
else if (prGlueInfo->rWpaInfo.u4CipherPairwise ==
IW_AUTH_CIPHER_CCMP)
prGtkData->u4PairwiseCipher = BIT(4);
else {
kalMemFree(prGtkData, VIR_MEM_TYPE,
sizeof(struct PARAM_GTK_REKEY_DATA));
return WLAN_STATUS_SUCCESS;
}
if (prGlueInfo->rWpaInfo.u4CipherGroup ==
IW_AUTH_CIPHER_TKIP)
prGtkData->u4GroupCipher = BIT(3);
else if (prGlueInfo->rWpaInfo.u4CipherGroup ==
IW_AUTH_CIPHER_CCMP)
prGtkData->u4GroupCipher = BIT(4);
else {
kalMemFree(prGtkData, VIR_MEM_TYPE,
sizeof(struct PARAM_GTK_REKEY_DATA));
return WLAN_STATUS_SUCCESS;
}
prGtkData->u4KeyMgmt = prGlueInfo->rWpaInfo.u4KeyMgmt;
prGtkData->u4MgmtGroupCipher = 0;
rStatus = kalIoctl(prGlueInfo, wlanoidSetGtkRekeyData, prGtkData,
sizeof(struct PARAM_GTK_REKEY_DATA),
FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
DBGLOG(INIT, INFO, "set GTK rekey data error:%x\n",
rStatus);
else
i4Rslt = 0;
kalMemFree(prGtkData, VIR_MEM_TYPE,
sizeof(struct PARAM_GTK_REKEY_DATA));
return i4Rslt;
}
void mtk_cfg80211_mgmt_frame_register(IN struct wiphy *wiphy,
IN struct wireless_dev *wdev,
IN u16 frame_type,
IN bool reg)
{
#if 0
struct MSG_P2P_MGMT_FRAME_REGISTER *prMgmtFrameRegister =
(struct MSG_P2P_MGMT_FRAME_REGISTER *) NULL;
#endif
struct GLUE_INFO *prGlueInfo = (struct GLUE_INFO *) NULL;
do {
DBGLOG(INIT, TRACE, "mtk_cfg80211_mgmt_frame_register\n");
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
switch (frame_type) {
case MAC_FRAME_PROBE_REQ:
if (reg) {
prGlueInfo->u4OsMgmtFrameFilter |=
PARAM_PACKET_FILTER_PROBE_REQ;
DBGLOG(INIT, TRACE,
"Open packet filer probe request\n");
} else {
prGlueInfo->u4OsMgmtFrameFilter &=
~PARAM_PACKET_FILTER_PROBE_REQ;
DBGLOG(INIT, TRACE,
"Close packet filer probe request\n");
}
break;
case MAC_FRAME_ACTION:
if (reg) {
prGlueInfo->u4OsMgmtFrameFilter |=
PARAM_PACKET_FILTER_ACTION_FRAME;
DBGLOG(INIT, TRACE,
"Open packet filer action frame.\n");
} else {
prGlueInfo->u4OsMgmtFrameFilter &=
~PARAM_PACKET_FILTER_ACTION_FRAME;
DBGLOG(INIT, TRACE,
"Close packet filer action frame.\n");
}
break;
default:
DBGLOG(INIT, TRACE,
"Ask frog to add code for mgmt:%x\n",
frame_type);
break;
}
if (prGlueInfo->prAdapter != NULL) {
set_bit(GLUE_FLAG_FRAME_FILTER_AIS_BIT,
&prGlueInfo->ulFlag);
/* wake up main thread */
wake_up_interruptible(&prGlueInfo->waitq);
if (in_interrupt())
DBGLOG(INIT, TRACE,
"It is in interrupt level\n");
}
#if 0
prMgmtFrameRegister =
(struct MSG_P2P_MGMT_FRAME_REGISTER *) cnmMemAlloc(
prGlueInfo->prAdapter, RAM_TYPE_MSG,
sizeof(struct MSG_P2P_MGMT_FRAME_REGISTER));
if (prMgmtFrameRegister == NULL) {
ASSERT(FALSE);
break;
}
prMgmtFrameRegister->rMsgHdr.eMsgId =
MID_MNY_P2P_MGMT_FRAME_REGISTER;
prMgmtFrameRegister->u2FrameType = frame_type;
prMgmtFrameRegister->fgIsRegister = reg;
mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0,
(struct MSG_HDR *) prMgmtFrameRegister,
MSG_SEND_METHOD_BUF);
#endif
} while (FALSE);
} /* mtk_cfg80211_mgmt_frame_register */
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for requesting to stay on a
* specified channel
*
* @param
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
int mtk_cfg80211_remain_on_channel(struct wiphy *wiphy,
struct wireless_dev *wdev,
struct ieee80211_channel *chan, unsigned int duration,
u64 *cookie)
{
struct GLUE_INFO *prGlueInfo = NULL;
int32_t i4Rslt = -EINVAL;
struct MSG_REMAIN_ON_CHANNEL *prMsgChnlReq =
(struct MSG_REMAIN_ON_CHANNEL *) NULL;
do {
if ((wiphy == NULL)
|| (wdev == NULL)
|| (chan == NULL)
|| (cookie == NULL)) {
break;
}
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
#if 1
DBGLOG(INIT, INFO, "--> %s()\n", __func__);
#endif
*cookie = prGlueInfo->u8Cookie++;
prMsgChnlReq = cnmMemAlloc(prGlueInfo->prAdapter,
RAM_TYPE_MSG, sizeof(struct MSG_REMAIN_ON_CHANNEL));
if (prMsgChnlReq == NULL) {
ASSERT(FALSE);
i4Rslt = -ENOMEM;
break;
}
prMsgChnlReq->rMsgHdr.eMsgId =
MID_MNY_AIS_REMAIN_ON_CHANNEL;
prMsgChnlReq->u8Cookie = *cookie;
prMsgChnlReq->u4DurationMs = duration;
prMsgChnlReq->ucChannelNum = nicFreq2ChannelNum(
chan->center_freq * 1000);
switch (chan->band) {
case KAL_BAND_2GHZ:
prMsgChnlReq->eBand = BAND_2G4;
break;
case KAL_BAND_5GHZ:
prMsgChnlReq->eBand = BAND_5G;
break;
default:
prMsgChnlReq->eBand = BAND_2G4;
break;
}
prMsgChnlReq->eSco = CHNL_EXT_SCN;
mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0,
(struct MSG_HDR *) prMsgChnlReq, MSG_SEND_METHOD_BUF);
i4Rslt = 0;
} while (FALSE);
return i4Rslt;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for requesting to cancel staying
* on a specified channel
*
* @param
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
int mtk_cfg80211_cancel_remain_on_channel(
struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie)
{
struct GLUE_INFO *prGlueInfo = NULL;
int32_t i4Rslt = -EINVAL;
struct MSG_CANCEL_REMAIN_ON_CHANNEL *prMsgChnlAbort =
(struct MSG_CANCEL_REMAIN_ON_CHANNEL *) NULL;
do {
if ((wiphy == NULL)
|| (wdev == NULL)
) {
break;
}
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
DBGLOG(REQ, INFO,
"mtk_cfg80211_cancel_remain_on_channel\n");
prMsgChnlAbort =
cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG,
sizeof(struct MSG_CANCEL_REMAIN_ON_CHANNEL));
if (prMsgChnlAbort == NULL) {
ASSERT(FALSE);
i4Rslt = -ENOMEM;
break;
}
prMsgChnlAbort->rMsgHdr.eMsgId =
MID_MNY_AIS_CANCEL_REMAIN_ON_CHANNEL;
prMsgChnlAbort->u8Cookie = cookie;
mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0,
(struct MSG_HDR *) prMsgChnlAbort, MSG_SEND_METHOD_BUF);
i4Rslt = 0;
} while (FALSE);
return i4Rslt;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for requesting to send a management frame
*
* @param
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
#if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
int mtk_cfg80211_mgmt_tx(struct wiphy *wiphy,
struct wireless_dev *wdev,
struct cfg80211_mgmt_tx_params *params,
u64 *cookie)
{
struct GLUE_INFO *prGlueInfo = NULL;
int32_t i4Rslt = -EINVAL;
struct MSG_MGMT_TX_REQUEST *prMsgTxReq = (struct
MSG_MGMT_TX_REQUEST *) NULL;
struct MSDU_INFO *prMgmtFrame = (struct MSDU_INFO *) NULL;
uint8_t *pucFrameBuf = (uint8_t *) NULL;
do {
if ((wiphy == NULL) || (wdev == NULL) || (params == 0)
|| (cookie == NULL))
break;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
DBGLOG(REQ, INFO, "mtk_cfg80211_mgmt_tx\n");
*cookie = prGlueInfo->u8Cookie++;
/* Channel & Channel Type & Wait time are ignored. */
prMsgTxReq = cnmMemAlloc(prGlueInfo->prAdapter,
RAM_TYPE_MSG,
sizeof(struct MSG_MGMT_TX_REQUEST));
if (prMsgTxReq == NULL) {
ASSERT(FALSE);
i4Rslt = -ENOMEM;
break;
}
prMsgTxReq->fgNoneCckRate = FALSE;
prMsgTxReq->fgIsWaitRsp = TRUE;
prMgmtFrame = cnmMgtPktAlloc(prGlueInfo->prAdapter,
(uint32_t) (params->len +
MAC_TX_RESERVED_FIELD));
prMsgTxReq->prMgmtMsduInfo = prMgmtFrame;
if (prMsgTxReq->prMgmtMsduInfo == NULL) {
ASSERT(FALSE);
i4Rslt = -ENOMEM;
break;
}
prMsgTxReq->u8Cookie = *cookie;
prMsgTxReq->rMsgHdr.eMsgId = MID_MNY_AIS_MGMT_TX;
pucFrameBuf = (uint8_t *) ((unsigned long)
prMgmtFrame->prPacket +
MAC_TX_RESERVED_FIELD);
kalMemCopy(pucFrameBuf, params->buf, params->len);
prMgmtFrame->u2FrameLength = params->len;
mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0,
(struct MSG_HDR *) prMsgTxReq, MSG_SEND_METHOD_BUF);
i4Rslt = 0;
} while (FALSE);
if ((i4Rslt != 0) && (prMsgTxReq != NULL)) {
if (prMsgTxReq->prMgmtMsduInfo != NULL)
cnmMgtPktFree(prGlueInfo->prAdapter,
prMsgTxReq->prMgmtMsduInfo);
cnmMemFree(prGlueInfo->prAdapter, prMsgTxReq);
}
return i4Rslt;
}
#else
int mtk_cfg80211_mgmt_tx(struct wiphy *wiphy,
struct wireless_dev *wdev,
struct ieee80211_channel *channel, bool offscan,
unsigned int wait,
const u8 *buf, size_t len, bool no_cck,
bool dont_wait_for_ack, u64 *cookie)
{
struct GLUE_INFO *prGlueInfo = NULL;
int32_t i4Rslt = -EINVAL;
struct MSG_MGMT_TX_REQUEST *prMsgTxReq = (struct
MSG_MGMT_TX_REQUEST *) NULL;
struct MSDU_INFO *prMgmtFrame = (struct MSDU_INFO *) NULL;
uint8_t *pucFrameBuf = (uint8_t *) NULL;
do {
if ((wiphy == NULL)
|| (buf == NULL)
|| (len == 0)
|| (wdev == NULL)
|| (cookie == NULL)) {
break;
}
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
DBGLOG(REQ, INFO, "mtk_cfg80211_mgmt_tx\n");
*cookie = prGlueInfo->u8Cookie++;
/* Channel & Channel Type & Wait time are ignored. */
prMsgTxReq = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG,
sizeof(struct MSG_MGMT_TX_REQUEST));
if (prMsgTxReq == NULL) {
ASSERT(FALSE);
i4Rslt = -ENOMEM;
break;
}
prMsgTxReq->fgNoneCckRate = FALSE;
prMsgTxReq->fgIsWaitRsp = TRUE;
prMgmtFrame = cnmMgtPktAlloc(prGlueInfo->prAdapter,
(uint32_t) (len + MAC_TX_RESERVED_FIELD));
prMsgTxReq->prMgmtMsduInfo = prMgmtFrame;
if (prMsgTxReq->prMgmtMsduInfo == NULL) {
ASSERT(FALSE);
i4Rslt = -ENOMEM;
break;
}
prMsgTxReq->u8Cookie = *cookie;
prMsgTxReq->rMsgHdr.eMsgId = MID_MNY_AIS_MGMT_TX;
pucFrameBuf = (uint8_t *) ((unsigned long)
prMgmtFrame->prPacket +
MAC_TX_RESERVED_FIELD);
kalMemCopy(pucFrameBuf, buf, len);
prMgmtFrame->u2FrameLength = len;
mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0,
(struct MSG_HDR *) prMsgTxReq, MSG_SEND_METHOD_BUF);
i4Rslt = 0;
} while (FALSE);
if ((i4Rslt != 0) && (prMsgTxReq != NULL)) {
if (prMsgTxReq->prMgmtMsduInfo != NULL)
cnmMgtPktFree(prGlueInfo->prAdapter,
prMsgTxReq->prMgmtMsduInfo);
cnmMemFree(prGlueInfo->prAdapter, prMsgTxReq);
}
return i4Rslt;
}
#endif
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for requesting to cancel the wait time
* from transmitting a management frame on another channel
*
* @param
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
int mtk_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
struct wireless_dev *wdev, u64 cookie)
{
struct GLUE_INFO *prGlueInfo = NULL;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
#if 1
DBGLOG(INIT, INFO, "--> %s()\n", __func__);
#endif
/* not implemented */
return -EINVAL;
}
#ifdef CONFIG_NL80211_TESTMODE
#if CFG_SUPPORT_PASSPOINT
int mtk_cfg80211_testmode_hs20_cmd(IN struct wiphy *wiphy,
IN void *data, IN int len)
{
struct GLUE_INFO *prGlueInfo = NULL;
struct wpa_driver_hs20_data_s *prParams = NULL;
uint32_t rstatus = WLAN_STATUS_SUCCESS;
int fgIsValid = 0;
uint32_t u4SetInfoLen = 0;
ASSERT(wiphy);
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
DBGLOG(REQ, INFO, "--> %s()\n", __func__);
if (data && len)
prParams = (struct wpa_driver_hs20_data_s *)data;
if (prParams) {
int i;
DBGLOG(INIT, INFO, "[%s] Cmd Type (%d)\n",
__func__, prParams->CmdType);
switch (prParams->CmdType) {
case HS20_CMD_ID_SET_BSSID_POOL:
DBGLOG(REQ, TRACE,
"fgBssidPoolIsEnable=%d, ucNumBssidPool=%d\n",
prParams->hs20_set_bssid_pool.fgBssidPoolIsEnable,
prParams->hs20_set_bssid_pool.ucNumBssidPool);
for (i = 0;
i < prParams->hs20_set_bssid_pool.ucNumBssidPool;
i++) {
DBGLOG(REQ, TRACE,
"[%d][ " MACSTR " ]\n",
i,
MAC2STR(prParams->
hs20_set_bssid_pool.
arBssidPool[i]));
}
rstatus = kalIoctl(prGlueInfo,
(PFN_OID_HANDLER_FUNC) wlanoidSetHS20BssidPool,
&prParams->hs20_set_bssid_pool,
sizeof(struct param_hs20_set_bssid_pool),
FALSE, FALSE, TRUE, &u4SetInfoLen);
break;
default:
DBGLOG(REQ, TRACE, "[%s] Unknown Cmd Type (%d)\n",
__func__, prParams->CmdType);
rstatus = WLAN_STATUS_FAILURE;
}
}
if (rstatus != WLAN_STATUS_SUCCESS)
fgIsValid = -EFAULT;
return fgIsValid;
}
#endif /* CFG_SUPPORT_PASSPOINT */
#if CFG_SUPPORT_WAPI
int mtk_cfg80211_testmode_set_key_ext(IN struct wiphy
*wiphy, IN void *data, IN int len)
{
struct GLUE_INFO *prGlueInfo = NULL;
struct NL80211_DRIVER_SET_KEY_EXTS *prParams =
(struct NL80211_DRIVER_SET_KEY_EXTS *) NULL;
struct iw_encode_exts *prIWEncExt = (struct iw_encode_exts
*)NULL;
uint32_t rstatus = WLAN_STATUS_SUCCESS;
int fgIsValid = 0;
uint32_t u4BufLen = 0;
const uint8_t aucBCAddr[] = BC_MAC_ADDR;
struct PARAM_KEY *prWpiKey = NULL;
uint8_t *keyStructBuf = NULL;
ASSERT(wiphy);
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
#if 1
DBGLOG(INIT, INFO, "--> %s()\n", __func__);
#endif
if (len < sizeof(struct NL80211_DRIVER_SET_KEY_EXTS)) {
DBGLOG(REQ, ERROR, "len [%d] is invalid!\n", len);
fgIsValid = -EINVAL;
goto freeBuf;
}
if (data == NULL || len == 0) {
DBGLOG(INIT, TRACE, "%s data or len is invalid\n", __func__);
fgIsValid = -EINVAL;
goto freeBuf;
}
keyStructBuf = kalMemAlloc(KEY_BUF_SIZE, VIR_MEM_TYPE);
if (keyStructBuf == NULL) {
DBGLOG(REQ, ERROR, "alloc key buffer fail\n");
fgIsValid = -EINVAL;
goto freeBuf;
}
memset(keyStructBuf, 0, KEY_BUF_SIZE);
prWpiKey = (struct PARAM_KEY *) keyStructBuf;
prParams = (struct NL80211_DRIVER_SET_KEY_EXTS *) data;
prIWEncExt = (struct iw_encode_exts *)&prParams->ext;
if (prIWEncExt->alg == IW_ENCODE_ALG_SMS4) {
/* KeyID */
prWpiKey->u4KeyIndex = prParams->key_index;
prWpiKey->u4KeyIndex--;
if (prWpiKey->u4KeyIndex > 1) {
fgIsValid = -EINVAL;
goto freeBuf;
}
if (prIWEncExt->key_len != 32) {
fgIsValid = -EINVAL;
goto freeBuf;
}
prWpiKey->u4KeyLength = prIWEncExt->key_len;
if (prIWEncExt->ext_flags & IW_ENCODE_EXT_SET_TX_KEY &&
!(prIWEncExt->ext_flags & IW_ENCODE_EXT_GROUP_KEY)) {
/* WAI seems set the STA group key with
* IW_ENCODE_EXT_SET_TX_KEY !!!!
* Ignore the group case
*/
prWpiKey->u4KeyIndex |= BIT(30);
prWpiKey->u4KeyIndex |= BIT(31);
/* BSSID */
memcpy(prWpiKey->arBSSID, prIWEncExt->addr, 6);
} else {
COPY_MAC_ADDR(prWpiKey->arBSSID, aucBCAddr);
}
/* PN */
/* memcpy(prWpiKey->rKeyRSC, prIWEncExt->tx_seq,
* IW_ENCODE_SEQ_MAX_SIZE * 2);
*/
memcpy(prWpiKey->aucKeyMaterial, prIWEncExt->key, 32);
prWpiKey->u4Length = sizeof(struct PARAM_KEY);
prWpiKey->ucBssIdx =
prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex;
prWpiKey->ucCipher = CIPHER_SUITE_WPI;
rstatus = kalIoctl(prGlueInfo, wlanoidSetAddKey, prWpiKey,
sizeof(struct PARAM_KEY),
FALSE, FALSE, TRUE, &u4BufLen);
if (rstatus != WLAN_STATUS_SUCCESS) {
fgIsValid = -EFAULT;
}
}
freeBuf:
if (keyStructBuf)
kalMemFree(keyStructBuf, VIR_MEM_TYPE, KEY_BUF_SIZE);
return fgIsValid;
}
#endif
int
mtk_cfg80211_testmode_get_sta_statistics(IN struct wiphy
*wiphy, IN void *data, IN int len,
IN struct GLUE_INFO *prGlueInfo)
{
uint32_t rStatus = WLAN_STATUS_SUCCESS;
uint32_t u4BufLen;
uint32_t u4LinkScore;
uint32_t u4TotalError;
uint32_t u4TxExceedThresholdCount;
uint32_t u4TxTotalCount;
struct NL80211_DRIVER_GET_STA_STATISTICS_PARAMS *prParams =
NULL;
struct PARAM_GET_STA_STATISTICS rQueryStaStatistics;
struct sk_buff *skb;
ASSERT(wiphy);
ASSERT(prGlueInfo);
if (len < sizeof(struct NL80211_DRIVER_GET_STA_STATISTICS_PARAMS)) {
DBGLOG(OID, WARN, "len [%d] is invalid!\n", len);
return -EINVAL;
}
if (data && len)
prParams = (struct NL80211_DRIVER_GET_STA_STATISTICS_PARAMS
*) data;
if (prParams == NULL) {
DBGLOG(QM, ERROR, "prParams is NULL, data=%p, len=%d\n",
data, len);
return -EINVAL;
}
skb = cfg80211_testmode_alloc_reply_skb(wiphy,
sizeof(struct PARAM_GET_STA_STATISTICS) + 1);
if (!skb) {
DBGLOG(QM, ERROR, "allocate skb failed:%x\n", rStatus);
return -ENOMEM;
}
kalMemZero(&rQueryStaStatistics,
sizeof(rQueryStaStatistics));
COPY_MAC_ADDR(rQueryStaStatistics.aucMacAddr,
prParams->aucMacAddr);
rQueryStaStatistics.ucReadClear = TRUE;
rStatus = kalIoctl(prGlueInfo,
wlanoidQueryStaStatistics,
&rQueryStaStatistics, sizeof(rQueryStaStatistics),
TRUE, FALSE, TRUE, &u4BufLen);
/* Calcute Link Score */
u4TxExceedThresholdCount =
rQueryStaStatistics.u4TxExceedThresholdCount;
u4TxTotalCount = rQueryStaStatistics.u4TxTotalCount;
u4TotalError = rQueryStaStatistics.u4TxFailCount +
rQueryStaStatistics.u4TxLifeTimeoutCount;
/* u4LinkScore 10~100 , ExceedThreshold ratio 0~90 only
* u4LinkScore 0~9 , Drop packet ratio 0~9 and all packets exceed
* threshold
*/
if (u4TxTotalCount) {
if (u4TxExceedThresholdCount <= u4TxTotalCount)
u4LinkScore = (90 - ((u4TxExceedThresholdCount * 90)
/ u4TxTotalCount));
else
u4LinkScore = 0;
} else {
u4LinkScore = 90;
}
u4LinkScore += 10;
if (u4LinkScore == 10) {
if (u4TotalError <= u4TxTotalCount)
u4LinkScore = (10 - ((u4TotalError * 10)
/ u4TxTotalCount));
else
u4LinkScore = 0;
}
if (u4LinkScore > 100)
u4LinkScore = 100;
{
u8 __tmp = 0;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_INVALID, sizeof(u8),
&__tmp) < 0))
goto nla_put_failure;
}
{
u8 __tmp = NL80211_DRIVER_TESTMODE_VERSION;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_VERSION, sizeof(u8),
&__tmp) < 0))
goto nla_put_failure;
}
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_MAC, MAC_ADDR_LEN,
prParams->aucMacAddr) < 0))
goto nla_put_failure;
{
u32 __tmp = u4LinkScore;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_LINK_SCORE, sizeof(u32),
&__tmp) < 0))
goto nla_put_failure;
}
{
u32 __tmp = rQueryStaStatistics.u4Flag;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_FLAG, sizeof(u32),
&__tmp) < 0))
goto nla_put_failure;
}
{
u32 __tmp = rQueryStaStatistics.u4EnqueueCounter;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_ENQUEUE, sizeof(u32),
&__tmp) < 0))
goto nla_put_failure;
}
{
u32 __tmp = rQueryStaStatistics.u4DequeueCounter;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_DEQUEUE, sizeof(u32),
&__tmp) < 0))
goto nla_put_failure;
}
{
u32 __tmp = rQueryStaStatistics.u4EnqueueStaCounter;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_STA_ENQUEUE, sizeof(u32),
&__tmp) < 0))
goto nla_put_failure;
}
{
u32 __tmp = rQueryStaStatistics.u4DequeueStaCounter;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_STA_DEQUEUE, sizeof(u32),
&__tmp) < 0))
goto nla_put_failure;
}
{
u32 __tmp = rQueryStaStatistics.IsrCnt;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_IRQ_ISR_CNT, sizeof(u32),
&__tmp) < 0))
goto nla_put_failure;
}
{
u32 __tmp = rQueryStaStatistics.IsrPassCnt;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_IRQ_ISR_PASS_CNT,
sizeof(u32), &__tmp) < 0))
goto nla_put_failure;
}
{
u32 __tmp = rQueryStaStatistics.TaskIsrCnt;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_IRQ_TASK_CNT, sizeof(u32),
&__tmp) < 0))
goto nla_put_failure;
}
{
u32 __tmp = rQueryStaStatistics.IsrAbnormalCnt;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_IRQ_AB_CNT, sizeof(u32),
&__tmp) < 0))
goto nla_put_failure;
}
{
u32 __tmp = rQueryStaStatistics.IsrSoftWareCnt;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_IRQ_SW_CNT, sizeof(u32),
&__tmp) < 0))
goto nla_put_failure;
}
{
u32 __tmp = rQueryStaStatistics.IsrTxCnt;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_IRQ_TX_CNT, sizeof(u32),
&__tmp) < 0))
goto nla_put_failure;
}
{
u32 __tmp = rQueryStaStatistics.IsrRxCnt;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_IRQ_RX_CNT, sizeof(u32),
&__tmp) < 0))
goto nla_put_failure;
}
/* FW part STA link status */
{
u8 __tmp = rQueryStaStatistics.ucPer;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_PER, sizeof(u8),
&__tmp) < 0))
goto nla_put_failure;
}
{
u8 __tmp = rQueryStaStatistics.ucRcpi;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_RSSI, sizeof(u8),
&__tmp) < 0))
goto nla_put_failure;
}
{
u32 __tmp = rQueryStaStatistics.u4PhyMode;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_PHY_MODE, sizeof(u32),
&__tmp) < 0))
goto nla_put_failure;
}
{
u16 __tmp = rQueryStaStatistics.u2LinkSpeed;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_TX_RATE, sizeof(u16),
&__tmp) < 0))
goto nla_put_failure;
}
{
u32 __tmp = rQueryStaStatistics.u4TxFailCount;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_FAIL_CNT, sizeof(u32),
&__tmp) < 0))
goto nla_put_failure;
}
{
u32 __tmp = rQueryStaStatistics.u4TxLifeTimeoutCount;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_TIMEOUT_CNT, sizeof(u32),
&__tmp) < 0))
goto nla_put_failure;
}
{
u32 __tmp = rQueryStaStatistics.u4TxAverageAirTime;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_AVG_AIR_TIME, sizeof(u32),
&__tmp) < 0))
goto nla_put_failure;
}
/* Driver part link status */
{
u32 __tmp = rQueryStaStatistics.u4TxTotalCount;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_TOTAL_CNT, sizeof(u32),
&__tmp) < 0))
goto nla_put_failure;
}
{
u32 __tmp = rQueryStaStatistics.u4TxExceedThresholdCount;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_THRESHOLD_CNT, sizeof(u32),
&__tmp) < 0))
goto nla_put_failure;
}
{
u32 __tmp = rQueryStaStatistics.u4TxAverageProcessTime;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_AVG_PROCESS_TIME,
sizeof(u32), &__tmp) < 0))
goto nla_put_failure;
}
{
u32 __tmp = rQueryStaStatistics.u4TxMaxTime;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_MAX_PROCESS_TIME,
sizeof(u32), &__tmp) < 0))
goto nla_put_failure;
}
{
u32 __tmp = rQueryStaStatistics.u4TxAverageHifTime;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_AVG_HIF_PROCESS_TIME,
sizeof(u32), &__tmp) < 0))
goto nla_put_failure;
}
{
u32 __tmp = rQueryStaStatistics.u4TxMaxHifTime;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_MAX_HIF_PROCESS_TIME,
sizeof(u32), &__tmp) < 0))
goto nla_put_failure;
}
/* Network counter */
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_TC_EMPTY_CNT_ARRAY,
sizeof(rQueryStaStatistics.au4TcResourceEmptyCount),
rQueryStaStatistics.au4TcResourceEmptyCount) < 0))
goto nla_put_failure;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_NO_TC_ARRAY,
sizeof(rQueryStaStatistics.au4DequeueNoTcResource),
rQueryStaStatistics.au4DequeueNoTcResource) < 0))
goto nla_put_failure;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_RB_ARRAY,
sizeof(rQueryStaStatistics.au4TcResourceBackCount),
rQueryStaStatistics.au4TcResourceBackCount) < 0))
goto nla_put_failure;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_USED_TC_PGCT_ARRAY,
sizeof(rQueryStaStatistics.au4TcResourceUsedPageCount),
rQueryStaStatistics.au4TcResourceUsedPageCount) < 0))
goto nla_put_failure;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_WANTED_TC_PGCT_ARRAY,
sizeof(rQueryStaStatistics.au4TcResourceWantedPageCount),
rQueryStaStatistics.au4TcResourceWantedPageCount) < 0))
goto nla_put_failure;
/* Sta queue length */
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_TC_QUE_LEN_ARRAY,
sizeof(rQueryStaStatistics.au4TcQueLen),
rQueryStaStatistics.au4TcQueLen) < 0))
goto nla_put_failure;
/* Global QM counter */
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_TC_AVG_QUE_LEN_ARRAY,
sizeof(rQueryStaStatistics.au4TcAverageQueLen),
rQueryStaStatistics.au4TcAverageQueLen) < 0))
goto nla_put_failure;
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_TC_CUR_QUE_LEN_ARRAY,
sizeof(rQueryStaStatistics.au4TcCurrentQueLen),
rQueryStaStatistics.au4TcCurrentQueLen) < 0))
goto nla_put_failure;
/* Reserved field */
if (unlikely(nla_put(skb,
NL80211_TESTMODE_STA_STATISTICS_RESERVED_ARRAY,
sizeof(rQueryStaStatistics.au4Reserved),
rQueryStaStatistics.au4Reserved) < 0))
goto nla_put_failure;
return cfg80211_testmode_reply(skb);
nla_put_failure:
/* nal_put_skb_fail */
kfree_skb(skb);
return -EFAULT;
}
int
mtk_cfg80211_testmode_get_link_detection(IN struct wiphy
*wiphy, IN void *data, IN int len,
IN struct GLUE_INFO *prGlueInfo)
{
uint32_t rStatus = WLAN_STATUS_SUCCESS;
int32_t i4Status = -EINVAL;
uint32_t u4BufLen;
uint8_t u1buf = 0;
uint32_t i = 0;
uint32_t arBugReport[sizeof(struct _EVENT_BUG_REPORT_T)];
struct PARAM_802_11_STATISTICS_STRUCT rStatistics;
struct _EVENT_BUG_REPORT_T *prBugReport;
struct sk_buff *skb;
ASSERT(wiphy);
ASSERT(prGlueInfo);
prBugReport = (struct _EVENT_BUG_REPORT_T *) kalMemAlloc(
sizeof(struct _EVENT_BUG_REPORT_T), VIR_MEM_TYPE);
if (!prBugReport) {
DBGLOG(QM, TRACE, "%s allocate prBugReport failed\n",
__func__);
return -ENOMEM;
}
skb = cfg80211_testmode_alloc_reply_skb(wiphy,
sizeof(struct PARAM_802_11_STATISTICS_STRUCT) +
sizeof(struct _EVENT_BUG_REPORT_T) + 1);
if (!skb) {
kalMemFree(prBugReport, VIR_MEM_TYPE,
sizeof(struct _EVENT_BUG_REPORT_T));
DBGLOG(QM, TRACE, "%s allocate skb failed\n", __func__);
return -ENOMEM;
}
kalMemZero(&rStatistics, sizeof(rStatistics));
kalMemZero(prBugReport, sizeof(struct _EVENT_BUG_REPORT_T));
kalMemZero(arBugReport,
sizeof(struct _EVENT_BUG_REPORT_T) * sizeof(uint32_t));
rStatus = kalIoctl(prGlueInfo,
wlanoidQueryStatistics,
&rStatistics, sizeof(rStatistics),
TRUE, TRUE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
DBGLOG(INIT, INFO, "query statistics error:%x\n", rStatus);
rStatus = kalIoctl(prGlueInfo,
wlanoidQueryBugReport,
prBugReport, sizeof(struct _EVENT_BUG_REPORT_T),
TRUE, TRUE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
DBGLOG(INIT, INFO, "query statistics error:%x\n", rStatus);
kalMemCopy(arBugReport, prBugReport,
sizeof(struct _EVENT_BUG_REPORT_T));
rStatistics.u4RstReason = eResetReason;
rStatistics.u8RstTime = u8ResetTime;
rStatistics.u4RoamFailCnt = prGlueInfo->u4RoamFailCnt;
rStatistics.u8RoamFailTime = prGlueInfo->u8RoamFailTime;
rStatistics.u2TxDoneDelayIsARP =
prGlueInfo->fgTxDoneDelayIsARP;
rStatistics.u4ArriveDrvTick = prGlueInfo->u4ArriveDrvTick;
rStatistics.u4EnQueTick = prGlueInfo->u4EnQueTick;
rStatistics.u4DeQueTick = prGlueInfo->u4DeQueTick;
rStatistics.u4LeaveDrvTick = prGlueInfo->u4LeaveDrvTick;
rStatistics.u4CurrTick = prGlueInfo->u4CurrTick;
rStatistics.u8CurrTime = prGlueInfo->u8CurrTime;
if (!NLA_PUT_U8(skb, NL80211_TESTMODE_LINK_INVALID, &u1buf))
goto nla_put_failure;
if (!NLA_PUT_U64(skb, NL80211_TESTMODE_LINK_TX_FAIL_CNT,
&rStatistics.rFailedCount.QuadPart))
goto nla_put_failure;
if (!NLA_PUT_U64(skb, NL80211_TESTMODE_LINK_TX_RETRY_CNT,
&rStatistics.rRetryCount.QuadPart))
goto nla_put_failure;
if (!NLA_PUT_U64(skb,
NL80211_TESTMODE_LINK_TX_MULTI_RETRY_CNT,
&rStatistics.rMultipleRetryCount.QuadPart))
goto nla_put_failure;
if (!NLA_PUT_U64(skb, NL80211_TESTMODE_LINK_ACK_FAIL_CNT,
&rStatistics.rACKFailureCount.QuadPart))
goto nla_put_failure;
if (!NLA_PUT_U64(skb, NL80211_TESTMODE_LINK_FCS_ERR_CNT,
&rStatistics.rFCSErrorCount.QuadPart))
goto nla_put_failure;
if (!NLA_PUT_U64(skb, NL80211_TESTMODE_LINK_TX_CNT,
&rStatistics.rTransmittedFragmentCount.QuadPart))
goto nla_put_failure;
if (!NLA_PUT_U64(skb, NL80211_TESTMODE_LINK_RX_CNT,
&rStatistics.rReceivedFragmentCount.QuadPart))
goto nla_put_failure;
if (!NLA_PUT_U32(skb, NL80211_TESTMODE_LINK_RST_REASON,
&rStatistics.u4RstReason))
goto nla_put_failure;
if (!NLA_PUT_U64(skb, NL80211_TESTMODE_LINK_RST_TIME,
&rStatistics.u8RstTime))
goto nla_put_failure;
if (!NLA_PUT_U32(skb, NL80211_TESTMODE_LINK_ROAM_FAIL_TIMES,
&rStatistics.u4RoamFailCnt))
goto nla_put_failure;
if (!NLA_PUT_U64(skb, NL80211_TESTMODE_LINK_ROAM_FAIL_TIME,
&rStatistics.u8RoamFailTime))
goto nla_put_failure;
if (!NLA_PUT_U8(skb,
NL80211_TESTMODE_LINK_TX_DONE_DELAY_IS_ARP,
&rStatistics.u2TxDoneDelayIsARP))
goto nla_put_failure;
if (!NLA_PUT_U32(skb, NL80211_TESTMODE_LINK_ARRIVE_DRV_TICK,
&rStatistics.u4ArriveDrvTick))
goto nla_put_failure;
if (!NLA_PUT_U32(skb, NL80211_TESTMODE_LINK_ENQUE_TICK,
&rStatistics.u4EnQueTick))
goto nla_put_failure;
if (!NLA_PUT_U32(skb, NL80211_TESTMODE_LINK_DEQUE_TICK,
&rStatistics.u4DeQueTick))
goto nla_put_failure;
if (!NLA_PUT_U32(skb, NL80211_TESTMODE_LINK_LEAVE_DRV_TICK,
&rStatistics.u4LeaveDrvTick))
goto nla_put_failure;
if (!NLA_PUT_U32(skb, NL80211_TESTMODE_LINK_CURR_TICK,
&rStatistics.u4CurrTick))
goto nla_put_failure;
if (!NLA_PUT_U64(skb, NL80211_TESTMODE_LINK_CURR_TIME,
&rStatistics.u8CurrTime))
goto nla_put_failure;
for (i = 0;
i < sizeof(struct _EVENT_BUG_REPORT_T) / sizeof(uint32_t);
i++) {
if (!NLA_PUT_U32(skb, i + NL80211_TESTMODE_LINK_DETECT_NUM,
&arBugReport[i]))
goto nla_put_failure;
}
i4Status = cfg80211_testmode_reply(skb);
kalMemFree(prBugReport, VIR_MEM_TYPE,
sizeof(struct _EVENT_BUG_REPORT_T));
return i4Status;
nla_put_failure:
/* nal_put_skb_fail */
kfree_skb(skb);
kalMemFree(prBugReport, VIR_MEM_TYPE,
sizeof(struct _EVENT_BUG_REPORT_T));
return -EFAULT;
}
int mtk_cfg80211_testmode_sw_cmd(IN struct wiphy *wiphy,
IN void *data, IN int len)
{
struct GLUE_INFO *prGlueInfo = NULL;
struct NL80211_DRIVER_SW_CMD_PARAMS *prParams =
(struct NL80211_DRIVER_SW_CMD_PARAMS *) NULL;
uint32_t rstatus = WLAN_STATUS_SUCCESS;
int fgIsValid = 0;
uint32_t u4SetInfoLen = 0;
ASSERT(wiphy);
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
#if 0
DBGLOG(INIT, INFO, "--> %s()\n", __func__);
#endif
if (len < sizeof(struct NL80211_DRIVER_SW_CMD_PARAMS)) {
DBGLOG(REQ, ERROR, "len [%d] is invalid!\n", len);
return -EINVAL;
}
if (data && len)
prParams = (struct NL80211_DRIVER_SW_CMD_PARAMS *) data;
if (prParams) {
if (prParams->set == 1) {
rstatus = kalIoctl(prGlueInfo,
(PFN_OID_HANDLER_FUNC) wlanoidSetSwCtrlWrite,
&prParams->adr, (uint32_t) 8,
FALSE, FALSE, TRUE, &u4SetInfoLen);
}
}
if (rstatus != WLAN_STATUS_SUCCESS)
fgIsValid = -EFAULT;
return fgIsValid;
}
static int mtk_wlan_cfg_testmode_cmd(struct wiphy *wiphy,
void *data, int len)
{
struct GLUE_INFO *prGlueInfo = NULL;
struct NL80211_DRIVER_TEST_MODE_PARAMS *prParams = NULL;
int32_t i4Status;
ASSERT(wiphy);
if (len < sizeof(struct NL80211_DRIVER_TEST_MODE_PARAMS)) {
DBGLOG(REQ, ERROR, "len [%d] is invalid!\n", len);
return -EINVAL;
}
if (!data || !len) {
DBGLOG(REQ, ERROR, "mtk_cfg80211_testmode_cmd null data\n");
return -EINVAL;
}
if (!wiphy) {
DBGLOG(REQ, ERROR,
"mtk_cfg80211_testmode_cmd null wiphy\n");
return -EINVAL;
}
prGlueInfo = (struct GLUE_INFO *)wiphy_priv(wiphy);
prParams = (struct NL80211_DRIVER_TEST_MODE_PARAMS *)data;
/* Clear the version byte */
prParams->index = prParams->index & ~BITS(24, 31);
DBGLOG(INIT, TRACE, "params index=%x\n", prParams->index);
switch (prParams->index) {
case TESTMODE_CMD_ID_SW_CMD: /* SW cmd */
i4Status = mtk_cfg80211_testmode_sw_cmd(wiphy, data, len);
break;
case TESTMODE_CMD_ID_WAPI: /* WAPI */
#if CFG_SUPPORT_WAPI
i4Status = mtk_cfg80211_testmode_set_key_ext(wiphy, data,
len);
#endif
break;
case 0x10:
i4Status = mtk_cfg80211_testmode_get_sta_statistics(wiphy,
data, len, prGlueInfo);
break;
case 0x20:
i4Status = mtk_cfg80211_testmode_get_link_detection(wiphy,
data, len, prGlueInfo);
break;
#if CFG_SUPPORT_PASSPOINT
case TESTMODE_CMD_ID_HS20:
i4Status = mtk_cfg80211_testmode_hs20_cmd(wiphy, data, len);
break;
#endif /* CFG_SUPPORT_PASSPOINT */
case TESTMODE_CMD_ID_STR_CMD:
i4Status = mtk_cfg80211_process_str_cmd(prGlueInfo,
(uint8_t *)(prParams + 1), len - sizeof(*prParams));
break;
default:
i4Status = -EINVAL;
break;
}
if (i4Status != 0)
DBGLOG(REQ, TRACE, "prParams->index=%d, status=%d\n",
prParams->index, i4Status);
return i4Status;
}
#if KERNEL_VERSION(3, 12, 0) <= CFG80211_VERSION_CODE
int mtk_cfg80211_testmode_cmd(struct wiphy *wiphy,
struct wireless_dev *wdev,
void *data, int len)
{
ASSERT(wdev);
return mtk_wlan_cfg_testmode_cmd(wiphy, data, len);
}
#else
int mtk_cfg80211_testmode_cmd(struct wiphy *wiphy,
void *data, int len)
{
return mtk_wlan_cfg_testmode_cmd(wiphy, data, len);
}
#endif
#endif
#if CFG_SUPPORT_SCHED_SCAN
int mtk_cfg80211_sched_scan_start(IN struct wiphy *wiphy,
IN struct net_device *ndev,
IN struct cfg80211_sched_scan_request *request)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint32_t rStatus;
uint32_t i, u4BufLen;
struct PARAM_SCHED_SCAN_REQUEST *prSchedScanRequest;
uint32_t num = 0;
if (likely(request)) {
scanlog_dbg(LOG_SCHED_SCAN_REQ_START_K2D, INFO, "ssid(%d)match(%d)ch(%u)f(%u)rssi(%d)\n",
request->n_ssids, request->n_match_sets,
request->n_channels, request->flags,
#if KERNEL_VERSION(3, 15, 0) <= CFG80211_VERSION_CODE
request->min_rssi_thold);
#else
request->rssi_thold);
#endif
} else
scanlog_dbg(LOG_SCHED_SCAN_REQ_START_K2D, INFO, "--> %s()\n",
__func__);
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
if (prGlueInfo->prAdapter == NULL) {
DBGLOG(REQ, ERROR, "prGlueInfo->prAdapter is NULL");
return -EINVAL;
}
#if CFG_SUPPORT_LOWLATENCY_MODE
if (!prGlueInfo->prAdapter->fgEnCfg80211Scan
&& PARAM_MEDIA_STATE_CONNECTED
== kalGetMediaStateIndicated(prGlueInfo)) {
DBGLOG(REQ, INFO,
"sched_scan_start LowLatency reject scan\n");
return -EBUSY;
}
#endif /* CFG_SUPPORT_LOWLATENCY_MODE */
if (prGlueInfo->prSchedScanRequest != NULL) {
DBGLOG(SCN, ERROR,
"GlueInfo->prSchedScanRequest != NULL\n");
return -EBUSY;
} else if (request == NULL) {
DBGLOG(SCN, ERROR, "request == NULL\n");
return -EINVAL;
} else if (!request->n_match_sets) {
/* invalid scheduled scan request */
DBGLOG(SCN, ERROR,
"No match sets. No need to do sched scan\n");
return -EINVAL;
} else if (request->n_match_sets >
CFG_SCAN_SSID_MATCH_MAX_NUM) {
DBGLOG(SCN, WARN, "request->n_match_sets(%d) > %d\n",
request->n_match_sets,
CFG_SCAN_SSID_MATCH_MAX_NUM);
return -EINVAL;
} else if (request->n_ssids >
CFG_SCAN_HIDDEN_SSID_MAX_NUM) {
DBGLOG(SCN, WARN, "request->n_ssids(%d) > %d\n",
request->n_ssids, CFG_SCAN_HIDDEN_SSID_MAX_NUM);
return -EINVAL;
}
prSchedScanRequest = (struct PARAM_SCHED_SCAN_REQUEST *)
kalMemAlloc(sizeof(struct PARAM_SCHED_SCAN_REQUEST),
VIR_MEM_TYPE);
if (prSchedScanRequest == NULL) {
DBGLOG(SCN, ERROR, "prSchedScanRequest kalMemAlloc fail\n");
return -ENOMEM;
}
kalMemZero(prSchedScanRequest,
sizeof(struct PARAM_SCHED_SCAN_REQUEST));
/* passed in the probe_reqs in active scans */
if (request->ssids) {
for (i = 0; i < request->n_ssids; i++) {
DBGLOG(SCN, TRACE, "ssids : (%d)[%s]\n",
i, request->ssids[i].ssid);
/* driver ignored the null ssid */
if (request->ssids[i].ssid_len == 0
|| request->ssids[i].ssid[0] == 0)
DBGLOG(SCN, TRACE, "ignore null ssid(%d)\n", i);
else {
struct PARAM_SSID *prSsid;
prSsid = &(prSchedScanRequest->arSsid[num]);
COPY_SSID(prSsid->aucSsid, prSsid->u4SsidLen,
request->ssids[i].ssid,
request->ssids[i].ssid_len);
num++;
}
}
}
prSchedScanRequest->u4SsidNum = num;
#if KERNEL_VERSION(3, 15, 0) <= CFG80211_VERSION_CODE
prSchedScanRequest->i4MinRssiThold =
request->min_rssi_thold;
#else
prSchedScanRequest->i4MinRssiThold = request->rssi_thold;
#endif
num = 0;
if (request->match_sets) {
for (i = 0; i < request->n_match_sets; i++) {
DBGLOG(SCN, TRACE, "match : (%d)[%s]\n", i,
request->match_sets[i].ssid.ssid);
/* driver ignored the null ssid */
if (request->match_sets[i].ssid.ssid_len == 0
|| request->match_sets[i].ssid.ssid[0] == 0)
DBGLOG(SCN, TRACE, "ignore null ssid(%d)\n", i);
else {
struct PARAM_SSID *prSsid =
&(prSchedScanRequest->arMatchSsid[num]);
COPY_SSID(prSsid->aucSsid,
prSsid->u4SsidLen,
request->match_sets[i].ssid.ssid,
request->match_sets[i].ssid.ssid_len);
#if KERNEL_VERSION(3, 15, 0) <= CFG80211_VERSION_CODE
prSchedScanRequest->ai4RssiThold[i] =
request->match_sets[i].rssi_thold;
#else
prSchedScanRequest->ai4RssiThold[i] =
request->rssi_thold;
#endif
num++;
}
}
}
prSchedScanRequest->u4MatchSsidNum = num;
if (kalSchedScanParseRandomMac(ndev, request,
prSchedScanRequest->aucRandomMac,
prSchedScanRequest->aucRandomMacMask)) {
prSchedScanRequest->ucScnFuncMask |= ENUM_SCN_RANDOM_MAC_EN;
}
prSchedScanRequest->u4IELength = request->ie_len;
if (request->ie_len > 0) {
prSchedScanRequest->pucIE =
kalMemAlloc(request->ie_len, VIR_MEM_TYPE);
if (prSchedScanRequest->pucIE == NULL) {
DBGLOG(SCN, ERROR, "pucIE kalMemAlloc fail\n");
} else {
kalMemZero(prSchedScanRequest->pucIE, request->ie_len);
kalMemCopy(prSchedScanRequest->pucIE,
(uint8_t *)request->ie, request->ie_len);
}
}
#if KERNEL_VERSION(4, 4, 0) <= CFG80211_VERSION_CODE
prSchedScanRequest->u2ScanInterval =
(uint16_t) (request->scan_plans->interval);
#else
prSchedScanRequest->u2ScanInterval = (uint16_t) (
request->interval);
#endif
prSchedScanRequest->ucChnlNum = (uint8_t)
request->n_channels;
prSchedScanRequest->pucChannels =
kalMemAlloc(request->n_channels, VIR_MEM_TYPE);
if (!prSchedScanRequest->pucChannels) {
DBGLOG(SCN, ERROR, "pucChannels kalMemAlloc fail\n");
prSchedScanRequest->ucChnlNum = 0;
} else {
for (i = 0; i < request->n_channels; i++) {
uint32_t freq =
request->channels[i]->center_freq * 1000;
prSchedScanRequest->pucChannels[i] =
nicFreq2ChannelNum(freq);
}
}
rStatus = kalIoctl(prGlueInfo, wlanoidSetStartSchedScan,
prSchedScanRequest,
sizeof(struct PARAM_SCHED_SCAN_REQUEST),
FALSE, FALSE, TRUE, &u4BufLen);
kalMemFree(prSchedScanRequest->pucChannels,
VIR_MEM_TYPE, request->n_channels);
kalMemFree(prSchedScanRequest->pucIE,
VIR_MEM_TYPE, request->ie_len);
kalMemFree(prSchedScanRequest,
VIR_MEM_TYPE, sizeof(struct PARAM_SCHED_SCAN_REQUEST));
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(REQ, WARN, "scheduled scan error:%x\n", rStatus);
return -EINVAL;
}
prGlueInfo->prSchedScanRequest = request;
return 0;
}
int mtk_cfg80211_sched_scan_stop(IN struct wiphy *wiphy,
IN struct net_device *ndev)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint32_t rStatus;
uint32_t u4BufLen;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
scanlog_dbg(LOG_SCHED_SCAN_REQ_STOP_K2D, INFO, "--> %s()\n", __func__);
/* check if there is any pending scan/sched_scan not yet finished */
if (prGlueInfo->prSchedScanRequest == NULL)
return -EPERM; /* Operation not permitted */
rStatus = kalIoctl(prGlueInfo, wlanoidSetStopSchedScan,
NULL, 0,
FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus == WLAN_STATUS_FAILURE) {
DBGLOG(REQ, WARN, "scheduled scan error:%x\n", rStatus);
return -EINVAL;
}
prGlueInfo->prSchedScanRequest = NULL;
return 0;
}
#endif /* CFG_SUPPORT_SCHED_SCAN */
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for handling association request
*
* @param
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
int mtk_cfg80211_assoc(struct wiphy *wiphy,
struct net_device *ndev, struct cfg80211_assoc_request *req)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t arBssid[PARAM_MAC_ADDR_LEN];
uint32_t rStatus;
uint32_t u4BufLen;
#if CFG_SUPPORT_CFG80211_AUTH
enum ENUM_WEP_STATUS eEncStatus;
enum ENUM_PARAM_AUTH_MODE eAuthMode;
uint32_t cipher;
uint32_t i, u4AkmSuite;
struct DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY *prEntry;
struct CONNECTION_SETTINGS *prConnSettings = NULL;
uint8_t *prDesiredIE = NULL;
uint8_t *pucIEStart = NULL;
u_int8_t fgCarryWPSIE = FALSE;
struct RSN_INFO rRsnInfo;
#if CFG_SUPPORT_802_11R
uint32_t u4InfoBufLen = 0;
#endif
uint8_t fgCarryRsnxe = FALSE;
#endif
#if CFG_SUPPORT_CFG80211_AUTH
rRsnInfo.u2PmkidCnt = 0;
kalMemZero(rRsnInfo.aucPmkidList, sizeof(rRsnInfo.aucPmkidList));
#endif
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
#if CFG_SUPPORT_CFG80211_AUTH
prConnSettings = &prGlueInfo->prAdapter->rWifiVar.rConnSettings;
/* [todo]temp use for indicate rx assoc resp,
* may need to be modified
*/
/* The BSS from cfg80211_ops.assoc must give back to
* cfg80211_send_rx_assoc() or to cfg80211_assoc_timeout().
* To ensure proper refcounting, new association requests
* while already associating must be rejected.
*/
if (prConnSettings->bss)
return -ENOENT;
prConnSettings->bss = req->bss;
#endif
DBGLOG(REQ, INFO, "mtk_cfg80211_assoc, media state:%d\n",
prGlueInfo->eParamMediaStateIndicated);
{
kalMemZero(arBssid, MAC_ADDR_LEN);
if (prGlueInfo->eParamMediaStateIndicated ==
PARAM_MEDIA_STATE_CONNECTED) {
wlanQueryInformation(prGlueInfo->prAdapter,
wlanoidQueryBssid,
&arBssid[0],
sizeof(arBssid),
&u4BufLen);
#if !CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT || !CFG_SUPPORT_802_11R
/* 1. check BSSID */
if (UNEQUAL_MAC_ADDR(arBssid,
req->bss->bssid)) {
/* wrong MAC address */
DBGLOG(REQ, WARN,
"incorrect BSSID: [" MACSTR
"] currently connected BSSID["
MACSTR "]\n",
MAC2STR(req->bss->bssid),
MAC2STR(arBssid));
return -ENOENT;
}
#endif
}
}
#if CFG_SUPPORT_CFG80211_AUTH
/* <1> Reset WPA info */
prGlueInfo->rWpaInfo.u4WpaVersion =
IW_AUTH_WPA_VERSION_DISABLED;
prGlueInfo->rWpaInfo.u4KeyMgmt = 0;
prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_NONE;
prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE;
#if CFG_SUPPORT_802_11W
prGlueInfo->rWpaInfo.u4CipherGroupMgmt = IW_AUTH_CIPHER_NONE;
prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED;
prGlueInfo->rWpaInfo.ucRSNMfpCap = RSN_AUTH_MFP_DISABLED;
#endif
prGlueInfo->rWpaInfo.ucRsneLen = 0;
/* 2.Fill WPA version */
if (req->crypto.wpa_versions & NL80211_WPA_VERSION_1)
prGlueInfo->rWpaInfo.u4WpaVersion =
IW_AUTH_WPA_VERSION_WPA;
else if (req->crypto.wpa_versions & NL80211_WPA_VERSION_2)
prGlueInfo->rWpaInfo.u4WpaVersion =
IW_AUTH_WPA_VERSION_WPA2;
else
prGlueInfo->rWpaInfo.u4WpaVersion =
IW_AUTH_WPA_VERSION_DISABLED;
DBGLOG(REQ, INFO, "wpa ver=%d\n",
prGlueInfo->rWpaInfo.u4WpaVersion);
/* 3.Fill pairwise cipher suite */
if (req->crypto.n_ciphers_pairwise) {
DBGLOG(RSN, INFO, "[wlan] cipher pairwise (%x)\n",
req->crypto.ciphers_pairwise[0]);
prGlueInfo->prAdapter->rWifiVar.rConnSettings.rRsnInfo
.au4PairwiseKeyCipherSuite[0] =
req->crypto.ciphers_pairwise[0];
switch (req->crypto.ciphers_pairwise[0]) {
case WLAN_CIPHER_SUITE_WEP40:
prGlueInfo->rWpaInfo.u4CipherPairwise =
IW_AUTH_CIPHER_WEP40;
break;
case WLAN_CIPHER_SUITE_WEP104:
prGlueInfo->rWpaInfo.u4CipherPairwise =
IW_AUTH_CIPHER_WEP104;
break;
case WLAN_CIPHER_SUITE_TKIP:
prGlueInfo->rWpaInfo.u4CipherPairwise =
IW_AUTH_CIPHER_TKIP;
break;
case WLAN_CIPHER_SUITE_CCMP:
prGlueInfo->rWpaInfo.u4CipherPairwise =
IW_AUTH_CIPHER_CCMP;
break;
case WLAN_CIPHER_SUITE_AES_CMAC:
prGlueInfo->rWpaInfo.u4CipherPairwise =
IW_AUTH_CIPHER_CCMP;
break;
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
prGlueInfo->rWpaInfo.u4CipherPairwise =
IW_AUTH_CIPHER_GCMP256;
break;
case WLAN_CIPHER_SUITE_GCMP_256:
prGlueInfo->rWpaInfo.u4CipherPairwise =
IW_AUTH_CIPHER_GCMP256;
break;
default:
DBGLOG(REQ, WARN,
"invalid cipher pairwise (%d)\n",
req->crypto.ciphers_pairwise[0]);
return -EINVAL;
}
}
/* 4. Fill group cipher suite */
if (req->crypto.cipher_group) {
DBGLOG(RSN, INFO, "[wlan] cipher group (%x)\n",
req->crypto.cipher_group);
prGlueInfo->prAdapter->rWifiVar.rConnSettings.rRsnInfo
.u4GroupKeyCipherSuite =
req->crypto.cipher_group;
switch (req->crypto.cipher_group) {
case WLAN_CIPHER_SUITE_WEP40:
prGlueInfo->rWpaInfo.u4CipherGroup =
IW_AUTH_CIPHER_WEP40;
break;
case WLAN_CIPHER_SUITE_WEP104:
prGlueInfo->rWpaInfo.u4CipherGroup =
IW_AUTH_CIPHER_WEP104;
break;
case WLAN_CIPHER_SUITE_TKIP:
prGlueInfo->rWpaInfo.u4CipherGroup =
IW_AUTH_CIPHER_TKIP;
break;
case WLAN_CIPHER_SUITE_CCMP:
prGlueInfo->rWpaInfo.u4CipherGroup =
IW_AUTH_CIPHER_CCMP;
break;
case WLAN_CIPHER_SUITE_AES_CMAC:
prGlueInfo->rWpaInfo.u4CipherGroup =
IW_AUTH_CIPHER_CCMP;
break;
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
prGlueInfo->rWpaInfo.u4CipherGroup =
IW_AUTH_CIPHER_GCMP256;
break;
case WLAN_CIPHER_SUITE_GCMP_256:
prGlueInfo->rWpaInfo.u4CipherGroup =
IW_AUTH_CIPHER_GCMP256;
break;
case WLAN_CIPHER_SUITE_NO_GROUP_ADDR:
break;
default:
DBGLOG(REQ, WARN, "invalid cipher group (%d)\n",
req->crypto.cipher_group);
return -EINVAL;
}
}
/* 5. Fill encryption status */
cipher = prGlueInfo->rWpaInfo.u4CipherGroup |
prGlueInfo->rWpaInfo.u4CipherPairwise;
if (1 /* prGlueInfo->rWpaInfo.fgPrivacyInvoke */) {
if (cipher & IW_AUTH_CIPHER_GCMP256) {
eEncStatus = ENUM_ENCRYPTION4_ENABLED;
} else if (cipher & IW_AUTH_CIPHER_CCMP) {
eEncStatus = ENUM_ENCRYPTION3_ENABLED;
} else if (cipher & IW_AUTH_CIPHER_TKIP) {
eEncStatus = ENUM_ENCRYPTION2_ENABLED;
} else if (cipher & (IW_AUTH_CIPHER_WEP104 |
IW_AUTH_CIPHER_WEP40)) {
eEncStatus = ENUM_ENCRYPTION1_ENABLED;
} else if (cipher & IW_AUTH_CIPHER_NONE) {
if (prGlueInfo->rWpaInfo.fgPrivacyInvoke)
eEncStatus = ENUM_ENCRYPTION1_ENABLED;
else
eEncStatus = ENUM_ENCRYPTION_DISABLED;
} else {
eEncStatus = ENUM_ENCRYPTION_DISABLED;
}
} else {
eEncStatus = ENUM_ENCRYPTION_DISABLED;
}
rStatus = kalIoctl(prGlueInfo,
wlanoidSetEncryptionStatus,
&eEncStatus,
sizeof(eEncStatus), FALSE, FALSE, FALSE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
DBGLOG(REQ, WARN,
"set encryption mode error:%x\n",
rStatus);
/* 6. Fill AKM suites */
u4AkmSuite = 0;
eAuthMode = 0;
DBGLOG(REQ, INFO, "request numbers of Akm Suite:%d\n",
req->crypto.n_akm_suites);
for (i = 0; i < req->crypto.n_akm_suites; i++)
DBGLOG(REQ, INFO, "request Akm Suite[%d]:%d\n",
i, req->crypto.akm_suites[i]);
if (req->crypto.n_akm_suites) {
prGlueInfo->prAdapter->rWifiVar.rConnSettings.rRsnInfo
.au4AuthKeyMgtSuite[0] =
req->crypto.akm_suites[0];
DBGLOG(REQ, INFO,
"Akm Suite:%d\n",
req->crypto.akm_suites[0]);
if (prGlueInfo->rWpaInfo.u4WpaVersion ==
IW_AUTH_WPA_VERSION_WPA) {
switch (req->crypto.akm_suites[0]) {
case WLAN_AKM_SUITE_8021X:
eAuthMode = AUTH_MODE_WPA;
u4AkmSuite = WPA_AKM_SUITE_802_1X;
break;
case WLAN_AKM_SUITE_PSK:
eAuthMode = AUTH_MODE_WPA_PSK;
u4AkmSuite = WPA_AKM_SUITE_PSK;
break;
default:
DBGLOG(REQ, WARN,
"invalid Akm Suite (%08x)\n",
req->crypto.akm_suites[0]);
return -EINVAL;
}
} else if (prGlueInfo->rWpaInfo.u4WpaVersion ==
IW_AUTH_WPA_VERSION_WPA2) {
switch (req->crypto.akm_suites[0]) {
case WLAN_AKM_SUITE_8021X:
eAuthMode = AUTH_MODE_WPA2;
u4AkmSuite = RSN_AKM_SUITE_802_1X;
break;
case WLAN_AKM_SUITE_PSK:
eAuthMode = AUTH_MODE_WPA2_PSK;
u4AkmSuite = RSN_AKM_SUITE_PSK;
break;
#if CFG_SUPPORT_802_11R
case WLAN_AKM_SUITE_FT_8021X:
eAuthMode = AUTH_MODE_WPA2_FT;
u4AkmSuite = RSN_AKM_SUITE_FT_802_1X;
break;
case WLAN_AKM_SUITE_FT_PSK:
eAuthMode = AUTH_MODE_WPA2_FT_PSK;
u4AkmSuite = RSN_AKM_SUITE_FT_PSK;
break;
#endif
#if CFG_SUPPORT_802_11W
/* Notice:: Need kernel patch!! */
case WLAN_AKM_SUITE_8021X_SHA256:
eAuthMode = AUTH_MODE_WPA2;
u4AkmSuite =
RSN_AKM_SUITE_802_1X_SHA256;
break;
case WLAN_AKM_SUITE_PSK_SHA256:
eAuthMode = AUTH_MODE_WPA2_PSK;
u4AkmSuite =
RSN_AKM_SUITE_PSK_SHA256;
break;
#endif
case WLAN_AKM_SUITE_8021X_SUITE_B:
eAuthMode = AUTH_MODE_WPA2_PSK;
u4AkmSuite =
RSN_AKM_SUITE_8021X_SUITE_B_192;
break;
case WLAN_AKM_SUITE_8021X_SUITE_B_192:
eAuthMode = AUTH_MODE_WPA2_PSK;
u4AkmSuite =
RSN_AKM_SUITE_8021X_SUITE_B_192;
break;
#if CFG_SUPPORT_SAE
/* Need to add in WPA also? */
case WLAN_AKM_SUITE_SAE:
eAuthMode = AUTH_MODE_WPA2_SAE;
u4AkmSuite = RSN_AKM_SUITE_SAE;
break;
#endif
#if CFG_SUPPORT_OWE
case WLAN_AKM_SUITE_OWE:
eAuthMode = AUTH_MODE_WPA2_PSK;
u4AkmSuite = RSN_AKM_SUITE_OWE;
break;
#endif
#if CFG_SUPPORT_DPP
case WLAN_AKM_SUITE_DPP:
eAuthMode = AUTH_MODE_WPA2_PSK;
u4AkmSuite = RSN_AKM_SUITE_DPP;
break;
#endif
default:
DBGLOG(REQ, WARN,
"invalid Akm Suite (%08x)\n",
req->crypto.akm_suites[0]);
return -EINVAL;
}
}
}
if (prGlueInfo->rWpaInfo.u4WpaVersion ==
IW_AUTH_WPA_VERSION_DISABLED) {
eAuthMode = (prGlueInfo->rWpaInfo.u4AuthAlg ==
IW_AUTH_ALG_OPEN_SYSTEM) ?
AUTH_MODE_OPEN : AUTH_MODE_AUTO_SWITCH;
}
DBGLOG(REQ, INFO, "set auth mode:%d, akm suite:0x%x\n",
eAuthMode, u4AkmSuite);
/* 6.1 Set auth mode*/
rStatus = kalIoctl(prGlueInfo, wlanoidSetAuthMode, &eAuthMode,
sizeof(eAuthMode), FALSE, FALSE, FALSE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
DBGLOG(REQ, WARN, "set auth mode error:%x\n", rStatus);
/* 6.2 Enable the specific AKM suite only. */
for (i = 0; i < MAX_NUM_SUPPORTED_AKM_SUITES; i++) {
prEntry = &prGlueInfo->prAdapter
->rMib.dot11RSNAConfigAuthenticationSuitesTable[i];
if (prEntry->dot11RSNAConfigAuthenticationSuite == u4AkmSuite) {
prEntry->dot11RSNAConfigAuthenticationSuiteEnabled
= TRUE;
DBGLOG(REQ, INFO, "match AuthenticationSuite = 0x%x",
u4AkmSuite);
} else {
prEntry->dot11RSNAConfigAuthenticationSuiteEnabled
= FALSE;
}
}
#endif
/* 7. Parsing desired ie from upper layer */
prGlueInfo->fgWpsActive = FALSE;
if (req->ie && req->ie_len > 0) {
#if CFG_SUPPORT_CFG80211_AUTH
pucIEStart = (uint8_t *)req->ie;
#if CFG_SUPPORT_WAPI
rStatus = kalIoctl(prGlueInfo,
wlanoidSetWapiAssocInfo,
pucIEStart, req->ie_len,
FALSE, FALSE, FALSE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
DBGLOG(SEC, WARN,
"[wapi] set wapi assoc info error:%x\n", rStatus);
#endif
#if CFG_SUPPORT_WPS2
if (wextSrchDesiredWPSIE(pucIEStart, req->ie_len, 0xDD,
(uint8_t **) &prDesiredIE)) {
prGlueInfo->fgWpsActive = TRUE;
fgCarryWPSIE = TRUE;
rStatus = kalIoctl(prGlueInfo, wlanoidSetWSCAssocInfo,
prDesiredIE, IE_SIZE(prDesiredIE),
FALSE, FALSE, FALSE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
DBGLOG(SEC, WARN,
"[WSC] set WSC assoc info error:%x\n",
rStatus);
}
#endif
#endif
#if CFG_SUPPORT_PASSPOINT
if (wextSrchDesiredHS20IE((uint8_t *) req->ie, req->ie_len,
(uint8_t **) &prDesiredIE)) {
rStatus = kalIoctl(prGlueInfo, wlanoidSetHS20Info,
prDesiredIE, IE_SIZE(prDesiredIE),
FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
/* DBGLOG(REQ, TRACE,
* ("[HS20] set HS20 assoc info error:%x\n",
* rStatus));
*/
}
}
if (wextSrchDesiredInterworkingIE((uint8_t *) req->ie,
req->ie_len, (uint8_t **) &prDesiredIE)) {
rStatus = kalIoctl(prGlueInfo,
wlanoidSetInterworkingInfo, prDesiredIE,
IE_SIZE(prDesiredIE),
FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
/* DBGLOG(REQ, TRACE,
* ("[HS20] set Interworking assoc info error:
* %x\n", rStatus));
*/
}
}
if (wextSrchDesiredRoamingConsortiumIE((uint8_t *) req->ie,
req->ie_len, (uint8_t **) &prDesiredIE)) {
rStatus = kalIoctl(prGlueInfo,
wlanoidSetRoamingConsortiumIEInfo,
prDesiredIE, IE_SIZE(prDesiredIE),
FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
/* DBGLOG(REQ, TRACE,
* ("[HS20] set RoamingConsortium assoc info
* error:%x\n", rStatus));
*/
}
}
#endif /* CFG_SUPPORT_PASSPOINT */
#if CFG_SUPPORT_CFG80211_AUTH
if (wextSrchDesiredWPAIE(pucIEStart, req->ie_len, 0x30,
(uint8_t **) &prDesiredIE)) {
if (rsnParseRsnIE(prGlueInfo->prAdapter,
(struct RSN_INFO_ELEM *)prDesiredIE,
&rRsnInfo)) {
#if CFG_SUPPORT_802_11W
/* Fill RSNE MFP Cap */
if (rRsnInfo.u2RsnCap & ELEM_WPA_CAP_MFPC) {
prGlueInfo->rWpaInfo.u4CipherGroupMgmt
= rRsnInfo
.u4GroupMgmtKeyCipherSuite;
prGlueInfo->rWpaInfo.ucRSNMfpCap =
RSN_AUTH_MFP_OPTIONAL;
if (rRsnInfo.u2RsnCap &
ELEM_WPA_CAP_MFPR)
prGlueInfo->rWpaInfo.ucRSNMfpCap
= RSN_AUTH_MFP_REQUIRED;
} else
prGlueInfo->rWpaInfo.ucRSNMfpCap =
RSN_AUTH_MFP_DISABLED;
#endif
prGlueInfo->rWpaInfo.ucRsneLen = rRsnInfo.ucRsneLen;
/* Fill RSNE PMKID Count and List */
prConnSettings->rRsnInfo.u2PmkidCnt =
rRsnInfo.u2PmkidCnt;
if (rRsnInfo.u2PmkidCnt > 0)
kalMemCopy(prConnSettings
->rRsnInfo.aucPmkidList,
rRsnInfo.aucPmkidList,
(rRsnInfo.u2PmkidCnt * RSN_PMKID_LEN));
}
}
/* Find non-wfa vendor specific ies set from upper layer */
if (cfg80211_get_non_wfa_vendor_ie(prGlueInfo, pucIEStart,
req->ie_len) > 0) {
DBGLOG(RSN, INFO, "Found non-wfa vendor ie (len=%u)\n",
prGlueInfo->non_wfa_vendor_ie_len);
}
#if CFG_SUPPORT_OWE
/* Gen OWE IE */
if (wextSrchDesiredWPAIE(pucIEStart, req->ie_len, 0xff,
(uint8_t **) &prDesiredIE)) {
uint8_t ucLength = (*(prDesiredIE+1)+2);
kalMemCopy(&prGlueInfo->prAdapter
->rWifiVar.rConnSettings.rOweInfo,
prDesiredIE, ucLength);
DBGLOG(REQ, INFO, "DUMP OWE INFO, EID %x length %x\n",
*prDesiredIE, ucLength);
DBGLOG_MEM8(REQ, INFO, &prGlueInfo->prAdapter
->rWifiVar.rConnSettings.rOweInfo, ucLength);
} else {
kalMemSet(&prGlueInfo->prAdapter
->rWifiVar.rConnSettings.rOweInfo,
0, sizeof(struct OWE_INFO_T));
}
#endif
/* Gen RSNXE */
if (wextSrchDesiredWPAIE(pucIEStart,
req->ie_len, 0xf4, (uint8_t **) &prDesiredIE)) {
uint16_t u2Length = (*(prDesiredIE+1)+2);
if (u2Length <= sizeof(prConnSettings->rRsnXE)) {
kalMemCopy(
&prConnSettings->rRsnXE,
prDesiredIE, u2Length);
fgCarryRsnxe = TRUE;
DBGLOG(REQ, INFO,
"DUMP RSNXE, EID %x length %x\n",
*prDesiredIE, u2Length);
DBGLOG_MEM8(REQ, INFO,
&prConnSettings->rRsnXE,
u2Length);
} else {
DBGLOG(RSN, ERROR, "RSNXE length exceeds 2\n");
}
}
if (fgCarryRsnxe == FALSE) {
kalMemSet(&prConnSettings->rRsnXE,
0, sizeof(struct RSNXE));
}
#if CFG_SUPPORT_802_11R
if (prGlueInfo->prAdapter->rWifiVar
.rConnSettings.eAuthMode == AUTH_MODE_WPA2_FT ||
prGlueInfo->prAdapter->rWifiVar.rConnSettings.eAuthMode ==
AUTH_MODE_WPA2_FT_PSK) {
rStatus = kalIoctl(prGlueInfo, wlanoidUpdateFtIes,
(void *)pucIEStart, req->ie_len, FALSE,
FALSE, FALSE, &u4InfoBufLen);
DBGLOG(REQ, TRACE,
"wlanoidUpdateFtIes rStatus 0x%x\n", rStatus);
}
#endif
#endif
}
#if CFG_SUPPORT_CFG80211_AUTH
/* clear WSC Assoc IE buffer in case WPS IE is not detected */
if (fgCarryWPSIE == FALSE) {
kalMemZero(&prGlueInfo->aucWSCAssocInfoIE, 200);
prGlueInfo->u2WSCAssocInfoIELen = 0;
}
#endif
/* Fill WPA info - mfp setting */
/* Must put after paring RSNE from upper layer
* for prGlueInfo->rWpaInfo.ucRSNMfpCap assignment
*/
#if CFG_SUPPORT_802_11W
prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED;
if (req->use_mfp)
prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_REQUIRED;
else {
/* Change Mfp parameter from DISABLED to OPTIONAL
* if upper layer set MFPC = 1 in RSNE
* since upper layer can't bring MFP OPTIONAL information
* to driver by sme->mfp
*/
if (prGlueInfo->rWpaInfo.ucRSNMfpCap ==
RSN_AUTH_MFP_OPTIONAL)
prGlueInfo->rWpaInfo.u4Mfp =
IW_AUTH_MFP_OPTIONAL;
else if (prGlueInfo->rWpaInfo.ucRSNMfpCap ==
RSN_AUTH_MFP_REQUIRED)
DBGLOG(REQ, WARN,
"mfp parameter(DISABLED) conflict with mfp cap(REQUIRED)\n");
}
/* DBGLOG(REQ, INFO, "MFP=%d\n", prGlueInfo->rWpaInfo.u4Mfp); */
#endif
#if CFG_SUPPORT_CFG80211_AUTH
/*[TODO]may to check if assoc
* parameters change as cfg80211_auth
*/
prConnSettings->fgIsSendAssoc = TRUE;
if ((!prConnSettings->fgIsConnInitialized)) {
rStatus = kalIoctl(prGlueInfo, wlanoidSetBssid,
(void *) req->bss->bssid, MAC_ADDR_LEN,
FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(REQ, WARN, "set BSSID:%x\n", rStatus);
return -EINVAL;
}
} else { /* skip join initial flow when it has been completed*/
rStatus = kalIoctl(prGlueInfo, wlanoidSendAuthAssoc,
(void *)req->bss->bssid, MAC_ADDR_LEN,
FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(REQ, WARN, "send assoc failed:%x\n", rStatus);
return -EINVAL;
}
}
#else
rStatus = kalIoctl(prGlueInfo, wlanoidSetBssid,
(void *)req->bss->bssid, MAC_ADDR_LEN,
FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(REQ, WARN, "set BSSID:%x\n", rStatus);
return -EINVAL;
}
#endif
return 0;
}
#if CFG_SUPPORT_NFC_BEAM_PLUS
int mtk_cfg80211_testmode_get_scan_done(IN struct wiphy
*wiphy, IN void *data, IN int len,
IN struct GLUE_INFO *prGlueInfo)
{
int32_t i4Status = -EINVAL;
#ifdef CONFIG_NL80211_TESTMODE
#define NL80211_TESTMODE_P2P_SCANDONE_INVALID 0
#define NL80211_TESTMODE_P2P_SCANDONE_STATUS 1
uint32_t rStatus = WLAN_STATUS_SUCCESS;
int32_t READY_TO_BEAM = 0;
struct sk_buff *skb = NULL;
ASSERT(wiphy);
ASSERT(prGlueInfo);
skb = cfg80211_testmode_alloc_reply_skb(wiphy,
sizeof(uint32_t));
/* READY_TO_BEAM =
* (UINT_32)(prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo
* .fgIsGOInitialDone)
* &(!prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo
* .fgIsScanRequest);
*/
READY_TO_BEAM = 1;
/* DBGLOG(QM, TRACE,
* "NFC:GOInitialDone[%d] and P2PScanning[%d]\n",
* prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo
* .fgIsGOInitialDone,
* prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo
* .fgIsScanRequest));
*/
if (!skb) {
DBGLOG(QM, TRACE, "%s allocate skb failed:%x\n", __func__,
rStatus);
return -ENOMEM;
}
{
u8 __tmp = 0;
if (unlikely(nla_put(skb, NL80211_TESTMODE_P2P_SCANDONE_INVALID,
sizeof(u8), &__tmp) < 0)) {
kfree_skb(skb);
return -EINVAL;
}
}
{
u32 __tmp = READY_TO_BEAM;
if (unlikely(nla_put(skb, NL80211_TESTMODE_P2P_SCANDONE_STATUS,
sizeof(u32), &__tmp) < 0)) {
kfree_skb(skb);
return -EINVAL;
}
}
i4Status = cfg80211_testmode_reply(skb);
#else
DBGLOG(QM, WARN, "CONFIG_NL80211_TESTMODE not enabled\n");
#endif
return i4Status;
}
#endif
#if CFG_SUPPORT_TDLS
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for changing a station information
*
* @param
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
#if KERNEL_VERSION(3, 16, 0) <= CFG80211_VERSION_CODE
int
mtk_cfg80211_change_station(struct wiphy *wiphy,
struct net_device *ndev, const u8 *mac,
struct station_parameters *params)
{
/* return 0; */
/* from supplicant -- wpa_supplicant_tdls_peer_addset() */
struct GLUE_INFO *prGlueInfo = NULL;
struct CMD_PEER_UPDATE rCmdUpdate;
uint32_t rStatus;
uint32_t u4BufLen, u4Temp;
struct ADAPTER *prAdapter;
struct BSS_INFO *prAisBssInfo;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
DBGLOG(REQ, INFO, "mtk_cfg80211_change_station\n");
/* make up command */
prAdapter = prGlueInfo->prAdapter;
prAisBssInfo = prAdapter->prAisBssInfo;
#if (CFG_ADVANCED_80211_MLO == 1)
if (params == NULL)
return 0;
else if (params->link_sta_params.supported_rates == NULL)
return 0;
#else
if (params == NULL)
return 0;
else if (params->supported_rates == NULL)
return 0;
#endif
/* init */
kalMemZero(&rCmdUpdate, sizeof(rCmdUpdate));
kalMemCopy(rCmdUpdate.aucPeerMac, mac, 6);
#if (CFG_ADVANCED_80211_MLO == 1)
if (params->link_sta_params.supported_rates != NULL) {
u4Temp = params->link_sta_params.supported_rates_len;
if (u4Temp > CMD_PEER_UPDATE_SUP_RATE_MAX)
u4Temp = CMD_PEER_UPDATE_SUP_RATE_MAX;
kalMemCopy(rCmdUpdate.aucSupRate,
params->link_sta_params.supported_rates,
u4Temp);
rCmdUpdate.u2SupRateLen = u4Temp;
}
#else
if (params->supported_rates != NULL) {
u4Temp = params->supported_rates_len;
if (u4Temp > CMD_PEER_UPDATE_SUP_RATE_MAX)
u4Temp = CMD_PEER_UPDATE_SUP_RATE_MAX;
kalMemCopy(rCmdUpdate.aucSupRate,
params->supported_rates,
u4Temp);
rCmdUpdate.u2SupRateLen = u4Temp;
}
#endif
/*
* In supplicant, only recognize WLAN_EID_QOS 46, not 0xDD WMM
* So force to support UAPSD here.
*/
rCmdUpdate.UapsdBitmap = 0x0F; /*params->uapsd_queues; */
rCmdUpdate.UapsdMaxSp = 0; /*params->max_sp; */
rCmdUpdate.u2Capability = params->capability;
if (params->ext_capab != NULL) {
u4Temp = params->ext_capab_len;
if (u4Temp > CMD_PEER_UPDATE_EXT_CAP_MAXLEN)
u4Temp = CMD_PEER_UPDATE_EXT_CAP_MAXLEN;
kalMemCopy(rCmdUpdate.aucExtCap, params->ext_capab, u4Temp);
rCmdUpdate.u2ExtCapLen = u4Temp;
}
#if (CFG_ADVANCED_80211_MLO == 1)
if (params->link_sta_params.ht_capa != NULL) {
rCmdUpdate.rHtCap.u2CapInfo =
params->link_sta_params.ht_capa->cap_info;
rCmdUpdate.rHtCap.ucAmpduParamsInfo =
params->link_sta_params.ht_capa->ampdu_params_info;
rCmdUpdate.rHtCap.u2ExtHtCapInfo =
params->link_sta_params.ht_capa->extended_ht_cap_info;
rCmdUpdate.rHtCap.u4TxBfCapInfo =
params->link_sta_params.ht_capa->tx_BF_cap_info;
rCmdUpdate.rHtCap.ucAntennaSelInfo =
params->link_sta_params.ht_capa->antenna_selection_info;
kalMemCopy(rCmdUpdate.rHtCap.rMCS.arRxMask,
params->link_sta_params.ht_capa->mcs.rx_mask,
sizeof(rCmdUpdate.rHtCap.rMCS.arRxMask));
rCmdUpdate.rHtCap.rMCS.u2RxHighest =
params->link_sta_params.ht_capa->mcs.rx_highest;
rCmdUpdate.rHtCap.rMCS.ucTxParams =
params->link_sta_params.ht_capa->mcs.tx_params;
rCmdUpdate.fgIsSupHt = TRUE;
}
/* vht */
if (params->link_sta_params.vht_capa != NULL) {
/* rCmdUpdate.rVHtCap */
/* rCmdUpdate.rVHtCap */
}
#else
if (params->ht_capa != NULL) {
rCmdUpdate.rHtCap.u2CapInfo =
params->ht_capa->cap_info;
rCmdUpdate.rHtCap.ucAmpduParamsInfo =
params->ht_capa->ampdu_params_info;
rCmdUpdate.rHtCap.u2ExtHtCapInfo =
params->ht_capa->extended_ht_cap_info;
rCmdUpdate.rHtCap.u4TxBfCapInfo =
params->ht_capa->tx_BF_cap_info;
rCmdUpdate.rHtCap.ucAntennaSelInfo =
params->ht_capa->antenna_selection_info;
kalMemCopy(rCmdUpdate.rHtCap.rMCS.arRxMask,
params->ht_capa->mcs.rx_mask,
sizeof(rCmdUpdate.rHtCap.rMCS.arRxMask));
rCmdUpdate.rHtCap.rMCS.u2RxHighest =
params->ht_capa->mcs.rx_highest;
rCmdUpdate.rHtCap.rMCS.ucTxParams =
params->ht_capa->mcs.tx_params;
rCmdUpdate.fgIsSupHt = TRUE;
}
/* vht */
if (params->vht_capa != NULL) {
/* rCmdUpdate.rVHtCap */
/* rCmdUpdate.rVHtCap */
}
#endif
/* update a TDLS peer record */
/* sanity check */
if ((params->sta_flags_set & BIT(
NL80211_STA_FLAG_TDLS_PEER)))
rCmdUpdate.eStaType = STA_TYPE_DLS_PEER;
rStatus = kalIoctl(prGlueInfo, cnmPeerUpdate, &rCmdUpdate,
sizeof(struct CMD_PEER_UPDATE), FALSE, FALSE, FALSE,
/* FALSE, //6628 -> 6630 fgIsP2pOid-> x */
&u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
return -EINVAL;
/* for Ch Sw AP prohibit case */
if (prAisBssInfo->fgTdlsIsChSwProhibited) {
/* disable TDLS ch sw function */
rStatus = kalIoctl(prGlueInfo,
TdlsSendChSwControlCmd,
&TdlsSendChSwControlCmd,
sizeof(struct CMD_TDLS_CH_SW),
FALSE, FALSE, FALSE,
/* FALSE, //6628 -> 6630 fgIsP2pOid-> x */
&u4BufLen);
}
return 0;
}
#else
int
mtk_cfg80211_change_station(struct wiphy *wiphy,
struct net_device *ndev, u8 *mac,
struct station_parameters *params)
{
/* return 0; */
/* from supplicant -- wpa_supplicant_tdls_peer_addset() */
struct GLUE_INFO *prGlueInfo = NULL;
struct CMD_PEER_UPDATE rCmdUpdate;
uint32_t rStatus;
uint32_t u4BufLen, u4Temp;
struct ADAPTER *prAdapter;
struct BSS_INFO *prAisBssInfo;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
DBGLOG(REQ, INFO, "mtk_cfg80211_change_station\n");
/* make up command */
prAdapter = prGlueInfo->prAdapter;
prAisBssInfo = prAdapter->prAisBssInfo;
if (params == NULL)
return 0;
else if (params->link_sta_params.supported_rates == NULL)
return 0;
/* init */
kalMemZero(&rCmdUpdate, sizeof(rCmdUpdate));
kalMemCopy(rCmdUpdate.aucPeerMac, mac, 6);
if (params->link_sta_params.supported_rates != NULL) {
u4Temp = params->link_sta_params.supported_rates_len;
if (u4Temp > CMD_PEER_UPDATE_SUP_RATE_MAX)
u4Temp = CMD_PEER_UPDATE_SUP_RATE_MAX;
kalMemCopy(rCmdUpdate.aucSupRate, params->link_sta_params.supported_rates,
u4Temp);
rCmdUpdate.u2SupRateLen = u4Temp;
}
/*
* In supplicant, only recognize WLAN_EID_QOS 46, not 0xDD WMM
* So force to support UAPSD here.
*/
rCmdUpdate.UapsdBitmap = 0x0F; /*params->uapsd_queues; */
rCmdUpdate.UapsdMaxSp = 0; /*params->max_sp; */
rCmdUpdate.u2Capability = params->capability;
if (params->ext_capab != NULL) {
u4Temp = params->ext_capab_len;
if (u4Temp > CMD_PEER_UPDATE_EXT_CAP_MAXLEN)
u4Temp = CMD_PEER_UPDATE_EXT_CAP_MAXLEN;
kalMemCopy(rCmdUpdate.aucExtCap, params->ext_capab, u4Temp);
rCmdUpdate.u2ExtCapLen = u4Temp;
}
if (params->link_sta_params.ht_capa != NULL) {
rCmdUpdate.rHtCap.u2CapInfo = params->link_sta_params.ht_capa->cap_info;
rCmdUpdate.rHtCap.ucAmpduParamsInfo =
params->link_sta_params.ht_capa->ampdu_params_info;
rCmdUpdate.rHtCap.u2ExtHtCapInfo =
params->link_sta_params.ht_capa->extended_ht_cap_info;
rCmdUpdate.rHtCap.u4TxBfCapInfo =
params->link_sta_params.ht_capa->tx_BF_cap_info;
rCmdUpdate.rHtCap.ucAntennaSelInfo =
params->link_sta_params.ht_capa->antenna_selection_info;
kalMemCopy(rCmdUpdate.rHtCap.rMCS.arRxMask,
params->link_sta_params.ht_capa->mcs.rx_mask,
sizeof(rCmdUpdate.rHtCap.rMCS.arRxMask));
rCmdUpdate.rHtCap.rMCS.u2RxHighest =
params->link_sta_params.ht_capa->mcs.rx_highest;
rCmdUpdate.rHtCap.rMCS.ucTxParams =
params->link_sta_params.ht_capa->mcs.tx_params;
rCmdUpdate.fgIsSupHt = TRUE;
}
/* vht */
if (params->link_sta_params.vht_capa != NULL) {
/* rCmdUpdate.rVHtCap */
/* rCmdUpdate.rVHtCap */
}
/* update a TDLS peer record */
/* sanity check */
if ((params->sta_flags_set & BIT(
NL80211_STA_FLAG_TDLS_PEER)))
rCmdUpdate.eStaType = STA_TYPE_DLS_PEER;
rStatus = kalIoctl(prGlueInfo, cnmPeerUpdate, &rCmdUpdate,
sizeof(struct CMD_PEER_UPDATE), FALSE, FALSE, FALSE,
/* FALSE, //6628 -> 6630 fgIsP2pOid-> x */
&u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
return -EINVAL;
/* for Ch Sw AP prohibit case */
if (prAisBssInfo->fgTdlsIsChSwProhibited) {
/* disable TDLS ch sw function */
rStatus = kalIoctl(prGlueInfo,
TdlsSendChSwControlCmd,
&TdlsSendChSwControlCmd,
sizeof(struct CMD_TDLS_CH_SW),
FALSE, FALSE, FALSE,
/* FALSE, //6628 -> 6630 fgIsP2pOid-> x */
&u4BufLen);
}
return 0;
}
#endif
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for adding a station information
*
* @param
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
#if KERNEL_VERSION(3, 16, 0) <= CFG80211_VERSION_CODE
int mtk_cfg80211_add_station(struct wiphy *wiphy,
struct net_device *ndev,
const u8 *mac, struct station_parameters *params)
{
/* return 0; */
/* from supplicant -- wpa_supplicant_tdls_peer_addset() */
struct GLUE_INFO *prGlueInfo = NULL;
struct CMD_PEER_ADD rCmdCreate;
struct ADAPTER *prAdapter;
uint32_t rStatus;
uint32_t u4BufLen;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
DBGLOG(REQ, INFO, "mtk_cfg80211_add_station\n");
/* make up command */
prAdapter = prGlueInfo->prAdapter;
/* init */
kalMemZero(&rCmdCreate, sizeof(rCmdCreate));
kalMemCopy(rCmdCreate.aucPeerMac, mac, 6);
/* create a TDLS peer record */
if ((params->sta_flags_set & BIT(
NL80211_STA_FLAG_TDLS_PEER))) {
rCmdCreate.eStaType = STA_TYPE_DLS_PEER;
rStatus = kalIoctl(prGlueInfo, cnmPeerAdd, &rCmdCreate,
sizeof(struct CMD_PEER_ADD),
FALSE, FALSE, FALSE,
/* FALSE, //6628 -> 6630 fgIsP2pOid-> x */
&u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
return -EINVAL;
}
return 0;
}
#else
int mtk_cfg80211_add_station(struct wiphy *wiphy,
struct net_device *ndev, u8 *mac,
struct station_parameters *params)
{
/* return 0; */
/* from supplicant -- wpa_supplicant_tdls_peer_addset() */
struct GLUE_INFO *prGlueInfo = NULL;
struct CMD_PEER_ADD rCmdCreate;
struct ADAPTER *prAdapter;
uint32_t rStatus;
uint32_t u4BufLen;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
DBGLOG(REQ, INFO, "mtk_cfg80211_add_station\n");
/* make up command */
prAdapter = prGlueInfo->prAdapter;
/* init */
kalMemZero(&rCmdCreate, sizeof(rCmdCreate));
kalMemCopy(rCmdCreate.aucPeerMac, mac, 6);
/* create a TDLS peer record */
if ((params->sta_flags_set & BIT(
NL80211_STA_FLAG_TDLS_PEER))) {
rCmdCreate.eStaType = STA_TYPE_DLS_PEER;
rStatus = kalIoctl(prGlueInfo, cnmPeerAdd, &rCmdCreate,
sizeof(struct CMD_PEER_ADD),
FALSE, FALSE, FALSE,
/* FALSE, //6628 -> 6630 fgIsP2pOid-> x */
&u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
return -EINVAL;
}
return 0;
}
#endif
/*----------------------------------------------------------------------------*/
/*!
* @brief This routine is responsible for deleting a station information
*
* @param
*
* @retval 0: successful
* others: failure
*
* @other
* must implement if you have add_station().
*/
/*----------------------------------------------------------------------------*/
#if KERNEL_VERSION(3, 16, 0) <= CFG80211_VERSION_CODE
#if KERNEL_VERSION(3, 19, 0) <= CFG80211_VERSION_CODE
static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
int mtk_cfg80211_del_station(struct wiphy *wiphy,
struct net_device *ndev,
struct station_del_parameters *params)
{
/* fgIsTDLSlinkEnable = 0; */
/* return 0; */
/* from supplicant -- wpa_supplicant_tdls_peer_addset() */
const u8 *mac = params->mac ? params->mac : bcast_addr;
struct GLUE_INFO *prGlueInfo = NULL;
struct ADAPTER *prAdapter;
struct STA_RECORD *prStaRec;
u8 deleteMac[MAC_ADDR_LEN];
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
DBGLOG(REQ, INFO, "mtk_cfg80211_del_station\n");
prAdapter = prGlueInfo->prAdapter;
/* For kernel 3.18 modification, we trasfer to local buff to query
* sta
*/
memset(deleteMac, 0, MAC_ADDR_LEN);
memcpy(deleteMac, mac, MAC_ADDR_LEN);
prStaRec = cnmGetStaRecByAddress(prAdapter,
(uint8_t) prAdapter->prAisBssInfo->ucBssIndex, deleteMac);
if (prStaRec != NULL)
cnmStaRecFree(prAdapter, prStaRec);
return 0;
}
#else
int mtk_cfg80211_del_station(struct wiphy *wiphy,
struct net_device *ndev, const u8 *mac)
{
/* fgIsTDLSlinkEnable = 0; */
/* return 0; */
/* from supplicant -- wpa_supplicant_tdls_peer_addset() */
struct GLUE_INFO *prGlueInfo = NULL;
struct ADAPTER *prAdapter;
struct STA_RECORD *prStaRec;
u8 deleteMac[MAC_ADDR_LEN];
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
DBGLOG(REQ, INFO, "mtk_cfg80211_del_station\n");
prAdapter = prGlueInfo->prAdapter;
/* For kernel 3.18 modification, we trasfer to local buff to query
* sta
*/
memset(deleteMac, 0, MAC_ADDR_LEN);
memcpy(deleteMac, mac, MAC_ADDR_LEN);
prStaRec = cnmGetStaRecByAddress(prAdapter,
(uint8_t) prAdapter->prAisBssInfo->ucBssIndex, deleteMac);
if (prStaRec != NULL)
cnmStaRecFree(prAdapter, prStaRec);
return 0;
}
#endif
#else
int mtk_cfg80211_del_station(struct wiphy *wiphy,
struct net_device *ndev, u8 *mac)
{
/* fgIsTDLSlinkEnable = 0; */
/* return 0; */
/* from supplicant -- wpa_supplicant_tdls_peer_addset() */
struct GLUE_INFO *prGlueInfo = NULL;
struct ADAPTER *prAdapter;
struct STA_RECORD *prStaRec;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
DBGLOG(REQ, INFO, "mtk_cfg80211_del_station\n");
prAdapter = prGlueInfo->prAdapter;
prStaRec = cnmGetStaRecByAddress(prAdapter,
(uint8_t) prAdapter->prAisBssInfo->ucBssIndex, mac);
if (prStaRec != NULL)
cnmStaRecFree(prAdapter, prStaRec);
return 0;
}
#endif
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is called to transmit a TDLS data frame 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
*/
/*----------------------------------------------------------------------------*/
#if KERNEL_VERSION(3, 18, 0) <= CFG80211_VERSION_CODE
int
mtk_cfg80211_tdls_mgmt(struct wiphy *wiphy,
struct net_device *dev,
const u8 *peer, u8 action_code, u8 dialog_token,
u16 status_code, u32 peer_capability,
bool initiator, const u8 *buf, size_t len)
{
struct GLUE_INFO *prGlueInfo;
struct TDLS_CMD_LINK_MGT rCmdMgt;
uint32_t u4BufLen;
DBGLOG(REQ, INFO, "mtk_cfg80211_tdls_mgmt\n");
/* sanity check */
if ((wiphy == NULL) || (peer == NULL) || (buf == NULL))
return -EINVAL;
/* init */
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (prGlueInfo == NULL)
return -EINVAL;
kalMemZero(&rCmdMgt, sizeof(rCmdMgt));
rCmdMgt.u2StatusCode = status_code;
rCmdMgt.u4SecBufLen = len;
rCmdMgt.ucDialogToken = dialog_token;
rCmdMgt.ucActionCode = action_code;
kalMemCopy(&(rCmdMgt.aucPeer), peer, 6);
if (len > TDLS_SEC_BUF_LENGTH) {
DBGLOG(REQ, WARN, "%s:len > TDLS_SEC_BUF_LENGTH\n", __func__);
return -EINVAL;
}
kalMemCopy(&(rCmdMgt.aucSecBuf), buf, len);
kalIoctl(prGlueInfo, TdlsexLinkMgt, &rCmdMgt,
sizeof(struct TDLS_CMD_LINK_MGT), FALSE, FALSE, FALSE,
/* FALSE, //6628 -> 6630 fgIsP2pOid-> x */
&u4BufLen);
return 0;
}
#elif KERNEL_VERSION(3, 16, 0) <= CFG80211_VERSION_CODE
int
mtk_cfg80211_tdls_mgmt(struct wiphy *wiphy,
struct net_device *dev,
const u8 *peer, u8 action_code, u8 dialog_token,
u16 status_code, u32 peer_capability,
const u8 *buf, size_t len)
{
struct GLUE_INFO *prGlueInfo;
struct TDLS_CMD_LINK_MGT rCmdMgt;
uint32_t u4BufLen;
DBGLOG(REQ, INFO, "mtk_cfg80211_tdls_mgmt\n");
/* sanity check */
if ((wiphy == NULL) || (peer == NULL) || (buf == NULL))
return -EINVAL;
/* init */
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (prGlueInfo == NULL)
return -EINVAL;
kalMemZero(&rCmdMgt, sizeof(rCmdMgt));
rCmdMgt.u2StatusCode = status_code;
rCmdMgt.u4SecBufLen = len;
rCmdMgt.ucDialogToken = dialog_token;
rCmdMgt.ucActionCode = action_code;
kalMemCopy(&(rCmdMgt.aucPeer), peer, 6);
if (len > TDLS_SEC_BUF_LENGTH) {
DBGLOG(REQ, WARN, "%s:len > TDLS_SEC_BUF_LENGTH\n", __func__);
return -EINVAL;
}
kalMemCopy(&(rCmdMgt.aucSecBuf), buf, len);
kalIoctl(prGlueInfo, TdlsexLinkMgt, &rCmdMgt,
sizeof(struct TDLS_CMD_LINK_MGT), FALSE, FALSE, FALSE,
/* FALSE, //6628 -> 6630 fgIsP2pOid-> x */
&u4BufLen);
return 0;
}
#else
int
mtk_cfg80211_tdls_mgmt(struct wiphy *wiphy,
struct net_device *dev,
u8 *peer, u8 action_code, u8 dialog_token,
u16 status_code, const u8 *buf, size_t len)
{
struct GLUE_INFO *prGlueInfo;
struct TDLS_CMD_LINK_MGT rCmdMgt;
uint32_t u4BufLen;
DBGLOG(REQ, INFO, "mtk_cfg80211_tdls_mgmt\n");
/* sanity check */
if ((wiphy == NULL) || (peer == NULL) || (buf == NULL))
return -EINVAL;
/* init */
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (prGlueInfo == NULL)
return -EINVAL;
kalMemZero(&rCmdMgt, sizeof(rCmdMgt));
rCmdMgt.u2StatusCode = status_code;
rCmdMgt.u4SecBufLen = len;
rCmdMgt.ucDialogToken = dialog_token;
rCmdMgt.ucActionCode = action_code;
kalMemCopy(&(rCmdMgt.aucPeer), peer, 6);
if (len > TDLS_SEC_BUF_LENGTH) {
DBGLOG(REQ, WARN,
"In mtk_cfg80211_tdls_mgmt , len > TDLS_SEC_BUF_LENGTH, please check\n");
return -EINVAL;
}
kalMemCopy(&(rCmdMgt.aucSecBuf), buf, len);
kalIoctl(prGlueInfo, TdlsexLinkMgt, &rCmdMgt,
sizeof(struct TDLS_CMD_LINK_MGT), FALSE, FALSE, FALSE,
/* FALSE, //6628 -> 6630 fgIsP2pOid-> x */
&u4BufLen);
return 0;
}
#endif
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is called to hadel TDLS link 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
*/
/*----------------------------------------------------------------------------*/
#if KERNEL_VERSION(3, 16, 0) <= CFG80211_VERSION_CODE
int mtk_cfg80211_tdls_oper(struct wiphy *wiphy,
struct net_device *dev,
const u8 *peer, enum nl80211_tdls_operation oper)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint32_t u4BufLen;
struct ADAPTER *prAdapter;
struct TDLS_CMD_LINK_OPER rCmdOper;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
DBGLOG(REQ, INFO, "mtk_cfg80211_tdls_oper\n");
ASSERT(prGlueInfo);
prAdapter = prGlueInfo->prAdapter;
kalMemZero(&rCmdOper, sizeof(rCmdOper));
kalMemCopy(rCmdOper.aucPeerMac, peer, 6);
rCmdOper.oper = (enum ENUM_TDLS_LINK_OPER)oper;
if (oper == NL80211_TDLS_DISABLE_LINK) {
/* [ALPS03767042] wlan: fix TDLS 5.3 test issue
* [Detail]
* Timing issue of data direct path design
* - Data sent directly through HW (new design in 6765)
* - Command sent to FW to process (original design)
* Issue occurs while
* - Tear down packet sent by wlanHardStartXmit(),
* but not real sent out
* - CMD_ID_REMOVE_STA_RECORD sent to FW to disable TDLS link
* [Solution]
* Short-term
* - Delay TDLS disable link to let tear down data package
* to send
* Long-term
* - Enhance the TDLS flow to guarantee TX can send out
* successfully
*/
DBGLOG(TDLS, INFO, "NL80211_TDLS_DISABLE_LINK, kalMsleep(20)");
kalMsleep(20);
}
kalIoctl(prGlueInfo, TdlsexLinkOper, &rCmdOper,
sizeof(struct TDLS_CMD_LINK_OPER), FALSE, FALSE, FALSE,
&u4BufLen);
return 0;
}
#else
int mtk_cfg80211_tdls_oper(struct wiphy *wiphy,
struct net_device *dev, u8 *peer,
enum nl80211_tdls_operation oper)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint32_t u4BufLen;
struct ADAPTER *prAdapter;
struct TDLS_CMD_LINK_OPER rCmdOper;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
DBGLOG(REQ, INFO, "mtk_cfg80211_tdls_oper\n");
prAdapter = prGlueInfo->prAdapter;
kalMemZero(&rCmdOper, sizeof(rCmdOper));
kalMemCopy(rCmdOper.aucPeerMac, peer, 6);
rCmdOper.oper = oper;
if (oper == NL80211_TDLS_DISABLE_LINK) {
/* [ALPS03767042] wlan: fix TDLS 5.3 test issue
* [Detail]
* Timing issue of data direct path design
* - Data sent directly through HW (new design in 6765)
* - Command sent to FW to process (original design)
* Issue occurs while
* - Tear down packet sent by wlanHardStartXmit(),
* but not real sent out
* - CMD_ID_REMOVE_STA_RECORD sent to FW to disable TDLS link
* [Solution]
* Short-term
* - Delay TDLS disable link to let tear down data package
* to send
* Long-term
* - Enhance the TDLS flow to guarantee TX can send out
* successfully
*/
DBGLOG(TDLS, INFO, "NL80211_TDLS_DISABLE_LINK, kalMsleep(20)");
kalMsleep(20);
}
kalIoctl(prGlueInfo, TdlsexLinkOper, &rCmdOper,
sizeof(struct TDLS_CMD_LINK_OPER), FALSE, FALSE, FALSE,
&u4BufLen);
return 0;
}
#endif
#endif
int32_t mtk_cfg80211_process_str_cmd(struct GLUE_INFO
*prGlueInfo, uint8_t *cmd, int32_t len)
{
uint32_t rStatus = WLAN_STATUS_SUCCESS;
uint32_t u4SetInfoLen = 0;
if (cmd == NULL || len == 0) {
DBGLOG(INIT, TRACE, "%s cmd or len is invalid\n", __func__);
return -EINVAL;
}
/* data is a null-terminated string, len also count null character */
if (strlen(cmd) == 9 &&
strnicmp(cmd, "tdls-ps ", 8) == 0) {
#if CFG_SUPPORT_TDLS
rStatus = kalIoctl(prGlueInfo,
wlanoidDisableTdlsPs,
(void *)(cmd + 8), 1,
FALSE, FALSE, TRUE, &u4SetInfoLen);
#else
DBGLOG(REQ, WARN, "not support tdls\n");
return -EOPNOTSUPP;
#endif
} else if (strncasecmp(cmd, "NEIGHBOR-REQUEST", 16) == 0) {
uint8_t *pucSSID = NULL;
uint32_t u4SSIDLen = 0;
if (strlen(cmd) > 22 &&
(strncasecmp(cmd+16, " SSID=", 6) == 0)) {
pucSSID = cmd + 22;
u4SSIDLen = len - 22;
DBGLOG(REQ, INFO, "cmd=%s, ssid len %u, ssid=%s\n", cmd,
u4SSIDLen, pucSSID);
}
rStatus = kalIoctl(prGlueInfo, wlanoidSendNeighborRequest,
(void *)pucSSID, u4SSIDLen, FALSE, FALSE,
TRUE, &u4SetInfoLen);
} else if (strncasecmp(cmd, "BSS-TRANSITION-QUERY", 20) == 0) {
uint8_t *pucReason = NULL;
if (strlen(cmd) > 28 &&
(strncasecmp(cmd+20, " reason=", 8) == 0))
pucReason = cmd + 28;
rStatus = kalIoctl(prGlueInfo, wlanoidSendBTMQuery,
(void *)pucReason, 1, FALSE, FALSE, TRUE,
&u4SetInfoLen);
} else if (strlen(cmd) == 11 &&
strnicmp(cmd, "OSHAREMOD ", 10) == 0) {
#if CFG_SUPPORT_OSHARE
struct OSHARE_MODE_T cmdBuf;
struct OSHARE_MODE_T *pCmdHeader = NULL;
struct OSHARE_MODE_SETTING_V1_T *pCmdData = NULL;
kalMemZero(&cmdBuf, sizeof(cmdBuf));
pCmdHeader = &cmdBuf;
pCmdHeader->cmdVersion = OSHARE_MODE_CMD_V1;
pCmdHeader->cmdType = 1; /*1-set 0-query*/
pCmdHeader->magicCode = OSHARE_MODE_MAGIC_CODE;
pCmdHeader->cmdBufferLen = MAX_OSHARE_MODE_LENGTH;
pCmdData = (struct OSHARE_MODE_SETTING_V1_T *) &
(pCmdHeader->buffer[0]);
pCmdData->osharemode = *(uint8_t *)(cmd + 10) - '0';
DBGLOG(REQ, INFO, "cmd=%s, osharemode=%u\n", cmd,
pCmdData->osharemode);
rStatus = kalIoctl(prGlueInfo,
wlanoidSetOshareMode,
&cmdBuf,
sizeof(struct OSHARE_MODE_T),
FALSE,
FALSE,
TRUE,
&u4SetInfoLen);
if (rStatus == WLAN_STATUS_SUCCESS)
prGlueInfo->prAdapter->fgEnOshareMode
= pCmdData->osharemode;
#else
DBGLOG(REQ, WARN, "not support OSHAREMOD\n");
return -EOPNOTSUPP;
#endif
} else
return -EOPNOTSUPP;
if (rStatus == WLAN_STATUS_SUCCESS)
return 0;
return -EINVAL;
}
#if (CFG_SUPPORT_SINGLE_SKU == 1)
#if (CFG_BUILT_IN_DRIVER == 1)
/* in kernel-x.x/net/wireless/reg.c */
#else
bool is_world_regdom(const char *alpha2)
{
if (!alpha2)
return false;
return (alpha2[0] == '0') && (alpha2[1] == '0');
}
#endif
enum regd_state regd_state_machine(IN struct regulatory_request *pRequest)
{
switch (pRequest->initiator) {
case NL80211_REGDOM_SET_BY_USER:
DBGLOG(RLM, INFO, "regd_state_machine: SET_BY_USER\n");
return rlmDomainStateTransition(REGD_STATE_SET_COUNTRY_USER,
pRequest);
case NL80211_REGDOM_SET_BY_DRIVER:
DBGLOG(RLM, INFO, "regd_state_machine: SET_BY_DRIVER\n");
return rlmDomainStateTransition(
REGD_STATE_SET_COUNTRY_DRIVER, pRequest);
case NL80211_REGDOM_SET_BY_CORE:
DBGLOG(RLM, INFO,
"regd_state_machine: NL80211_REGDOM_SET_BY_CORE\n");
return rlmDomainStateTransition(REGD_STATE_SET_WW_CORE,
pRequest);
case NL80211_REGDOM_SET_BY_COUNTRY_IE:
DBGLOG(RLM, WARN,
"============== WARNING ==============\n");
DBGLOG(RLM, WARN,
"regd_state_machine: SET_BY_COUNTRY_IE\n");
DBGLOG(RLM, WARN, "Regulatory rule is updated by IE.\n");
DBGLOG(RLM, WARN,
"============== WARNING ==============\n");
return rlmDomainStateTransition(REGD_STATE_SET_COUNTRY_IE,
pRequest);
default:
return rlmDomainStateTransition(REGD_STATE_INVALID,
pRequest);
}
}
void
mtk_apply_custom_regulatory(IN struct wiphy *pWiphy,
IN const struct ieee80211_regdomain *pRegdom)
{
u32 band_idx, ch_idx;
struct ieee80211_supported_band *sband;
struct ieee80211_channel *chan;
DBGLOG(RLM, INFO, "%s()\n", __func__);
/* to reset cha->flags*/
for (band_idx = 0; band_idx < KAL_NUM_BANDS; band_idx++) {
sband = pWiphy->bands[band_idx];
if (!sband)
continue;
for (ch_idx = 0; ch_idx < sband->n_channels; ch_idx++) {
chan = &sband->channels[ch_idx];
/*reset chan->flags*/
chan->flags = 0;
}
}
/* update to kernel */
wiphy_apply_custom_regulatory(pWiphy, pRegdom);
#if KERNEL_VERSION(4, 3, 0) <= CFG80211_VERSION_CODE
/*Fix Kernel 4.3 and later bug for parser domain info*/
for (band_idx = 0; band_idx < KAL_NUM_BANDS; band_idx++) {
sband = pWiphy->bands[band_idx];
if (!sband)
continue;
for (ch_idx = 0; ch_idx < sband->n_channels; ch_idx++) {
chan = &sband->channels[ch_idx];
if (chan->flags & IEEE80211_CHAN_NO_20MHZ)
chan->flags |= IEEE80211_CHAN_DISABLED;
}
}
#endif
}
void mtk_reg_notify_work(IN struct wiphy *pWiphy,
IN struct regulatory_request *pRequest)
{
#if (CFG_SUPPORT_CFG80211_AUTH == 1 && CFG_SUPPORT_CFG80211_QUEUE == 1 && \
CFG_SUPPORT_SINGLE_SKU_LOCAL_DB == 1)
rlmDomainRegSetAddToQueue(pWiphy, pRequest);
#else
mtk_reg_notify(pWiphy, pRequest);
#endif
}
void
mtk_reg_notify(IN struct wiphy *pWiphy,
IN struct regulatory_request *pRequest)
{
struct GLUE_INFO *prGlueInfo;
struct ADAPTER *prAdapter;
enum regd_state old_state;
if (g_u4HaltFlag) {
DBGLOG(RLM, WARN, "wlan is halt, skip reg callback\n");
return;
}
if (!pWiphy) {
DBGLOG(RLM, ERROR, "pWiphy = NULL!\n");
return;
}
/*
* Awlays use wlan0's base wiphy pointer to update reg notifier.
* Because only one reg state machine is handled.
*/
if (gprWdev && (pWiphy != gprWdev->wiphy)) {
pWiphy = gprWdev->wiphy;
DBGLOG(RLM, ERROR, "Use base wiphy to update (p=%p)\n",
gprWdev->wiphy);
}
old_state = rlmDomainGetCtrlState();
/*
* Magic flow for driver to send inband command after kernel's calling
* reg_notifier callback
*/
if (!pRequest) {
/*triggered by our driver in wlan initial process.*/
if (old_state == REGD_STATE_INIT) {
if (rlmDomainIsUsingLocalRegDomainDataBase()) {
DBGLOG(RLM, WARN,
"County Code is not assigned. Use default WW.\n");
goto DOMAIN_SEND_CMD;
} else {
DBGLOG(RLM, ERROR,
"Invalid REG state happened. state = 0x%x\n",
old_state);
return;
}
} else if ((old_state == REGD_STATE_SET_WW_CORE) ||
(old_state == REGD_STATE_SET_COUNTRY_USER) ||
(old_state == REGD_STATE_SET_COUNTRY_DRIVER)) {
goto DOMAIN_SEND_CMD;
} else {
DBGLOG(RLM, ERROR,
"Invalid REG state happened. state = 0x%x\n",
old_state);
return;
}
}
/*
* Ignore the CORE's WW setting when using local data base of regulatory
* rules
*/
if ((pRequest->initiator == NL80211_REGDOM_SET_BY_CORE) &&
#if KERNEL_VERSION(3, 14, 0) > CFG80211_VERSION_CODE
(pWiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY))
#else
(pWiphy->regulatory_flags & REGULATORY_CUSTOM_REG))
#endif
return;/*Ignore the CORE's WW setting*/
prGlueInfo = rlmDomainGetGlueInfo();
if (!prGlueInfo) {
DBGLOG(RLM, ERROR, "prGlueInfo is NULL!\n");
} else {
prAdapter = prGlueInfo->prAdapter;
/*
* Ignore the CORE's WW setting when had been set other path,
* or will be covered
*/
if (prAdapter && prAdapter->rWifiVar.ucDisMixRegionSetup) {
if ((pRequest->initiator == NL80211_REGDOM_SET_BY_CORE) &&
((old_state == REGD_STATE_SET_COUNTRY_DRIVER) ||
(old_state == REGD_STATE_SET_COUNTRY_USER))) {
DBGLOG(RLM, ERROR,
"Mixed region cfg, direct return\n");
return;/*Ignore Mix region setting*/
}
}
}
/*
* State machine transition
*/
DBGLOG(RLM, INFO,
"request->alpha2=%s, initiator=%x, intersect=%d\n",
pRequest->alpha2, pRequest->initiator, pRequest->intersect);
regd_state_machine(pRequest);
if (rlmDomainGetCtrlState() == old_state) {
if (((old_state == REGD_STATE_SET_COUNTRY_USER)
|| (old_state == REGD_STATE_SET_COUNTRY_DRIVER))
&& (!(rlmDomainIsSameCountryCode(pRequest->alpha2,
sizeof(pRequest->alpha2)))))
DBGLOG(RLM, INFO, "Set by user to NEW country code\n");
else
/* Change to same state or same country, ignore */
return;
} else if (rlmDomainIsCtrlStateEqualTo(REGD_STATE_INVALID)) {
DBGLOG(RLM, ERROR,
"\n%s():\n---> WARNING. Transit to invalid state.\n",
__func__);
DBGLOG(RLM, ERROR, "---> WARNING.\n ");
rlmDomainAssert(0);
}
/*
* Set country code
*/
if (pRequest->initiator != NL80211_REGDOM_SET_BY_DRIVER) {
rlmDomainSetCountryCode(pRequest->alpha2,
sizeof(pRequest->alpha2));
} else {
/*SET_BY_DRIVER*/
if (rlmDomainIsEfuseUsed()) {
if (!rlmDomainIsUsingLocalRegDomainDataBase())
DBGLOG(RLM, WARN,
"[WARNING!!!] Local DB must be used if country code from efuse.\n");
} else {
/* iwpriv case */
if (rlmDomainIsUsingLocalRegDomainDataBase() &&
(!rlmDomainIsEfuseUsed())) {
/*iwpriv set country but local data base*/
u32 country_code =
rlmDomainGetTempCountryCode();
rlmDomainSetCountryCode((char *)&country_code,
sizeof(country_code));
} else {
/*iwpriv set country but query CRDA*/
rlmDomainSetCountryCode(pRequest->alpha2,
sizeof(pRequest->alpha2));
}
}
}
rlmDomainSetDfsRegion(pRequest->dfs_region);
DOMAIN_SEND_CMD:
DBGLOG(RLM, INFO, "g_mtk_regd_control.alpha2 = 0x%x\n",
rlmDomainGetCountryCode());
/*
* Check if using customized regulatory rule
*/
if (rlmDomainIsUsingLocalRegDomainDataBase()) {
const struct ieee80211_regdomain *pRegdom;
u32 country_code = rlmDomainGetCountryCode();
char alpha2[4];
/*fetch regulatory rules from local data base*/
alpha2[0] = country_code & 0xFF;
alpha2[1] = (country_code >> 8) & 0xFF;
alpha2[2] = (country_code >> 16) & 0xFF;
alpha2[3] = (country_code >> 24) & 0xFF;
pRegdom = rlmDomainSearchRegdomainFromLocalDataBase(alpha2);
if (!pRegdom) {
DBGLOG(RLM, ERROR,
"%s(): Error, Cannot find the correct RegDomain. country = %u\n",
__func__, rlmDomainGetCountryCode());
rlmDomainAssert(0);
return;
}
mtk_apply_custom_regulatory(pWiphy, pRegdom);
}
/*
* Parsing channels
*/
rlmDomainParsingChannel(pWiphy); /*real regd update*/
/*
* Check if firmawre support single sku.
* no need to send information to FW due to FW is not supported.
*/
if (!regd_is_single_sku_en())
return;
/*
* Always use the wlan GlueInfo as parameter.
*/
prGlueInfo = rlmDomainGetGlueInfo();
if (!prGlueInfo) {
DBGLOG(RLM, ERROR, "prGlueInfo is NULL!\n");
return; /*interface is not up yet.*/
}
prAdapter = prGlueInfo->prAdapter;
if (!prAdapter) {
DBGLOG(RLM, ERROR, "prAdapter is NULL!\n");
return; /*interface is not up yet.*/
}
if (test_bit(SUSPEND_FLAG_CLEAR_WHEN_RESUME,
&prAdapter->ulSuspendFlag)) {
DBGLOG(RLM, STATE,
"[%s] Suspend is ongoing\n", __func__);
return;
}
/*
* Send commands to firmware
*/
prAdapter->rWifiVar.rConnSettings.u2CountryCode =
(uint16_t)rlmDomainGetCountryCode();
rlmDomainSendCmd(prAdapter);
}
void
cfg80211_regd_set_wiphy(IN struct wiphy *prWiphy)
{
#if (CFG_SUPPORT_SINGLE_SKU_LOCAL_DB == 1)
#if KERNEL_VERSION(4, 3, 0) <= CFG80211_VERSION_CODE
u32 band_idx, ch_idx;
struct ieee80211_supported_band *sband;
struct ieee80211_channel *chan;
#endif
#endif
/*
* register callback
*/
prWiphy->reg_notifier = mtk_reg_notify_work;
/*
* clear REGULATORY_CUSTOM_REG flag
*/
#if KERNEL_VERSION(3, 14, 0) > CFG80211_VERSION_CODE
/*tells kernel that assign WW as default*/
prWiphy->flags &= ~(WIPHY_FLAG_CUSTOM_REGULATORY);
#else
prWiphy->regulatory_flags &= ~(REGULATORY_CUSTOM_REG);
/*ignore the hint from IE*/
prWiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE;
#ifdef CFG_SUPPORT_DISABLE_BCN_HINTS
/*disable beacon hint to avoid channel flag be changed*/
prWiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS;
#endif
#endif
/*
* set REGULATORY_CUSTOM_REG flag
*/
#if (CFG_SUPPORT_SINGLE_SKU_LOCAL_DB == 1)
#if KERNEL_VERSION(3, 14, 0) > CFG80211_VERSION_CODE
/*tells kernel that assign WW as default*/
prWiphy->flags |= (WIPHY_FLAG_CUSTOM_REGULATORY);
#else
prWiphy->regulatory_flags |= (REGULATORY_CUSTOM_REG);
#endif
/* assigned a defautl one */
if (rlmDomainGetLocalDefaultRegd()) {
wiphy_apply_custom_regulatory(prWiphy,
rlmDomainGetLocalDefaultRegd());
#if KERNEL_VERSION(4, 3, 0) <= CFG80211_VERSION_CODE
/*Fix Kernel 4.3 and later bug for parser domain info*/
for (band_idx = 0; band_idx < KAL_NUM_BANDS; band_idx++) {
sband = prWiphy->bands[band_idx];
if (!sband)
continue;
for (ch_idx = 0; ch_idx < sband->n_channels; ch_idx++) {
chan = &sband->channels[ch_idx];
if (chan->flags & IEEE80211_CHAN_NO_20MHZ)
chan->flags |= IEEE80211_CHAN_DISABLED;
}
}
#endif
}
#endif
/*
* Initialize regd control information
*/
rlmDomainResetCtrlInfo(FALSE);
}
#else
void
cfg80211_regd_set_wiphy(IN struct wiphy *prWiphy)
{
}
#endif
int mtk_cfg80211_suspend(struct wiphy *wiphy,
struct cfg80211_wowlan *wow)
{
struct GLUE_INFO *prGlueInfo = NULL;
DBGLOG(REQ, STATE, "mtk_cfg80211_suspend\n");
if (!wiphy)
return 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!prGlueInfo)
return 0;
#if !CFG_ENABLE_WAKE_LOCK
/* AIS flow: disassociation if wow_en=0 */
/* cancel scan report done event */
aisPreSuspendFlow(prGlueInfo);
/* In current design, only support AIS connection during suspend only.
* It need to add flow to deactive P2P (GC/GO) link during suspend flow.
* Otherwise, MT7668 would fail to enter deep sleep.
*/
p2pProcessPreSuspendFlow(prGlueInfo->prAdapter);
#endif
if (kalHaltTryLock())
return 0;
if (kalIsHalted() || !wiphy)
goto end;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (prGlueInfo && prGlueInfo->prAdapter) {
set_bit(SUSPEND_FLAG_FOR_WAKEUP_REASON,
&prGlueInfo->prAdapter->ulSuspendFlag);
set_bit(SUSPEND_FLAG_CLEAR_WHEN_RESUME,
&prGlueInfo->prAdapter->ulSuspendFlag);
}
end:
kalHaltUnlock();
return 0;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief cfg80211 resume callback, will be invoked in wiphy_resume.
*
* @param wiphy: pointer to wiphy
*
* @retval 0: successful
* others: failure
*/
/*----------------------------------------------------------------------------*/
int mtk_cfg80211_resume(struct wiphy *wiphy)
{
struct GLUE_INFO *prGlueInfo = NULL;
struct BSS_DESC **pprBssDesc = NULL;
struct ADAPTER *prAdapter = NULL;
uint8_t i = 0;
DBGLOG(REQ, STATE, "mtk_cfg80211_resume\n");
if (kalHaltTryLock())
return 0;
if (kalIsHalted() || !wiphy)
goto end;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (prGlueInfo)
prAdapter = prGlueInfo->prAdapter;
if (prAdapter == NULL)
goto end;
clear_bit(SUSPEND_FLAG_CLEAR_WHEN_RESUME,
&prAdapter->ulSuspendFlag);
pprBssDesc = &prAdapter->rWifiVar.rScanInfo.rSchedScanParam.
aprPendingBssDescToInd[0];
for (; i < SCN_SSID_MATCH_MAX_NUM; i++) {
if (pprBssDesc[i] == NULL)
break;
if (pprBssDesc[i]->u2RawLength == 0)
continue;
kalIndicateBssInfo(prGlueInfo,
(uint8_t *) pprBssDesc[i]->aucRawBuf,
pprBssDesc[i]->u2RawLength,
pprBssDesc[i]->ucChannelNum,
RCPI_TO_dBm(pprBssDesc[i]->ucRCPI));
}
DBGLOG(SCN, INFO, "pending %d sched scan results\n", i);
if (i > 0)
kalMemZero(&pprBssDesc[0], i * sizeof(struct BSS_DESC *));
end:
kalHaltUnlock();
return 0;
}
#if CFG_ENABLE_UNIFY_WIPHY
/*----------------------------------------------------------------------------*/
/*!
* @brief Check the net device is P2P net device (P2P GO/GC, AP), or not.
*
* @param prGlueInfo : the driver private data
* ndev : the net device
*
* @retval 0: AIS device (STA/IBSS)
* 1: P2P GO/GC, AP
*/
/*----------------------------------------------------------------------------*/
int mtk_IsP2PNetDevice(struct GLUE_INFO *prGlueInfo,
struct net_device *ndev)
{
struct NETDEV_PRIVATE_GLUE_INFO *prNetDevPrivate = NULL;
int iftype = 0;
int ret = 1;
if (ndev == NULL) {
DBGLOG(REQ, WARN, "ndev is NULL\n");
return -1;
}
prNetDevPrivate = (struct NETDEV_PRIVATE_GLUE_INFO *)
netdev_priv(ndev);
iftype = ndev->ieee80211_ptr->iftype;
/* P2P device/GO/GC always return 1 */
if (prNetDevPrivate->ucIsP2p == TRUE)
ret = 1;
else if (iftype == NL80211_IFTYPE_STATION)
ret = 0;
else if (iftype == NL80211_IFTYPE_ADHOC)
ret = 0;
DBGLOG(REQ, LOUD,
"ucIsP2p = %d\n",
ret);
return ret;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief Initialize the AIS related FSM and data.
*
* @param prGlueInfo : the driver private data
* ndev : the net device
* ucBssIdx : the AIS BSS index adssigned by the driver (wlanProbe)
*
* @retval 0
*
*/
/*----------------------------------------------------------------------------*/
int mtk_init_sta_role(struct ADAPTER *prAdapter,
struct net_device *ndev)
{
struct NETDEV_PRIVATE_GLUE_INFO *prNdevPriv = NULL;
if ((prAdapter == NULL) || (ndev == NULL))
return -1;
/* init AIS FSM */
aisFsmInit(prAdapter);
aisInitializeConnectionSettings(prAdapter, NULL);
#if CFG_SUPPORT_ROAMING
/* Roaming Module - intiailization */
roamingFsmInit(prAdapter);
#endif /* CFG_SUPPORT_ROAMING */
ndev->netdev_ops = wlanGetNdevOps();
ndev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
COPY_MAC_ADDR(ndev->dev_addr, prAdapter->rMyMacAddr);
/* set the ndev's ucBssIdx to the AIS BSS index */
prNdevPriv = (struct NETDEV_PRIVATE_GLUE_INFO *)
netdev_priv(ndev);
prNdevPriv->ucBssIdx = prAdapter->prAisBssInfo->ucBssIndex;
return 0;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief Uninitialize the AIS related FSM and data.
*
* @param prAdapter : the driver private data
*
* @retval 0
*
*/
/*----------------------------------------------------------------------------*/
int mtk_uninit_sta_role(struct ADAPTER *prAdapter,
struct net_device *ndev)
{
struct NETDEV_PRIVATE_GLUE_INFO *prNdevPriv = NULL;
if ((prAdapter == NULL) || (ndev == NULL))
return -1;
#if CFG_SUPPORT_ROAMING
/* Roaming Module - unintiailization */
roamingFsmUninit(prAdapter);
#endif /* CFG_SUPPORT_ROAMING */
/* uninit AIS FSM */
aisFsmUninit(prAdapter);
/* set the ucBssIdx to the illegal value */
prNdevPriv = (struct NETDEV_PRIVATE_GLUE_INFO *)
netdev_priv(ndev);
prNdevPriv->ucBssIdx = 0xff;
return 0;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief Initialize the AP (P2P) related FSM and data.
*
* @param prGlueInfo : the driver private data
* ndev : net device
*
* @retval 0 : success
* others : can't alloc and setup the AP FSM & data
*
*/
/*----------------------------------------------------------------------------*/
int mtk_init_ap_role(struct GLUE_INFO *prGlueInfo,
struct net_device *ndev)
{
int u4Idx = 0;
struct ADAPTER *prAdapter = prGlueInfo->prAdapter;
for (u4Idx = 0; u4Idx < KAL_P2P_NUM; u4Idx++) {
if (gprP2pRoleWdev[u4Idx] == NULL)
break;
}
if (u4Idx >= KAL_P2P_NUM) {
DBGLOG(INIT, ERROR, "There is no free gprP2pRoleWdev.\n");
return -ENOMEM;
}
if ((u4Idx == 0) ||
(prAdapter == NULL) ||
(prAdapter->rP2PNetRegState !=
ENUM_NET_REG_STATE_REGISTERED)) {
DBGLOG(INIT, ERROR,
"The wlan0 can't set to AP without p2p0\n");
/* System will crash, if p2p0 isn't existing. */
return -EFAULT;
}
/* reference from the glRegisterP2P() */
gprP2pRoleWdev[u4Idx] = ndev->ieee80211_ptr;
if (glSetupP2P(prGlueInfo, gprP2pRoleWdev[u4Idx], ndev,
u4Idx, TRUE)) {
gprP2pRoleWdev[u4Idx] = NULL;
return -EFAULT;
}
prGlueInfo->prAdapter->prP2pInfo->u4DeviceNum++;
/* reference from p2pNetRegister() */
/* The ndev doesn't need register_netdev, only reassign the gPrP2pDev.*/
gPrP2pDev[u4Idx] = ndev;
return 0;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief Unnitialize the AP (P2P) related FSM and data.
*
* @param prGlueInfo : the driver private data
* ndev : net device
*
* @retval 0 : success
* others : can't find the AP information by the ndev
*
*/
/*----------------------------------------------------------------------------*/
int mtk_uninit_ap_role(struct GLUE_INFO *prGlueInfo,
struct net_device *ndev)
{
unsigned char u4Idx;
if (mtk_Netdev_To_RoleIdx(prGlueInfo, ndev, &u4Idx) != 0) {
DBGLOG(INIT, WARN,
"can't find the matched dev to uninit AP\n");
return -EFAULT;
}
glUnregisterP2P(prGlueInfo, u4Idx);
gPrP2pDev[u4Idx] = NULL;
gprP2pRoleWdev[u4Idx] = NULL;
return 0;
}
#if (CFG_SUPPORT_DFS_MASTER == 1)
#if KERNEL_VERSION(3, 15, 0) <= CFG80211_VERSION_CODE
int mtk_cfg_start_radar_detection(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_chan_def *chandef,
unsigned int cac_time_ms)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, dev) <= 0) {
DBGLOG(REQ, WARN, "STA doesn't support this function\n");
return -EFAULT;
}
return mtk_p2p_cfg80211_start_radar_detection(wiphy,
dev, chandef, cac_time_ms);
}
#else
int mtk_cfg_start_radar_detection(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_chan_def *chandef)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, dev) <= 0) {
DBGLOG(REQ, WARN, "STA doesn't support this function\n");
return -EFAULT;
}
return mtk_p2p_cfg80211_start_radar_detection(wiphy, dev, chandef);
}
#endif
#if KERNEL_VERSION(3, 13, 0) <= CFG80211_VERSION_CODE
int mtk_cfg_channel_switch(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_csa_settings *params)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, dev) <= 0) {
DBGLOG(REQ, WARN, "STA doesn't support this function\n");
return -EFAULT;
}
return mtk_p2p_cfg80211_channel_switch(wiphy, dev, params);
}
#endif
#endif
#if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE
struct wireless_dev *mtk_cfg_add_iface(struct wiphy *wiphy,
const char *name,
unsigned char name_assign_type,
enum nl80211_iftype type,
struct vif_params *params)
#elif KERNEL_VERSION(4, 1, 0) <= CFG80211_VERSION_CODE
struct wireless_dev *mtk_cfg_add_iface(struct wiphy *wiphy,
const char *name,
unsigned char name_assign_type,
enum nl80211_iftype type,
u32 *flags,
struct vif_params *params)
#else
struct wireless_dev *mtk_cfg_add_iface(struct wiphy *wiphy,
const char *name,
enum nl80211_iftype type,
u32 *flags,
struct vif_params *params)
#endif
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return ERR_PTR(-EFAULT);
}
/* TODO: error handele for the non-P2P interface */
#if (CFG_ENABLE_WIFI_DIRECT_CFG_80211 == 0)
DBGLOG(REQ, WARN, "P2P is not supported\n");
return ERR_PTR(-EINVAL);
#else /* CFG_ENABLE_WIFI_DIRECT_CFG_80211 */
#if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE
return mtk_p2p_cfg80211_add_iface(wiphy, name,
name_assign_type, type, params);
#elif KERNEL_VERSION(4, 1, 0) <= CFG80211_VERSION_CODE
return mtk_p2p_cfg80211_add_iface(wiphy, name,
name_assign_type, type,
flags, params);
#else /* KERNEL_VERSION > (4, 1, 0) */
return mtk_p2p_cfg80211_add_iface(wiphy, name, type, flags,
params);
#endif /* KERNEL_VERSION */
#endif /* CFG_ENABLE_WIFI_DIRECT_CFG_80211 */
}
int mtk_cfg_del_iface(struct wiphy *wiphy,
struct wireless_dev *wdev)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
/* TODO: error handele for the non-P2P interface */
#if (CFG_ENABLE_WIFI_DIRECT_CFG_80211 == 0)
DBGLOG(REQ, WARN, "P2P is not supported\n");
return -EINVAL;
#else /* CFG_ENABLE_WIFI_DIRECT_CFG_80211 */
return mtk_p2p_cfg80211_del_iface(wiphy, wdev);
#endif /* CFG_ENABLE_WIFI_DIRECT_CFG_80211 */
}
#if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE
int mtk_cfg_change_iface(struct wiphy *wiphy,
struct net_device *ndev,
enum nl80211_iftype type,
struct vif_params *params)
#else
int mtk_cfg_change_iface(struct wiphy *wiphy,
struct net_device *ndev,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params)
#endif
{
struct GLUE_INFO *prGlueInfo = NULL;
struct ADAPTER *prAdapter = NULL;
struct NETDEV_PRIVATE_GLUE_INFO *prNetdevPriv = NULL;
struct P2P_INFO *prP2pInfo = NULL;
uint8_t state = 0;
GLUE_SPIN_LOCK_DECLARATION();
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
ASSERT(prGlueInfo);
DBGLOG(P2P, INFO, "ndev=%p, new type=%d\n", ndev, type);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (!ndev) {
DBGLOG(REQ, WARN, "ndev is NULL\n");
return -EINVAL;
}
prNetdevPriv = (struct NETDEV_PRIVATE_GLUE_INFO *)
netdev_priv(ndev);
#if (CFG_ENABLE_WIFI_DIRECT_CFG_80211)
/* for p2p0(GO/GC) & ap0(SAP): mtk_p2p_cfg80211_change_iface
* for wlan0 (STA/SAP): the following mtk_cfg_change_iface process
*/
if (ndev != prGlueInfo->prDevHandler) {
#if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE
return mtk_p2p_cfg80211_change_iface(wiphy, ndev, type,
NULL, params);
#else
return mtk_p2p_cfg80211_change_iface(wiphy, ndev, type,
flags, params);
#endif
}
#endif /* CFG_ENABLE_WIFI_DIRECT_CFG_80211 */
prAdapter = prGlueInfo->prAdapter;
if (ndev->ieee80211_ptr->iftype == type) {
DBGLOG(REQ, INFO, "ndev type is not changed (%d)\n", type);
return 0;
}
netif_carrier_off(ndev);
/* stop ap will stop all queue, and kalIndicateStatusAndComplete only do
* netif_carrier_on. So that, the following STA can't send 4-way M2 to
* AP.
*/
netif_tx_start_all_queues(ndev);
/* flush scan */
GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV);
if ((prGlueInfo->prScanRequest != NULL) &&
(prGlueInfo->prScanRequest->wdev == ndev->ieee80211_ptr)) {
kalCfg80211ScanDone(prGlueInfo->prScanRequest, TRUE);
prGlueInfo->prScanRequest = NULL;
}
GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV);
/* expect that only AP & STA will be handled here (excluding IBSS) */
if (type == NL80211_IFTYPE_AP) {
/* STA mode change to AP mode */
prP2pInfo = prAdapter->prP2pInfo;
if (prP2pInfo == NULL) {
DBGLOG(INIT, ERROR, "prP2pInfo is NULL\n");
return -EFAULT;
}
if (prP2pInfo->u4DeviceNum >= KAL_P2P_NUM) {
DBGLOG(INIT, ERROR, "resource invalid, u4DeviceNum=%d\n"
, prP2pInfo->u4DeviceNum);
return -EFAULT;
}
mtk_uninit_sta_role(prAdapter, ndev);
if (mtk_init_ap_role(prGlueInfo, ndev) != 0) {
DBGLOG(INIT, ERROR, "mtk_init_ap_role FAILED\n");
/* Only AP/P2P resource has the failure case. */
/* So, just re-init AIS. */
mtk_init_sta_role(prAdapter, ndev);
return -EFAULT;
}
} else {
/* AP mode change to STA mode */
if (mtk_uninit_ap_role(prGlueInfo, ndev) != 0) {
DBGLOG(INIT, ERROR, "mtk_uninit_ap_role FAILED\n");
return -EFAULT;
}
mtk_init_sta_role(prAdapter, ndev);
/* continue the mtk_cfg80211_change_iface() process */
#if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE
mtk_cfg80211_change_iface(wiphy, ndev, type, NULL, params);
#else
mtk_cfg80211_change_iface(wiphy, ndev, type, flags, params);
#endif
}
return 0;
}
#if (CFG_ADVANCED_80211_MLO == 1)
int mtk_cfg_add_key(struct wiphy *wiphy,
struct net_device *ndev, int link_id, u8 key_index,
bool pairwise, const u8 *mac_addr,
struct key_params *params)
#else
int mtk_cfg_add_key(struct wiphy *wiphy,
struct net_device *ndev, u8 key_index,
bool pairwise, const u8 *mac_addr,
struct key_params *params)
#endif
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) {
return mtk_p2p_cfg80211_add_key(wiphy, ndev, key_index,
pairwise, mac_addr, params);
}
/* STA Mode */
return mtk_cfg80211_add_key(wiphy, ndev, key_index,
pairwise,
mac_addr, params);
}
#if (CFG_ADVANCED_80211_MLO == 1)
int mtk_cfg_get_key(struct wiphy *wiphy,
struct net_device *ndev, int link_id, u8 key_index,
bool pairwise, const u8 *mac_addr, void *cookie,
void (*callback)(void *cookie, struct key_params *))
#else
int mtk_cfg_get_key(struct wiphy *wiphy,
struct net_device *ndev, u8 key_index,
bool pairwise, const u8 *mac_addr, void *cookie,
void (*callback)(void *cookie, struct key_params *))
#endif
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) {
return mtk_p2p_cfg80211_get_key(wiphy, ndev, key_index,
pairwise, mac_addr, cookie, callback);
}
/* STA Mode */
return mtk_cfg80211_get_key(wiphy, ndev, key_index,
pairwise, mac_addr, cookie, callback);
}
#if (CFG_ADVANCED_80211_MLO == 1)
int mtk_cfg_del_key(struct wiphy *wiphy,
struct net_device *ndev, int link_id, u8 key_index,
bool pairwise, const u8 *mac_addr)
#else
int mtk_cfg_del_key(struct wiphy *wiphy,
struct net_device *ndev, u8 key_index,
bool pairwise, const u8 *mac_addr)
#endif
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) {
return mtk_p2p_cfg80211_del_key(wiphy, ndev, key_index,
pairwise, mac_addr);
}
/* STA Mode */
return mtk_cfg80211_del_key(wiphy, ndev, key_index,
pairwise, mac_addr);
}
#if (CFG_ADVANCED_80211_MLO == 1)
int mtk_cfg_set_default_key(struct wiphy *wiphy,
struct net_device *ndev, int link_id,
u8 key_index, bool unicast, bool multicast)
#else
int mtk_cfg_set_default_key(struct wiphy *wiphy,
struct net_device *ndev,
u8 key_index, bool unicast, bool multicast)
#endif
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) {
return mtk_p2p_cfg80211_set_default_key(wiphy, ndev,
key_index, unicast, multicast);
}
/* STA Mode */
return mtk_cfg80211_set_default_key(wiphy, ndev,
key_index, unicast, multicast);
}
#if (CFG_ADVANCED_80211_MLO == 1)
int mtk_cfg_set_default_mgmt_key(struct wiphy *wiphy,
struct net_device *ndev, int link_id, u8 key_index)
#else
int mtk_cfg_set_default_mgmt_key(struct wiphy *wiphy,
struct net_device *ndev, u8 key_index)
#endif
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0)
return mtk_p2p_cfg80211_set_mgmt_key(wiphy, ndev, key_index);
/* STA Mode */
DBGLOG(REQ, WARN, "STA don't support this function\n");
return -EFAULT;
}
#if KERNEL_VERSION(3, 16, 0) <= CFG80211_VERSION_CODE
int mtk_cfg_get_station(struct wiphy *wiphy,
struct net_device *ndev,
const u8 *mac, struct station_info *sinfo)
#else
int mtk_cfg_get_station(struct wiphy *wiphy,
struct net_device *ndev,
u8 *mac, struct station_info *sinfo)
#endif
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0)
return mtk_p2p_cfg80211_get_station(wiphy, ndev, mac,
sinfo);
/* STA Mode */
return mtk_cfg80211_get_station(wiphy, ndev, mac, sinfo);
}
#if CFG_SUPPORT_TDLS
#if KERNEL_VERSION(3, 16, 0) <= CFG80211_VERSION_CODE
int mtk_cfg_change_station(struct wiphy *wiphy,
struct net_device *ndev,
const u8 *mac, struct station_parameters *params)
#else
int mtk_cfg_change_station(struct wiphy *wiphy,
struct net_device *ndev,
u8 *mac, struct station_parameters *params)
#endif
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) {
DBGLOG(REQ, WARN, "P2P/AP don't support this function\n");
return -EFAULT;
}
/* STA Mode */
return mtk_cfg80211_change_station(wiphy, ndev, mac,
params);
}
#if KERNEL_VERSION(3, 16, 0) <= CFG80211_VERSION_CODE
int mtk_cfg_add_station(struct wiphy *wiphy,
struct net_device *ndev,
const u8 *mac, struct station_parameters *params)
#else
int mtk_cfg_add_station(struct wiphy *wiphy,
struct net_device *ndev,
u8 *mac, struct station_parameters *params)
#endif
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) {
DBGLOG(REQ, WARN, "P2P/AP don't support this function\n");
return -EFAULT;
}
/* STA Mode */
return mtk_cfg80211_add_station(wiphy, ndev, mac, params);
}
#if KERNEL_VERSION(3, 16, 0) <= CFG80211_VERSION_CODE
int mtk_cfg_tdls_oper(struct wiphy *wiphy,
struct net_device *ndev,
const u8 *peer, enum nl80211_tdls_operation oper)
#else
int mtk_cfg_tdls_oper(struct wiphy *wiphy,
struct net_device *ndev,
u8 *peer, enum nl80211_tdls_operation oper)
#endif
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) {
DBGLOG(REQ, WARN, "P2P/AP don't support this function\n");
return -EFAULT;
}
/* STA Mode */
return mtk_cfg80211_tdls_oper(wiphy, ndev, peer, oper);
}
#if KERNEL_VERSION(3, 18, 0) <= CFG80211_VERSION_CODE
int mtk_cfg_tdls_mgmt(struct wiphy *wiphy,
struct net_device *dev,
const u8 *peer, u8 action_code, u8 dialog_token,
u16 status_code, u32 peer_capability,
bool initiator, const u8 *buf, size_t len)
#elif KERNEL_VERSION(3, 16, 0) <= CFG80211_VERSION_CODE
int mtk_cfg_tdls_mgmt(struct wiphy *wiphy,
struct net_device *dev,
const u8 *peer, u8 action_code, u8 dialog_token,
u16 status_code, u32 peer_capability,
const u8 *buf, size_t len)
#else
int mtk_cfg_tdls_mgmt(struct wiphy *wiphy,
struct net_device *dev,
u8 *peer, u8 action_code, u8 dialog_token,
u16 status_code,
const u8 *buf, size_t len)
#endif
{
struct GLUE_INFO *prGlueInfo;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, dev) > 0) {
DBGLOG(REQ, WARN, "P2P/AP don't support this function\n");
return -EFAULT;
}
#if KERNEL_VERSION(3, 18, 0) <= CFG80211_VERSION_CODE
return mtk_cfg80211_tdls_mgmt(wiphy, dev, peer, action_code,
dialog_token, status_code, peer_capability, initiator,
buf, len);
#elif KERNEL_VERSION(3, 16, 0) <= CFG80211_VERSION_CODE
return mtk_cfg80211_tdls_mgmt(wiphy, dev, peer, action_code,
dialog_token, status_code, peer_capability,
buf, len);
#else
return mtk_cfg80211_tdls_mgmt(wiphy, dev, peer, action_code,
dialog_token, status_code,
buf, len);
#endif
}
#endif /* CFG_SUPPORT_TDLS */
#if KERNEL_VERSION(3, 19, 0) <= CFG80211_VERSION_CODE
int mtk_cfg_del_station(struct wiphy *wiphy,
struct net_device *ndev,
struct station_del_parameters *params)
#elif KERNEL_VERSION(3, 16, 0) <= CFG80211_VERSION_CODE
int mtk_cfg_del_station(struct wiphy *wiphy,
struct net_device *ndev,
const u8 *mac)
#else
int mtk_cfg_del_station(struct wiphy *wiphy,
struct net_device *ndev, u8 *mac)
#endif
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) {
#if KERNEL_VERSION(3, 19, 0) <= CFG80211_VERSION_CODE
return mtk_p2p_cfg80211_del_station(wiphy, ndev, params);
#else
return mtk_p2p_cfg80211_del_station(wiphy, ndev, mac);
#endif
}
/* STA Mode */
#if CFG_SUPPORT_TDLS
#if KERNEL_VERSION(3, 19, 0) <= CFG80211_VERSION_CODE
return mtk_cfg80211_del_station(wiphy, ndev, params);
#else /* CFG80211_VERSION_CODE > KERNEL_VERSION(3, 19, 0) */
return mtk_cfg80211_del_station(wiphy, ndev, mac);
#endif /* CFG80211_VERSION_CODE */
#else /* CFG_SUPPORT_TDLS == 0 */
/* AIS only support this function when CFG_SUPPORT_TDLS */
return -EFAULT;
#endif /* CFG_SUPPORT_TDLS */
}
int mtk_cfg_scan(struct wiphy *wiphy,
struct cfg80211_scan_request *request)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo,
request->wdev->netdev) > 0)
return mtk_p2p_cfg80211_scan(wiphy, request);
/* STA Mode */
return mtk_cfg80211_scan(wiphy, request);
}
#if KERNEL_VERSION(4, 5, 0) <= CFG80211_VERSION_CODE
void mtk_cfg_abort_scan(struct wiphy *wiphy,
struct wireless_dev *wdev)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return;
}
if (mtk_IsP2PNetDevice(prGlueInfo, wdev->netdev) > 0)
mtk_p2p_cfg80211_abort_scan(wiphy, wdev);
else /* STA Mode */
mtk_cfg80211_abort_scan(wiphy, wdev);
}
#endif
#if CFG_SUPPORT_SCHED_SCAN
int mtk_cfg_sched_scan_start(IN struct wiphy *wiphy,
IN struct net_device *ndev,
IN struct cfg80211_sched_scan_request *request)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) {
DBGLOG(REQ, WARN, "P2P/AP don't support this function\n");
return -EFAULT;
}
return mtk_cfg80211_sched_scan_start(wiphy, ndev, request);
}
#if KERNEL_VERSION(4, 14, 0) <= CFG80211_VERSION_CODE
int mtk_cfg_sched_scan_stop(IN struct wiphy *wiphy,
IN struct net_device *ndev,
IN u64 reqid)
#else
int mtk_cfg_sched_scan_stop(IN struct wiphy *wiphy,
IN struct net_device *ndev)
#endif
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) {
DBGLOG(REQ, WARN, "P2P/AP don't support this function\n");
return -EFAULT;
}
return mtk_cfg80211_sched_scan_stop(wiphy, ndev);
}
#endif /* CFG_SUPPORT_SCHED_SCAN */
int mtk_cfg_connect(struct wiphy *wiphy,
struct net_device *ndev,
struct cfg80211_connect_params *sme)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0)
return mtk_p2p_cfg80211_connect(wiphy, ndev, sme);
/* STA Mode */
return mtk_cfg80211_connect(wiphy, ndev, sme);
}
int mtk_cfg_disconnect(struct wiphy *wiphy,
struct net_device *ndev,
u16 reason_code)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0)
return mtk_p2p_cfg80211_disconnect(wiphy, ndev,
reason_code);
/* STA Mode */
return mtk_cfg80211_disconnect(wiphy, ndev, reason_code);
}
int mtk_cfg_join_ibss(struct wiphy *wiphy,
struct net_device *ndev,
struct cfg80211_ibss_params *params)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0)
return mtk_p2p_cfg80211_join_ibss(wiphy, ndev, params);
/* STA Mode */
return mtk_cfg80211_join_ibss(wiphy, ndev, params);
}
int mtk_cfg_leave_ibss(struct wiphy *wiphy,
struct net_device *ndev)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0)
return mtk_p2p_cfg80211_leave_ibss(wiphy, ndev);
/* STA Mode */
return mtk_cfg80211_leave_ibss(wiphy, ndev);
}
int mtk_cfg_set_power_mgmt(struct wiphy *wiphy,
struct net_device *ndev,
bool enabled, int timeout)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) {
return mtk_p2p_cfg80211_set_power_mgmt(wiphy, ndev,
enabled, timeout);
}
/* STA Mode */
return mtk_cfg80211_set_power_mgmt(wiphy, ndev, enabled,
timeout);
}
int mtk_cfg_set_pmksa(struct wiphy *wiphy,
struct net_device *ndev,
struct cfg80211_pmksa *pmksa)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) {
DBGLOG(REQ, WARN, "P2P/AP don't support this function\n");
return -EFAULT;
}
return mtk_cfg80211_set_pmksa(wiphy, ndev, pmksa);
}
int mtk_cfg_del_pmksa(struct wiphy *wiphy,
struct net_device *ndev,
struct cfg80211_pmksa *pmksa)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) {
DBGLOG(REQ, WARN, "P2P/AP don't support this function\n");
return -EFAULT;
}
return mtk_cfg80211_del_pmksa(wiphy, ndev, pmksa);
}
int mtk_cfg_flush_pmksa(struct wiphy *wiphy,
struct net_device *ndev)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) {
DBGLOG(REQ, WARN, "P2P/AP don't support this function\n");
return -EFAULT;
}
return mtk_cfg80211_flush_pmksa(wiphy, ndev);
}
#if CONFIG_SUPPORT_GTK_REKEY
int mtk_cfg_set_rekey_data(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_gtk_rekey_data *data)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, dev) > 0) {
DBGLOG(REQ, WARN, "P2P/AP don't support this function\n");
return -EFAULT;
}
return mtk_cfg80211_set_rekey_data(wiphy, dev, data);
}
#endif /* CONFIG_SUPPORT_GTK_REKEY */
int mtk_cfg_suspend(struct wiphy *wiphy,
struct cfg80211_wowlan *wow)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return 0;
}
/* TODO: AP/P2P do not support this function, should take that case. */
return mtk_cfg80211_suspend(wiphy, wow);
}
int mtk_cfg_resume(struct wiphy *wiphy)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return 0;
}
/* TODO: AP/P2P do not support this function, should take that case. */
return mtk_cfg80211_resume(wiphy);
}
#if CFG_SUPPORT_CFG80211_AUTH
int mtk_cfg_auth(struct wiphy *wiphy, struct net_device *ndev,
struct cfg80211_auth_request *req)
{
struct GLUE_INFO *prGlueInfo = NULL;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if ((!prGlueInfo) || (prGlueInfo->u4ReadyFlag == 0)) {
DBGLOG(REQ, WARN, "driver is not ready\n");
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0)
return mtk_p2p_cfg80211_auth(wiphy, ndev, req);
/* STA Mode */
return mtk_cfg80211_auth(wiphy, ndev, req);
}
#endif
int mtk_cfg_assoc(struct wiphy *wiphy,
struct net_device *ndev,
struct cfg80211_assoc_request *req)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
#if CFG_SUPPORT_CFG80211_AUTH
if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0)
return mtk_p2p_cfg80211_assoc(wiphy, ndev, req);
#else
if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) {
DBGLOG(REQ, WARN, "P2P/AP don't support this function\n");
return -EFAULT;
}
#endif
/* STA Mode */
return mtk_cfg80211_assoc(wiphy, ndev, req);
}
int mtk_cfg_remain_on_channel(struct wiphy *wiphy,
struct wireless_dev *wdev,
struct ieee80211_channel *chan,
unsigned int duration, u64 *cookie)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, wdev->netdev) > 0) {
return mtk_p2p_cfg80211_remain_on_channel(wiphy, wdev, chan,
duration, cookie);
}
/* STA Mode */
return mtk_cfg80211_remain_on_channel(wiphy, wdev, chan,
duration, cookie);
}
int mtk_cfg_cancel_remain_on_channel(struct wiphy *wiphy,
struct wireless_dev *wdev, u64 cookie)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, wdev->netdev) > 0) {
return mtk_p2p_cfg80211_cancel_remain_on_channel(wiphy,
wdev,
cookie);
}
/* STA Mode */
return mtk_cfg80211_cancel_remain_on_channel(wiphy, wdev,
cookie);
}
#if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
int mtk_cfg_mgmt_tx(struct wiphy *wiphy,
struct wireless_dev *wdev,
struct cfg80211_mgmt_tx_params *params, u64 *cookie)
#else
int mtk_cfg_mgmt_tx(struct wiphy *wiphy,
struct wireless_dev *wdev,
struct ieee80211_channel *channel, bool offscan,
unsigned int wait, const u8 *buf, size_t len, bool no_cck,
bool dont_wait_for_ack, u64 *cookie)
#endif
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
#if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
if (mtk_IsP2PNetDevice(prGlueInfo, wdev->netdev) > 0)
return mtk_p2p_cfg80211_mgmt_tx(wiphy, wdev, params,
cookie);
/* STA Mode */
return mtk_cfg80211_mgmt_tx(wiphy, wdev, params, cookie);
#else /* KERNEL_VERSION(3, 14, 0) > CFG80211_VERSION_CODE */
if (mtk_IsP2PNetDevice(prGlueInfo, wdev->netdev) > 0) {
return mtk_p2p_cfg80211_mgmt_tx(wiphy, wdev, channel, offscan,
wait, buf, len, no_cck, dont_wait_for_ack, cookie);
}
/* STA Mode */
return mtk_cfg80211_mgmt_tx(wiphy, wdev, channel, offscan, wait, buf,
len, no_cck, dont_wait_for_ack, cookie);
#endif
}
void mtk_cfg_mgmt_frame_register(struct wiphy *wiphy,
struct wireless_dev *wdev,
u16 frame_type, bool reg)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return;
}
if (mtk_IsP2PNetDevice(prGlueInfo, wdev->netdev) > 0) {
mtk_p2p_cfg80211_mgmt_frame_register(wiphy, wdev,
frame_type,
reg);
} else {
mtk_cfg80211_mgmt_frame_register(wiphy, wdev, frame_type,
reg);
}
}
#if KERNEL_VERSION(5, 8, 0) <= CFG80211_VERSION_CODE
void mtk_cfg_mgmt_frame_update(struct wiphy *wiphy,
struct wireless_dev *wdev,
struct mgmt_frame_regs *upd)
{
struct GLUE_INFO *prGlueInfo = NULL;
u_int8_t fgIsP2pNetDevice = FALSE;
uint32_t *pu4PacketFilter = NULL;
if ((wiphy == NULL) || (wdev == NULL) || (upd == NULL)) {
DBGLOG(INIT, TRACE, "Invalidate params\n");
return;
}
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if ((!prGlueInfo) || (prGlueInfo->u4ReadyFlag == 0)) {
DBGLOG(REQ, WARN, "driver is not ready\n");
return;
}
fgIsP2pNetDevice = mtk_IsP2PNetDevice(prGlueInfo, wdev->netdev);
DBGLOG(INIT, TRACE,
"netdev(0x%p) update management frame filter: 0x%08x\n",
wdev->netdev, upd->interface_stypes);
if (fgIsP2pNetDevice) {
uint8_t ucRoleIdx = 0;
struct P2P_ROLE_FSM_INFO *prP2pRoleFsmInfo =
(struct P2P_ROLE_FSM_INFO *) NULL;
if (prGlueInfo->prP2PInfo[0]->prDevHandler ==
wdev->netdev) {
pu4PacketFilter =
&prGlueInfo->prP2PDevInfo
->u4OsMgmtFrameFilter;
/* Reset filters*/
*pu4PacketFilter = 0;
} else {
if (mtk_Netdev_To_RoleIdx(prGlueInfo,
wdev->netdev, &ucRoleIdx) < 0) {
DBGLOG(P2P, WARN,
"wireless dev match fail!\n");
return;
}
/* Non P2P device*/
if (ucRoleIdx >= KAL_P2P_NUM) {
DBGLOG(P2P, WARN,
"Invalid RoleIdx %u\n",
ucRoleIdx);
return;
}
DBGLOG(P2P, TRACE,
"Open packet filer RoleIdx %u\n",
ucRoleIdx);
prP2pRoleFsmInfo =
prGlueInfo->prAdapter->rWifiVar
.aprP2pRoleFsmInfo[ucRoleIdx];
pu4PacketFilter = &prP2pRoleFsmInfo
->u4P2pPacketFilter;
*pu4PacketFilter =
PARAM_PACKET_FILTER_SUPPORTED;
}
} else {
pu4PacketFilter = &prGlueInfo->u4OsMgmtFrameFilter;
*pu4PacketFilter = 0;
}
if (upd->interface_stypes & MASK_MAC_FRAME_PROBE_REQ)
*pu4PacketFilter |= PARAM_PACKET_FILTER_PROBE_REQ;
if (upd->interface_stypes & MASK_MAC_FRAME_ACTION)
*pu4PacketFilter |= PARAM_PACKET_FILTER_ACTION_FRAME;
set_bit(fgIsP2pNetDevice ?
GLUE_FLAG_FRAME_FILTER_BIT :
GLUE_FLAG_FRAME_FILTER_AIS_BIT,
&prGlueInfo->ulFlag);
/* wake up main thread */
wake_up_interruptible(&prGlueInfo->waitq);
}
#endif
#ifdef CONFIG_NL80211_TESTMODE
#if KERNEL_VERSION(3, 12, 0) <= CFG80211_VERSION_CODE
int mtk_cfg_testmode_cmd(struct wiphy *wiphy,
struct wireless_dev *wdev,
void *data, int len)
#else
int mtk_cfg_testmode_cmd(struct wiphy *wiphy, void *data,
int len)
#endif
{
#if KERNEL_VERSION(3, 12, 0) <= CFG80211_VERSION_CODE
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, wdev->netdev) > 0) {
return mtk_p2p_cfg80211_testmode_cmd(wiphy, wdev, data,
len);
}
return mtk_cfg80211_testmode_cmd(wiphy, wdev, data, len);
#else
/* XXX: no information can to check the mtk_IsP2PNetDevice */
/* return mtk_p2p_cfg80211_testmode_cmd(wiphy, data, len); */
return mtk_cfg80211_testmode_cmd(wiphy, data, len);
#endif
}
#endif /* CONFIG_NL80211_TESTMODE */
#if (CFG_ENABLE_WIFI_DIRECT_CFG_80211 != 0)
int mtk_cfg_change_bss(struct wiphy *wiphy,
struct net_device *dev,
struct bss_parameters *params)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, dev) <= 0) {
DBGLOG(REQ, WARN, "STA doesn't support this function\n");
return -EFAULT;
}
return mtk_p2p_cfg80211_change_bss(wiphy, dev, params);
}
int mtk_cfg_mgmt_tx_cancel_wait(struct wiphy *wiphy,
struct wireless_dev *wdev,
u64 cookie)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, wdev->netdev) <= 0) {
DBGLOG(REQ, WARN, "STA doesn't support this function\n");
return -EFAULT;
}
return mtk_p2p_cfg80211_mgmt_tx_cancel_wait(wiphy, wdev,
cookie);
}
int mtk_cfg_deauth(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_deauth_request *req)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
int ret = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, dev) > 0)
ret = mtk_p2p_cfg80211_deauth(wiphy, dev, req);
#if CFG_SUPPORT_CFG80211_AUTH
else
ret = mtk_cfg80211_deauth(wiphy, dev, req);
#endif
return ret;
}
int mtk_cfg_disassoc(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_disassoc_request *req)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, dev) <= 0) {
DBGLOG(REQ, WARN, "STA doesn't support this function\n");
return -EFAULT;
}
return mtk_p2p_cfg80211_disassoc(wiphy, dev, req);
}
int mtk_cfg_start_ap(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_ap_settings *settings)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, dev) <= 0) {
DBGLOG(REQ, WARN, "STA doesn't support this function\n");
return -EFAULT;
}
return mtk_p2p_cfg80211_start_ap(wiphy, dev, settings);
}
int mtk_cfg_change_beacon(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_beacon_data *info)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, dev) <= 0) {
DBGLOG(REQ, WARN, "STA doesn't support this function\n");
return -EFAULT;
}
return mtk_p2p_cfg80211_change_beacon(wiphy, dev, info);
}
#if (CFG_ADVANCED_80211_MLO == 1)
int mtk_cfg_stop_ap(struct wiphy *wiphy,
struct net_device *dev,
unsigned int link_id)
#else
int mtk_cfg_stop_ap(struct wiphy *wiphy,
struct net_device *dev)
#endif
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, dev) <= 0) {
DBGLOG(REQ, WARN, "STA doesn't support this function\n");
return -EFAULT;
}
return mtk_p2p_cfg80211_stop_ap(wiphy, dev);
}
int mtk_cfg_set_wiphy_params(struct wiphy *wiphy,
u32 changed)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
/* TODO: AIS not support this function */
return mtk_p2p_cfg80211_set_wiphy_params(wiphy, changed);
}
int mtk_cfg_set_bitrate_mask(struct wiphy *wiphy,
struct net_device *dev,
#if (CFG_ADVANCED_80211_MLO == 1)
unsigned int link_id,
#endif
const u8 *peer,
const struct cfg80211_bitrate_mask *mask)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, dev) <= 0) {
DBGLOG(REQ, WARN, "STA doesn't support this function\n");
return -EFAULT;
}
return mtk_p2p_cfg80211_set_bitrate_mask(wiphy, dev, peer,
mask);
}
int mtk_cfg_set_txpower(struct wiphy *wiphy,
struct wireless_dev *wdev,
enum nl80211_tx_power_setting type, int mbm)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, wdev->netdev) <= 0) {
DBGLOG(REQ, WARN, "STA doesn't support this function\n");
return -EFAULT;
}
return mtk_p2p_cfg80211_set_txpower(wiphy, wdev, type, mbm);
}
int mtk_cfg_get_txpower(struct wiphy *wiphy,
struct wireless_dev *wdev,
int *dbm)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint8_t state = 0;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) {
DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state);
return -EFAULT;
}
if (mtk_IsP2PNetDevice(prGlueInfo, wdev->netdev) <= 0) {
DBGLOG_LIMITED(REQ, WARN,
"STA doesn't support this function\n");
return -EFAULT;
}
return mtk_p2p_cfg80211_get_txpower(wiphy, wdev, dbm);
}
#endif /* (CFG_ENABLE_WIFI_DIRECT_CFG_80211 != 0) */
#endif /* CFG_ENABLE_UNIFY_WIPHY */
/*-----------------------------------------------------------------------*/
/*!
* @brief This function goes through the provided ies buffer, and
* collects those non-wfa vendor specific ies into driver's
* internal buffer (non_wfa_vendor_ie_buf), to be sent in
* AssocReq in AIS mode.
* The non-wfa vendor specific ies are those with ie_id = 0xdd
* and ouis are different from wfa's oui. (i.e., it could be
* customer's vendor ie ...etc.
*
* @param prGlueInfo driver's private glueinfo
* ies ie buffer
* len length of ie
*
* @retval length of the non_wfa vendor ie
*/
/*-----------------------------------------------------------------------*/
uint16_t cfg80211_get_non_wfa_vendor_ie(struct GLUE_INFO *prGlueInfo,
uint8_t *ies, int32_t len)
{
const uint8_t *pos = ies, *end = ies+len;
struct ieee80211_vendor_ie *ie;
int32_t ie_oui = 0;
uint16_t *ret_len, max_len;
uint8_t *w_pos;
if (!prGlueInfo || !ies || !len)
return 0;
w_pos = prGlueInfo->non_wfa_vendor_ie_buf;
ret_len = &prGlueInfo->non_wfa_vendor_ie_len;
max_len = (uint16_t)sizeof(prGlueInfo->non_wfa_vendor_ie_buf);
while (pos < end) {
pos = cfg80211_find_ie(WLAN_EID_VENDOR_SPECIFIC, pos,
end - pos);
if (!pos)
break;
ie = (struct ieee80211_vendor_ie *)pos;
/* Make sure we can access ie->len */
BUILD_BUG_ON(offsetof(struct ieee80211_vendor_ie, len) != 1);
if (ie->len < sizeof(*ie))
goto cont;
ie_oui = ie->oui[0] << 16 | ie->oui[1] << 8 | ie->oui[2];
/*
* If oui is other than: 0x0050f2 & 0x506f9a,
* we consider it is non-wfa oui.
*/
if (ie_oui != WLAN_OUI_MICROSOFT && ie_oui != WLAN_OUI_WFA) {
/*
* If remaining buf len is capable, we copy
* this ie to the buf.
*/
if (max_len-(*ret_len) >= ie->len+2) {
DBGLOG(AIS, TRACE,
"vendor ie(len=%d, oui=0x%06x)\n",
ie->len, ie_oui);
memcpy(w_pos, pos, ie->len+2);
w_pos += (ie->len+2);
(*ret_len) += ie->len+2;
} else {
/* Otherwise we give an error msg
* and return.
*/
DBGLOG(AIS, ERROR,
"Insufficient buf for vendor ie, exit!\n");
break;
}
}
cont:
pos += 2 + ie->len;
}
return *ret_len;
}
int mtk_cfg80211_update_ft_ies(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_update_ft_ies_params *ftie)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint32_t u4InfoBufLen = 0;
uint32_t rStatus = WLAN_STATUS_FAILURE;
#if !CFG_SUPPORT_802_11R
DBGLOG(OID, INFO, "FT: 802.11R is not enabled\n");
return 0;
#endif
if (!wiphy)
return -1;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(wiphy);
rStatus = kalIoctl(prGlueInfo, wlanoidUpdateFtIes, (void *)ftie,
sizeof(*ftie), FALSE, FALSE, FALSE, &u4InfoBufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
DBGLOG(OID, INFO, "FT: update Ft IE failed\n");
return 0;
}