| /****************************************************************************** |
| * |
| * 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" |
| |
| /******************************************************************************* |
| * C O N S T A N T S |
| ******************************************************************************** |
| */ |
| |
| /******************************************************************************* |
| * D A T A T Y P E S |
| ******************************************************************************** |
| */ |
| |
| /******************************************************************************* |
| * P U B L I C D A T A |
| ******************************************************************************** |
| */ |
| |
| /******************************************************************************* |
| * 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) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; |
| ENUM_PARAM_OP_MODE_T eOpMode; |
| UINT_32 u4BufLen; |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| 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:%lx\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; |
| #endif |
| |
| 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) |
| { |
| PARAM_KEY_T rKey; |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; |
| INT_32 i4Rslt = -EINVAL; |
| UINT_32 u4BufLen = 0; |
| UINT_8 tmp1[8], tmp2[8]; |
| #if CFG_SUPPORT_REPLAY_DETECTION |
| P_BSS_INFO_T prBssInfo = NULL; |
| struct SEC_DETECT_REPLAY_INFO *prDetRplyInfo = NULL; |
| UINT_8 ucCheckZeroKey = 0; |
| UINT_8 i = 0; |
| #endif |
| |
| const UINT_8 aucBCAddr[] = BC_MAC_ADDR; |
| /* const UINT_8 aucZeroMacAddr[] = NULL_MAC_ADDR; */ |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| #if DBG |
| DBGLOG(RSN, INFO, "mtk_cfg80211_add_key\n"); |
| 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(PARAM_KEY_T)); |
| |
| 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 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, ¶ms->key[16], 8); |
| kalMemCopy(tmp2, ¶ms->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 = ((ULONG)&(((P_PARAM_KEY_T) 0)->aucKeyMaterial)) + rKey.u4KeyLength; |
| |
| #if CFG_SUPPORT_REPLAY_DETECTION |
| prBssInfo = GET_BSS_INFO_BY_INDEX(prGlueInfo->prAdapter, prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex); |
| |
| prDetRplyInfo = &prBssInfo->rDetRplyInfo; |
| |
| 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, "hit group key reinstall case, 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 *) |
| ) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| |
| prGlueInfo = (P_GLUE_INFO_T) 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) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; |
| PARAM_REMOVE_KEY_T rRemoveKey; |
| UINT_32 u4BufLen = 0; |
| INT_32 i4Rslt = -EINVAL; |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| if (g_u4HaltFlag) { |
| DBGLOG(RSN, WARN, "wlan is halt, skip key deletion\n"); |
| return WLAN_STATUS_FAILURE; |
| } |
| |
| #if DBG |
| DBGLOG(RSN, TRACE, "mtk_cfg80211_del_key\n"); |
| 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(PARAM_REMOVE_KEY_T)); |
| rRemoveKey.u4KeyIndex = key_index; |
| rRemoveKey.u4Length = sizeof(PARAM_REMOVE_KEY_T); |
| if (mac_addr) { |
| COPY_MAC_ADDR(rRemoveKey.arBSSID, mac_addr); |
| rRemoveKey.u4KeyIndex |= BIT(30); |
| } |
| |
| 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:%lx\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) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| PARAM_DEFAULT_KEY_T rDefaultKey; |
| WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; |
| INT_32 i4Rst = -EINVAL; |
| UINT_32 u4BufLen = 0; |
| BOOLEAN fgDef = FALSE, fgMgtDef = FALSE; |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| /* For STA, should wep set the default key !! */ |
| #if DBG |
| DBGLOG(RSN, INFO, "mtk_cfg80211_set_default_key\n"); |
| 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(PARAM_DEFAULT_KEY_T), 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) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| WLAN_STATUS rStatus; |
| PARAM_MAC_ADDRESS arBssid; |
| UINT_32 u4BufLen, u4Rate; |
| INT_32 i4Rssi; |
| PARAM_GET_STA_STA_STATISTICS rQueryStaStatistics; |
| UINT_32 u4TotalError; |
| struct net_device_stats *prDevStats; |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| 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"); |
| } else { |
| 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)) { |
| /* |
| * DBGLOG(REQ, WARN, "unable to retrieve link speed\n")); |
| */ |
| DBGLOG(REQ, WARN, "last link speed\n"); |
| sinfo->txrate.legacy = prGlueInfo->u4LinkSpeedCache; |
| } else { |
| /* |
| * sinfo->filled |= STATION_INFO_TX_BITRATE; |
| */ |
| sinfo->txrate.legacy = u4Rate / 1000; /* convert from 100bps to 100kbps */ |
| 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); |
| |
| #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) || (i4Rssi == PARAM_WHQL_RSSI_MIN_DBM) |
| || (i4Rssi == PARAM_WHQL_RSSI_MAX_DBM)) { |
| DBGLOG(REQ, WARN, "last rssi\n"); |
| sinfo->signal = prGlueInfo->i4RssiCache; |
| } 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); |
| #else |
| sinfo->filled |= STATION_INFO_RX_PACKETS; |
| #endif |
| sinfo->rx_packets = prDevStats->rx_packets; |
| |
| /* 5. fill TX_PACKETS */ |
| #if KERNEL_VERSION(4, 0, 0) <= CFG80211_VERSION_CODE |
| sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS); |
| #else |
| sinfo->filled |= STATION_INFO_TX_PACKETS; |
| #endif |
| 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, "unable to retrieve link speed,status code = %d\n", rStatus); |
| } else { |
| DBGLOG(REQ, INFO, "BSSID: [" MACSTR "] TxFailCount %d LifeTimeOut %d\n", |
| MAC2STR(arBssid), rQueryStaStatistics.u4TxFailCount, |
| rQueryStaStatistics.u4TxLifeTimeoutCount); |
| |
| 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) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| WLAN_STATUS rStatus; |
| PARAM_MAC_ADDRESS arBssid; |
| UINT_32 u4BufLen, u4Rate; |
| INT_32 i4Rssi; |
| PARAM_GET_STA_STA_STATISTICS rQueryStaStatistics; |
| UINT_32 u4TotalError; |
| struct net_device_stats *prDevStats; |
| |
| prGlueInfo = (P_GLUE_INFO_T) 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 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)) { |
| /* |
| * DBGLOG(REQ, WARN, "unable to retrieve link speed\n")); |
| */ |
| DBGLOG(REQ, WARN, "last link speed\n"); |
| sinfo->txrate.legacy = prGlueInfo->u4LinkSpeedCache; |
| } else { |
| /* |
| * sinfo->filled |= STATION_INFO_TX_BITRATE; |
| */ |
| sinfo->txrate.legacy = u4Rate / 1000; /* convert from 100bps to 100kbps */ |
| 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) || (i4Rssi == PARAM_WHQL_RSSI_MIN_DBM) |
| || (i4Rssi == PARAM_WHQL_RSSI_MAX_DBM)) { |
| DBGLOG(REQ, WARN, "last rssi\n"); |
| sinfo->signal = prGlueInfo->i4RssiCache; |
| } 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, "unable to get sta statistics: status[0x%x]\n", rStatus); |
| } else { |
| DBGLOG(REQ, INFO, "BSSID: [" MACSTR "] TxFailCount %d LifeTimeOut %d\n", |
| 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) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| WLAN_STATUS rStatus; |
| PARAM_MAC_ADDRESS arBssid; |
| UINT_32 u4BufLen; |
| INT_32 i4Rssi; |
| PARAM_GET_STA_STA_STATISTICS rQueryStaStatistics; |
| PARAM_GET_BSS_STATISTICS rQueryBssStatistics; |
| struct net_device_stats *prDevStats; |
| P_NETDEV_PRIVATE_GLUE_INFO prNetDevPrivate = (P_NETDEV_PRIVATE_GLUE_INFO) NULL; |
| UINT_8 ucBssIndex; |
| |
| prGlueInfo = (P_GLUE_INFO_T) 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 = (P_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) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| WLAN_STATUS rStatus; |
| UINT_32 i, u4BufLen; |
| PARAM_SCAN_REQUEST_ADV_T rScanRequest; |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| kalMemZero(&rScanRequest, sizeof(rScanRequest)); |
| |
| /* check if there is any pending scan/sched_scan not yet finished */ |
| if (prGlueInfo->prScanRequest != NULL) |
| return -EBUSY; |
| |
| if (request->n_ssids == 0) { |
| rScanRequest.u4SsidNum = 0; |
| } else if (request->n_ssids <= SCN_SSID_MAX_NUM) { |
| rScanRequest.u4SsidNum = request->n_ssids; |
| |
| for (i = 0; i < request->n_ssids; i++) { |
| COPY_SSID(rScanRequest.rSsid[i].aucSsid, |
| rScanRequest.rSsid[i].u4SsidLen, request->ssids[i].ssid, request->ssids[i].ssid_len); |
| } |
| } else { |
| return -EINVAL; |
| } |
| |
| rScanRequest.u4IELength = request->ie_len; |
| if (request->ie_len > 0) |
| rScanRequest.pucIE = (PUINT_8) (request->ie); |
| |
| #if CFG_SCAN_CHANNEL_SPECIFIED |
| DBGLOG(REQ, INFO, "scan channel num = %d\n", request->n_channels); |
| |
| if (request->n_channels > MAXIMUM_OPERATION_CHANNEL_LIST) { |
| DBGLOG(REQ, WARN, "scan channel num (%d) exceeds %d, do a full scan instead\n", |
| request->n_channels, MAXIMUM_OPERATION_CHANNEL_LIST); |
| rScanRequest.ucChannelListNum = 0; |
| } else { |
| rScanRequest.ucChannelListNum = request->n_channels; |
| for (i = 0; i < request->n_channels; i++) { |
| rScanRequest.arChnlInfoList[i].eBand = |
| kalCfg80211ToMtkBand(request->channels[i]->band); |
| rScanRequest.arChnlInfoList[i].u4CenterFreq1 = request->channels[i]->center_freq; |
| rScanRequest.arChnlInfoList[i].u4CenterFreq2 = 0; |
| rScanRequest.arChnlInfoList[i].u2PriChnlFreq = request->channels[i]->center_freq; |
| #if KERNEL_VERSION(3, 12, 0) <= CFG80211_VERSION_CODE |
| rScanRequest.arChnlInfoList[i].ucChnlBw = request->scan_width; |
| #else |
| rScanRequest.arChnlInfoList[i].ucChnlBw = 0; |
| #endif |
| rScanRequest.arChnlInfoList[i].ucChannelNum = |
| ieee80211_frequency_to_channel(request->channels[i]->center_freq); |
| } |
| } |
| #endif |
| |
| rStatus = kalIoctl(prGlueInfo, |
| wlanoidSetBssidListScanAdv, |
| &rScanRequest, sizeof(PARAM_SCAN_REQUEST_ADV_T), FALSE, FALSE, FALSE, &u4BufLen); |
| |
| if (rStatus != WLAN_STATUS_SUCCESS) { |
| DBGLOG(REQ, WARN, "scan error:%lx\n", rStatus); |
| return -EINVAL; |
| } |
| |
| prGlueInfo->prScanRequest = request; |
| |
| return 0; |
| } |
| |
| static UINT_8 wepBuf[48]; |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @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) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| WLAN_STATUS rStatus; |
| UINT_32 u4BufLen; |
| ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus; |
| ENUM_PARAM_AUTH_MODE_T eAuthMode; |
| UINT_32 cipher; |
| PARAM_CONNECT_T rNewSsid; |
| BOOLEAN fgCarryWPSIE = FALSE; |
| ENUM_PARAM_OP_MODE_T eOpMode; |
| UINT_32 i, u4AkmSuite = 0; |
| P_DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY prEntry; |
| #if CFG_SUPPORT_REPLAY_DETECTION |
| P_BSS_INFO_T prBssInfo = NULL; |
| struct SEC_DETECT_REPLAY_INFO *prDetRplyInfo = NULL; |
| #endif |
| |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| /* printk("[wlan]mtk_cfg80211_connect\n"); */ |
| 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%lx\n", rStatus); |
| return -EFAULT; |
| } |
| |
| /* after set operation mode, key table are cleared */ |
| |
| /* 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_REPLAY_DETECTION |
| /* reset Detect replay information */ |
| prBssInfo = GET_BSS_INFO_BY_INDEX(prGlueInfo->prAdapter, prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex); |
| |
| prDetRplyInfo = &prBssInfo->rDetRplyInfo; |
| kalMemZero(prDetRplyInfo, sizeof(struct SEC_DETECT_REPLAY_INFO)); |
| #endif |
| |
| |
| #if CFG_SUPPORT_802_11W |
| prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; |
| switch (sme->mfp) { |
| case NL80211_MFP_NO: |
| prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; |
| break; |
| case NL80211_MFP_REQUIRED: |
| prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_REQUIRED; |
| break; |
| default: |
| prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; |
| break; |
| } |
| /* DBGLOG(SCN, INFO, ("MFP=%d\n", prGlueInfo->rWpaInfo.u4Mfp)); */ |
| #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; |
| default: |
| prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM | IW_AUTH_ALG_SHARED_KEY; |
| 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; |
| 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; |
| 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_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 |
| 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) { |
| eAuthMode = (prGlueInfo->rWpaInfo.u4AuthAlg == IW_AUTH_ALG_OPEN_SYSTEM) ? |
| AUTH_MODE_OPEN : AUTH_MODE_AUTO_SWITCH; |
| } |
| |
| prGlueInfo->rWpaInfo.fgPrivacyInvoke = sme->privacy; |
| prGlueInfo->fgWpsActive = FALSE; |
| |
| #if CFG_SUPPORT_PASSPOINT |
| prGlueInfo->fgConnectHS20AP = FALSE; |
| #endif /* CFG_SUPPORT_PASSPOINT */ |
| |
| if (sme->ie && sme->ie_len > 0) { |
| WLAN_STATUS rStatus; |
| UINT_32 u4BufLen; |
| PUINT_8 prDesiredIE = NULL; |
| PUINT_8 pucIEStart = (PUINT_8)sme->ie; |
| #if CFG_SUPPORT_WAPI |
| rStatus = kalIoctl(prGlueInfo, |
| wlanoidSetWapiAssocInfo, pucIEStart, sme->ie_len, FALSE, FALSE, FALSE, &u4BufLen); |
| |
| if (rStatus != WLAN_STATUS_SUCCESS) |
| DBGLOG(SEC, WARN, "[wapi] set wapi assoc info error:%lx\n", rStatus); |
| #endif |
| #if CFG_SUPPORT_WPS2 |
| if (wextSrchDesiredWPSIE(pucIEStart, sme->ie_len, 0xDD, (PUINT_8 *) &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:%lx\n", rStatus); |
| } |
| #endif |
| #if CFG_SUPPORT_PASSPOINT |
| if (wextSrchDesiredHS20IE(pucIEStart, sme->ie_len, (PUINT_8 *) &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:%lx\n", rStatus); |
| #endif |
| } |
| if (wextSrchDesiredInterworkingIE(pucIEStart, sme->ie_len, (PUINT_8 *) &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:%lx\n", rStatus); |
| #endif |
| } |
| if (wextSrchDesiredRoamingConsortiumIE(pucIEStart, sme->ie_len, (PUINT_8 *) &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:%lx\n", rStatus); |
| #endif |
| } |
| #endif /* CFG_SUPPORT_PASSPOINT */ |
| if (wextSrchDesiredWPAIE(pucIEStart, sme->ie_len, 0x30, (PUINT_8 *) &prDesiredIE)) { |
| RSN_INFO_T rRsnInfo; |
| |
| if (rsnParseRsnIE(prGlueInfo->prAdapter, (P_RSN_INFO_ELEM_T)prDesiredIE, &rRsnInfo)) { |
| if (rRsnInfo.u2RsnCap & ELEM_WPA_CAP_MFPC) { |
| 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 = 0; |
| } |
| } |
| } |
| |
| /* clear WSC Assoc IE buffer in case WPS IE is not detected */ |
| if (fgCarryWPSIE == FALSE) { |
| kalMemZero(&prGlueInfo->aucWSCAssocInfoIE, 200); |
| prGlueInfo->u2WSCAssocInfoIELen = 0; |
| } |
| |
| rStatus = kalIoctl(prGlueInfo, |
| wlanoidSetAuthMode, &eAuthMode, sizeof(eAuthMode), FALSE, FALSE, FALSE, &u4BufLen); |
| if (rStatus != WLAN_STATUS_SUCCESS) |
| DBGLOG(REQ, WARN, "set auth mode error:%lx\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; |
| /* printk("match AuthenticationSuite = 0x%x", u4AkmSuite); */ |
| } else { |
| prEntry->dot11RSNAConfigAuthenticationSuiteEnabled = FALSE; |
| } |
| } |
| |
| cipher = prGlueInfo->rWpaInfo.u4CipherGroup | prGlueInfo->rWpaInfo.u4CipherPairwise; |
| |
| if (1 /* prGlueInfo->rWpaInfo.fgPrivacyInvoke */) { |
| 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:%lx\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 */ |
| P_PARAM_WEP_T prWepKey = (P_PARAM_WEP_T) wepBuf; |
| |
| kalMemZero(prWepKey, sizeof(PARAM_WEP_T)); |
| prWepKey->u4Length = OFFSET_OF(PARAM_WEP_T, aucKeyMaterial) + sme->key_len; |
| prWepKey->u4KeyLength = (UINT_32) sme->key_len; |
| prWepKey->u4KeyIndex = (UINT_32) sme->key_idx; |
| prWepKey->u4KeyIndex |= IS_TRANSMIT_KEY; |
| if (prWepKey->u4KeyLength > MAX_KEY_LEN) { |
| DBGLOG(REQ, WARN, "Too long key length (%lu)\n", prWepKey->u4KeyLength); |
| 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%lx\n", rStatus); |
| return -EFAULT; |
| } |
| } |
| |
| rNewSsid.u4CenterFreq = sme->channel ? sme->channel->center_freq : 0; |
| rNewSsid.pucBssid = (UINT_8 *)sme->bssid; |
| rNewSsid.pucSsid = (UINT_8 *)sme->ssid; |
| rNewSsid.u4SsidLen = sme->ssid_len; |
| rStatus = kalIoctl(prGlueInfo, wlanoidSetConnect, (PVOID)&rNewSsid, sizeof(PARAM_CONNECT_T), |
| 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) { |
| P_CONNECTION_SETTINGS_T 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, |
| (PVOID) sme->bssid, MAC_ADDR_LEN, FALSE, FALSE, TRUE, FALSE, &u4BufLen); |
| |
| if (rStatus != WLAN_STATUS_SUCCESS) { |
| DBGLOG(REQ, WARN, "set BSSID:%lx\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, |
| (PVOID)&rNewSsid, sizeof(PARAM_SSID_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); |
| |
| if (rStatus != WLAN_STATUS_SUCCESS) { |
| DBGLOG(REQ, WARN, "set SSID:%lx\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) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| WLAN_STATUS rStatus; |
| UINT_32 u4BufLen; |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| rStatus = kalIoctl(prGlueInfo, wlanoidSetDisassociate, NULL, 0, FALSE, FALSE, TRUE, &u4BufLen); |
| |
| if (rStatus != WLAN_STATUS_SUCCESS) { |
| DBGLOG(REQ, WARN, "disassociate error:%lx\n", rStatus); |
| return -EFAULT; |
| } |
| |
| return 0; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @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) |
| { |
| PARAM_SSID_T rNewSsid; |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| UINT_32 u4ChnlFreq; /* Store channel or frequency information */ |
| UINT_32 u4BufLen = 0; |
| WLAN_STATUS rStatus; |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| /* 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 */ |
| kalMemCopy(rNewSsid.aucSsid, params->ssid, params->ssid_len); |
| rStatus = kalIoctl(prGlueInfo, |
| wlanoidSetSsid, (PVOID)&rNewSsid, sizeof(PARAM_SSID_T), FALSE, FALSE, TRUE, &u4BufLen); |
| |
| if (rStatus != WLAN_STATUS_SUCCESS) { |
| DBGLOG(REQ, WARN, "set SSID:%lx\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) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| WLAN_STATUS rStatus; |
| UINT_32 u4BufLen; |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| rStatus = kalIoctl(prGlueInfo, wlanoidSetDisassociate, NULL, 0, FALSE, FALSE, TRUE, &u4BufLen); |
| |
| if (rStatus != WLAN_STATUS_SUCCESS) { |
| DBGLOG(REQ, WARN, "disassociate error:%lx\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) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| WLAN_STATUS rStatus; |
| UINT_32 u4BufLen; |
| PARAM_POWER_MODE_T rPowerMode; |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| if (!prGlueInfo) |
| return -EFAULT; |
| |
| if (!prGlueInfo->prAdapter->prAisBssInfo) |
| return -EFAULT; |
| |
| if (enabled) { |
| if (timeout == -1) |
| rPowerMode.ePowerMode = Param_PowerModeFast_PSP; |
| else |
| rPowerMode.ePowerMode = Param_PowerModeMAX_PSP; |
| } else { |
| rPowerMode.ePowerMode = Param_PowerModeCAM; |
| } |
| |
| rPowerMode.ucBssIdx = prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex; |
| |
| rStatus = kalIoctl(prGlueInfo, |
| wlanoidSet802dot11PowerSaveProfile, |
| &rPowerMode, sizeof(PARAM_POWER_MODE_T), FALSE, FALSE, TRUE, &u4BufLen); |
| |
| if (rStatus != WLAN_STATUS_SUCCESS) { |
| DBGLOG(REQ, WARN, "set_power_mgmt error:%lx\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) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| WLAN_STATUS rStatus; |
| UINT_32 u4BufLen; |
| P_PARAM_PMKID_T prPmkid; |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| prPmkid = (P_PARAM_PMKID_T) kalMemAlloc(8 + sizeof(PARAM_BSSID_INFO_T), VIR_MEM_TYPE); |
| if (!prPmkid) { |
| DBGLOG(INIT, INFO, "Can not alloc memory for IW_PMKSA_ADD\n"); |
| return -ENOMEM; |
| } |
| |
| prPmkid->u4Length = 8 + sizeof(PARAM_BSSID_INFO_T); |
| 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(PARAM_PMKID_T), FALSE, FALSE, FALSE, &u4BufLen); |
| |
| if (rStatus != WLAN_STATUS_SUCCESS) |
| DBGLOG(INIT, INFO, "add pmkid error:%lx\n", rStatus); |
| kalMemFree(prPmkid, VIR_MEM_TYPE, 8 + sizeof(PARAM_BSSID_INFO_T)); |
| |
| 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) |
| { |
| |
| 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) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| WLAN_STATUS rStatus; |
| UINT_32 u4BufLen; |
| P_PARAM_PMKID_T prPmkid; |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| prPmkid = (P_PARAM_PMKID_T) kalMemAlloc(8, VIR_MEM_TYPE); |
| 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(PARAM_PMKID_T), FALSE, FALSE, FALSE, &u4BufLen); |
| |
| if (rStatus != WLAN_STATUS_SUCCESS) |
| DBGLOG(INIT, INFO, "flush pmkid error:%lx\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) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| UINT_32 u4BufLen; |
| P_PARAM_GTK_REKEY_DATA prGtkData; |
| WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; |
| INT_32 i4Rslt = -EINVAL; |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| /* if disable offload, we store key data here, and enable rekey offload when enter 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 = |
| (P_PARAM_GTK_REKEY_DATA) kalMemAlloc(sizeof(PARAM_GTK_REKEY_DATA), VIR_MEM_TYPE); |
| |
| if (!prGtkData) |
| return WLAN_STATUS_SUCCESS; |
| |
| DBGLOG(RSN, INFO, "cfg80211_set_rekey_data size( %d)\n", sizeof(*data)); |
| |
| DBGLOG(RSN, INFO, "kek\n"); |
| DBGLOG_MEM8(PF, ERROR, (PUINT_8)data->kek, NL80211_KEK_LEN); |
| DBGLOG(RSN, INFO, "kck\n"); |
| DBGLOG_MEM8(PF, ERROR, (PUINT_8)data->kck, NL80211_KCK_LEN); |
| DBGLOG(RSN, INFO, "replay count\n"); |
| DBGLOG_MEM8(PF, ERROR, (PUINT_8)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(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(PARAM_GTK_REKEY_DATA)); |
| return WLAN_STATUS_SUCCESS; |
| } |
| |
| prGtkData->u4KeyMgmt = prGlueInfo->rWpaInfo.u4KeyMgmt; |
| prGtkData->u4MgmtGroupCipher = 0; |
| |
| prGtkData->ucRekeyMode = GTK_REKEY_CMD_MODE_OFFLOAD_ON; |
| |
| rStatus = kalIoctl(prGlueInfo, |
| wlanoidSetGtkRekeyData, |
| prGtkData, sizeof(PARAM_GTK_REKEY_DATA), FALSE, FALSE, TRUE, &u4BufLen); |
| |
| if (rStatus != WLAN_STATUS_SUCCESS) |
| DBGLOG(INIT, INFO, "set GTK rekey data error:%lx\n", rStatus); |
| else |
| i4Rslt = 0; |
| |
| kalMemFree(prGtkData, VIR_MEM_TYPE, sizeof(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 |
| P_MSG_P2P_MGMT_FRAME_REGISTER_T prMgmtFrameRegister = (P_MSG_P2P_MGMT_FRAME_REGISTER_T) NULL; |
| #endif |
| P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; |
| |
| do { |
| |
| DBGLOG(INIT, TRACE, "mtk_cfg80211_mgmt_frame_register\n"); |
| |
| prGlueInfo = (P_GLUE_INFO_T) 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 = |
| (P_MSG_P2P_MGMT_FRAME_REGISTER_T) cnmMemAlloc(prGlueInfo->prAdapter, |
| RAM_TYPE_MSG, sizeof(MSG_P2P_MGMT_FRAME_REGISTER_T)); |
| |
| 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, (P_MSG_HDR_T) 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) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| INT_32 i4Rslt = -EINVAL; |
| P_MSG_REMAIN_ON_CHANNEL_T prMsgChnlReq = (P_MSG_REMAIN_ON_CHANNEL_T) NULL; |
| |
| do { |
| if ((wiphy == NULL) |
| || (wdev == NULL) |
| || (chan == NULL) |
| || (cookie == NULL)) { |
| break; |
| } |
| |
| prGlueInfo = (P_GLUE_INFO_T) 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(MSG_REMAIN_ON_CHANNEL_T)); |
| |
| 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, (P_MSG_HDR_T) 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) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| INT_32 i4Rslt = -EINVAL; |
| P_MSG_CANCEL_REMAIN_ON_CHANNEL_T prMsgChnlAbort = (P_MSG_CANCEL_REMAIN_ON_CHANNEL_T) NULL; |
| |
| do { |
| if ((wiphy == NULL) |
| || (wdev == NULL) |
| ) { |
| break; |
| } |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| prMsgChnlAbort = |
| cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_CANCEL_REMAIN_ON_CHANNEL_T)); |
| |
| 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, (P_MSG_HDR_T) 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) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| INT_32 i4Rslt = -EINVAL; |
| P_MSG_MGMT_TX_REQUEST_T prMsgTxReq = (P_MSG_MGMT_TX_REQUEST_T) NULL; |
| P_MSDU_INFO_T prMgmtFrame = (P_MSDU_INFO_T) NULL; |
| PUINT_8 pucFrameBuf = (PUINT_8) NULL; |
| |
| do { |
| if ((wiphy == NULL) || (wdev == NULL) || (params == 0) || (cookie == NULL)) |
| break; |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| *cookie = prGlueInfo->u8Cookie++; |
| |
| /* Channel & Channel Type & Wait time are ignored. */ |
| prMsgTxReq = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_MGMT_TX_REQUEST_T)); |
| |
| if (prMsgTxReq == NULL) { |
| ASSERT(FALSE); |
| i4Rslt = -ENOMEM; |
| break; |
| } |
| |
| prMsgTxReq->fgNoneCckRate = FALSE; |
| prMsgTxReq->fgIsWaitRsp = TRUE; |
| |
| prMgmtFrame = cnmMgtPktAlloc(prGlueInfo->prAdapter, (UINT_32) (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 = (PUINT_8) ((ULONG) prMgmtFrame->prPacket + MAC_TX_RESERVED_FIELD); |
| |
| kalMemCopy(pucFrameBuf, params->buf, params->len); |
| |
| prMgmtFrame->u2FrameLength = params->len; |
| |
| mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) 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) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| INT_32 i4Rslt = -EINVAL; |
| P_MSG_MGMT_TX_REQUEST_T prMsgTxReq = (P_MSG_MGMT_TX_REQUEST_T) NULL; |
| P_MSDU_INFO_T prMgmtFrame = (P_MSDU_INFO_T) NULL; |
| PUINT_8 pucFrameBuf = (PUINT_8) NULL; |
| |
| do { |
| if ((wiphy == NULL) |
| || (buf == NULL) |
| || (len == 0) |
| || (wdev == NULL) |
| || (cookie == NULL)) { |
| break; |
| } |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| *cookie = prGlueInfo->u8Cookie++; |
| |
| /* Channel & Channel Type & Wait time are ignored. */ |
| prMsgTxReq = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_MGMT_TX_REQUEST_T)); |
| |
| if (prMsgTxReq == NULL) { |
| ASSERT(FALSE); |
| i4Rslt = -ENOMEM; |
| break; |
| } |
| |
| prMsgTxReq->fgNoneCckRate = FALSE; |
| prMsgTxReq->fgIsWaitRsp = TRUE; |
| |
| prMgmtFrame = cnmMgtPktAlloc(prGlueInfo->prAdapter, (UINT_32) (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 = (PUINT_8) ((ULONG) prMgmtFrame->prPacket + MAC_TX_RESERVED_FIELD); |
| |
| kalMemCopy(pucFrameBuf, buf, len); |
| |
| prMgmtFrame->u2FrameLength = len; |
| |
| mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) 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) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| |
| prGlueInfo = (P_GLUE_INFO_T) 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) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| struct wpa_driver_hs20_data_s *prParams = NULL; |
| WLAN_STATUS rstatus = WLAN_STATUS_SUCCESS; |
| int fgIsValid = 0; |
| UINT_32 u4SetInfoLen = 0; |
| |
| ASSERT(wiphy); |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| |
| #if 1 |
| DBGLOG(INIT, INFO, "--> %s()\n", __func__); |
| #endif |
| |
| if (data && len) |
| prParams = (struct wpa_driver_hs20_data_s *)data; |
| |
| DBGLOG(INIT, INFO, "[%s] Cmd Type (%d)\n", __func__, prParams->CmdType); |
| |
| if (prParams) { |
| int i; |
| |
| switch (prParams->CmdType) { |
| case HS20_CMD_ID_SET_BSSID_POOL: |
| DBGLOG(INIT, INFO, |
| "[%s] fgBssidPoolIsEnable (%d)\n", __func__, |
| prParams->hs20_set_bssid_pool.fgBssidPoolIsEnable); |
| DBGLOG(INIT, INFO, |
| "[%s] ucNumBssidPool (%d)\n", __func__, prParams->hs20_set_bssid_pool.ucNumBssidPool); |
| |
| for (i = 0; i < prParams->hs20_set_bssid_pool.ucNumBssidPool; i++) { |
| DBGLOG(INIT, INFO, "[%s][%d][" MACSTR "]\n", __func__, 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(INIT, INFO, "[%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) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| P_NL80211_DRIVER_SET_KEY_EXTS prParams = (P_NL80211_DRIVER_SET_KEY_EXTS) NULL; |
| struct iw_encode_exts *prIWEncExt = (struct iw_encode_exts *)NULL; |
| WLAN_STATUS rstatus = WLAN_STATUS_SUCCESS; |
| int fgIsValid = 0; |
| UINT_32 u4BufLen = 0; |
| const UINT_8 aucBCAddr[] = BC_MAC_ADDR; |
| |
| P_PARAM_KEY_T prWpiKey = (P_PARAM_KEY_T) keyStructBuf; |
| |
| memset(keyStructBuf, 0, sizeof(keyStructBuf)); |
| |
| ASSERT(wiphy); |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| |
| #if 1 |
| DBGLOG(INIT, INFO, "--> %s()\n", __func__); |
| #endif |
| |
| if (data && len) |
| prParams = (P_NL80211_DRIVER_SET_KEY_EXTS) data; |
| |
| if (prParams) |
| 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) { |
| /* key id is out of range */ |
| /* printk(KERN_INFO "[wapi] add key error: key_id invalid %d\n", prWpiKey->ucKeyID); */ |
| return -EINVAL; |
| } |
| |
| if (prIWEncExt->key_len != 32) { |
| /* key length not valid */ |
| /* printk(KERN_INFO "[wapi] add key error: key_len invalid %d\n", prIWEncExt->key_len); */ |
| return -EINVAL; |
| } |
| 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(PARAM_KEY_T); |
| prWpiKey->ucBssIdx = prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex; |
| prWpiKey->ucCipher = CIPHER_SUITE_WPI; |
| |
| rstatus = kalIoctl(prGlueInfo, |
| wlanoidSetAddKey, prWpiKey, sizeof(PARAM_KEY_T), FALSE, FALSE, TRUE, &u4BufLen); |
| |
| if (rstatus != WLAN_STATUS_SUCCESS) { |
| /* printk(KERN_INFO "[wapi] add key error:%lx\n", rStatus); */ |
| fgIsValid = -EFAULT; |
| } |
| |
| } |
| return fgIsValid; |
| } |
| #endif |
| |
| int |
| mtk_cfg80211_testmode_get_sta_statistics(IN struct wiphy *wiphy, IN void *data, IN int len, IN P_GLUE_INFO_T prGlueInfo) |
| { |
| WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; |
| UINT_32 u4BufLen; |
| UINT_32 u4LinkScore; |
| UINT_32 u4TotalError; |
| UINT_32 u4TxExceedThresholdCount; |
| UINT_32 u4TxTotalCount; |
| |
| P_NL80211_DRIVER_GET_STA_STATISTICS_PARAMS prParams = NULL; |
| PARAM_GET_STA_STA_STATISTICS rQueryStaStatistics; |
| struct sk_buff *skb; |
| |
| ASSERT(wiphy); |
| ASSERT(prGlueInfo); |
| |
| if (data && len) |
| prParams = (P_NL80211_DRIVER_GET_STA_STATISTICS_PARAMS) data; |
| |
| if (!prParams->aucMacAddr) { |
| DBGLOG(QM, TRACE, "%s MAC Address is NULL\n", __func__); |
| return -EINVAL; |
| } |
| |
| skb = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(PARAM_GET_STA_STA_STATISTICS) + 1); |
| |
| if (!skb) { |
| DBGLOG(QM, TRACE, "%s allocate skb failed:%lx\n", __func__, rStatus); |
| return -ENOMEM; |
| } |
| DBGLOG(QM, TRACE, "Get [" MACSTR "] STA statistics\n", MAC2STR(prParams->aucMacAddr)); |
| |
| 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; |
| { |
| u8 __tmp = u4LinkScore; |
| |
| if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_LINK_SCORE, 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 = rQueryStaStatistics.u4Flag; |
| |
| if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_FLAG, 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; |
| } |
| |
| /* 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; |
| |
| /* 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_sw_cmd(IN struct wiphy *wiphy, IN void *data, IN int len) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| P_NL80211_DRIVER_SW_CMD_PARAMS prParams = (P_NL80211_DRIVER_SW_CMD_PARAMS) NULL; |
| WLAN_STATUS rstatus = WLAN_STATUS_SUCCESS; |
| int fgIsValid = 0; |
| UINT_32 u4SetInfoLen = 0; |
| |
| ASSERT(wiphy); |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| |
| #if 1 |
| DBGLOG(INIT, INFO, "--> %s()\n", __func__); |
| #endif |
| |
| if (data && len) |
| prParams = (P_NL80211_DRIVER_SW_CMD_PARAMS) data; |
| |
| if (prParams) { |
| if (prParams->set == 1) { |
| rstatus = kalIoctl(prGlueInfo, |
| (PFN_OID_HANDLER_FUNC) wlanoidSetSwCtrlWrite, |
| &prParams->adr, (UINT_32) 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) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| P_NL80211_DRIVER_TEST_MODE_PARAMS prParams = NULL; |
| INT_32 i4Status; |
| |
| ASSERT(wiphy); |
| DBGLOG(INIT, INFO, "-->%s()\n", __func__); |
| |
| 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 = (P_GLUE_INFO_T)wiphy_priv(wiphy); |
| prParams = (P_NL80211_DRIVER_TEST_MODE_PARAMS)data; |
| |
| /* Clear the version byte */ |
| prParams->index = prParams->index & ~BITS(24, 31); |
| |
| 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; |
| |
| #if CFG_SUPPORT_PASSPOINT |
| case TESTMODE_CMD_ID_HS20: |
| i4Status = mtk_cfg80211_testmode_hs20_cmd(wiphy, data, len); |
| break; |
| #endif /* CFG_SUPPORT_PASSPOINT */ |
| |
| 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 |
| |
| int |
| mtk_cfg80211_sched_scan_start(IN struct wiphy *wiphy, |
| IN struct net_device *ndev, IN struct cfg80211_sched_scan_request *request) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| WLAN_STATUS rStatus; |
| UINT_32 i, u4BufLen; |
| P_PARAM_SCHED_SCAN_REQUEST prSchedScanRequest; |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| /* check if there is any pending scan/sched_scan not yet finished */ |
| if (prGlueInfo->prScanRequest != NULL || prGlueInfo->prSchedScanRequest != NULL) { |
| DBGLOG(SCN, INFO, "(prGlueInfo->prScanRequest != NULL || prGlueInfo->prSchedScanRequest != NULL)\n"); |
| return -EBUSY; |
| } else if (request == NULL || request->n_match_sets > CFG_SCAN_SSID_MATCH_MAX_NUM) { |
| DBGLOG(SCN, INFO, "(request == NULL || request->n_match_sets > CFG_SCAN_SSID_MATCH_MAX_NUM)\n"); |
| /* invalid scheduled scan request */ |
| return -EINVAL; |
| } else if (!request->n_ssids || !request->n_match_sets) { |
| /* invalid scheduled scan request */ |
| return -EINVAL; |
| } |
| |
| prSchedScanRequest = (P_PARAM_SCHED_SCAN_REQUEST) kalMemAlloc(sizeof(PARAM_SCHED_SCAN_REQUEST), VIR_MEM_TYPE); |
| if (prSchedScanRequest == NULL) { |
| DBGLOG(SCN, INFO, "(prSchedScanRequest == NULL) kalMemAlloc fail\n"); |
| return -ENOMEM; |
| } |
| |
| prSchedScanRequest->u4SsidNum = request->n_match_sets; |
| for (i = 0; i < request->n_match_sets; i++) { |
| if (request->match_sets == NULL || &(request->match_sets[i]) == NULL) { |
| prSchedScanRequest->arSsid[i].u4SsidLen = 0; |
| } else { |
| COPY_SSID(prSchedScanRequest->arSsid[i].aucSsid, |
| prSchedScanRequest->arSsid[i].u4SsidLen, |
| request->match_sets[i].ssid.ssid, request->match_sets[i].ssid.ssid_len); |
| } |
| } |
| |
| prSchedScanRequest->u4IELength = request->ie_len; |
| if (request->ie_len > 0) |
| prSchedScanRequest->pucIE = (PUINT_8) (request->ie); |
| |
| #if KERNEL_VERSION(4, 4, 0) <= CFG80211_VERSION_CODE |
| prSchedScanRequest->u2ScanInterval = (UINT_16) (request->scan_plans->interval); |
| #else |
| prSchedScanRequest->u2ScanInterval = (UINT_16) (request->interval); |
| #endif |
| rStatus = kalIoctl(prGlueInfo, |
| wlanoidSetStartSchedScan, |
| prSchedScanRequest, sizeof(PARAM_SCHED_SCAN_REQUEST), FALSE, FALSE, TRUE, &u4BufLen); |
| |
| kalMemFree(prSchedScanRequest, VIR_MEM_TYPE, sizeof(PARAM_SCHED_SCAN_REQUEST)); |
| |
| if (rStatus != WLAN_STATUS_SUCCESS) { |
| DBGLOG(REQ, WARN, "scheduled scan error:%lx\n", rStatus); |
| return -EINVAL; |
| } |
| |
| prGlueInfo->prSchedScanRequest = request; |
| |
| return 0; |
| } |
| |
| int mtk_cfg80211_sched_scan_stop(IN struct wiphy *wiphy, IN struct net_device *ndev) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| WLAN_STATUS rStatus; |
| UINT_32 u4BufLen; |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| /* check if there is any pending scan/sched_scan not yet finished */ |
| if (prGlueInfo->prSchedScanRequest == NULL) |
| return -EBUSY; |
| |
| rStatus = kalIoctl(prGlueInfo, wlanoidSetStopSchedScan, NULL, 0, FALSE, FALSE, TRUE, &u4BufLen); |
| |
| if (rStatus == WLAN_STATUS_FAILURE) { |
| DBGLOG(REQ, WARN, "scheduled scan error:%lx\n", rStatus); |
| return -EINVAL; |
| } |
| |
| return 0; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @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) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| PARAM_MAC_ADDRESS arBssid; |
| #if CFG_SUPPORT_PASSPOINT |
| PUINT_8 prDesiredIE = NULL; |
| #endif /* CFG_SUPPORT_PASSPOINT */ |
| WLAN_STATUS rStatus; |
| UINT_32 u4BufLen; |
| |
| prGlueInfo = (P_GLUE_INFO_T) 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, 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; |
| } |
| |
| if (req->ie && req->ie_len > 0) { |
| #if CFG_SUPPORT_PASSPOINT |
| if (wextSrchDesiredHS20IE((PUINT_8) req->ie, req->ie_len, (PUINT_8 *) &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:%lx\n", rStatus)); |
| */ |
| } |
| } |
| |
| if (wextSrchDesiredInterworkingIE((PUINT_8) req->ie, req->ie_len, (PUINT_8 *) &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:%lx\n", rStatus)); |
| */ |
| } |
| } |
| |
| if (wextSrchDesiredRoamingConsortiumIE((PUINT_8) req->ie, req->ie_len, (PUINT_8 *) &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:%lx\n", rStatus)); |
| */ |
| } |
| } |
| #endif /* CFG_SUPPORT_PASSPOINT */ |
| } |
| |
| rStatus = kalIoctl(prGlueInfo, |
| wlanoidSetBssid, (PVOID) req->bss->bssid, MAC_ADDR_LEN, FALSE, FALSE, TRUE, &u4BufLen); |
| |
| if (rStatus != WLAN_STATUS_SUCCESS) { |
| DBGLOG(REQ, WARN, "set BSSID:%lx\n", rStatus); |
| return -EINVAL; |
| } |
| |
| 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 P_GLUE_INFO_T prGlueInfo) |
| { |
| #define NL80211_TESTMODE_P2P_SCANDONE_INVALID 0 |
| #define NL80211_TESTMODE_P2P_SCANDONE_STATUS 1 |
| |
| #ifdef CONFIG_NL80211_TESTMODE |
| WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; |
| INT_32 i4Status = -EINVAL, READY_TO_BEAM = 0; |
| |
| struct sk_buff *skb = NULL; |
| |
| ASSERT(wiphy); |
| ASSERT(prGlueInfo); |
| |
| skb = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(UINT_32)); |
| |
| /* 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:%lx\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); |
| goto nla_put_failure; |
| } |
| } |
| { |
| u32 __tmp = READY_TO_BEAM; |
| |
| if (unlikely(nla_put(skb, NL80211_TESTMODE_P2P_SCANDONE_STATUS, sizeof(u32), &__tmp) < 0)) { |
| kfree_skb(skb); |
| goto nla_put_failure; |
| } |
| } |
| |
| i4Status = cfg80211_testmode_reply(skb); |
| |
| nla_put_failure: |
| return i4Status; |
| |
| #else |
| DBGLOG(QM, WARN, "CONFIG_NL80211_TESTMODE not enabled\n"); |
| return -EINVAL; |
| #endif |
| |
| } |
| |
| #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() */ |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| CMD_PEER_UPDATE_T rCmdUpdate; |
| WLAN_STATUS rStatus; |
| UINT_32 u4BufLen, u4Temp; |
| ADAPTER_T *prAdapter; |
| P_BSS_INFO_T prAisBssInfo; |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| /* make up command */ |
| |
| prAdapter = prGlueInfo->prAdapter; |
| prAisBssInfo = prAdapter->prAisBssInfo; |
| |
| if (params == NULL) |
| return 0; |
| else if (params->supported_rates == NULL) |
| return 0; |
| |
| /* init */ |
| kalMemZero(&rCmdUpdate, sizeof(rCmdUpdate)); |
| kalMemCopy(rCmdUpdate.aucPeerMac, mac, 6); |
| |
| 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; |
| } |
| |
| /* |
| * 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->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 */ |
| } |
| |
| /* 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(CMD_PEER_UPDATE_T), 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(CMD_TDLS_CH_SW_T), 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() */ |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| CMD_PEER_UPDATE_T rCmdUpdate; |
| WLAN_STATUS rStatus; |
| UINT_32 u4BufLen, u4Temp; |
| ADAPTER_T *prAdapter; |
| P_BSS_INFO_T prAisBssInfo; |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| /* make up command */ |
| |
| prAdapter = prGlueInfo->prAdapter; |
| prAisBssInfo = prAdapter->prAisBssInfo; |
| |
| if (params == NULL) |
| return 0; |
| else if (params->supported_rates == NULL) |
| return 0; |
| |
| /* init */ |
| kalMemZero(&rCmdUpdate, sizeof(rCmdUpdate)); |
| kalMemCopy(rCmdUpdate.aucPeerMac, mac, 6); |
| |
| 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; |
| } |
| |
| /* |
| * 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->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 */ |
| } |
| |
| /* 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(CMD_PEER_UPDATE_T), 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(CMD_TDLS_CH_SW_T), 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() */ |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| CMD_PEER_ADD_T rCmdCreate; |
| ADAPTER_T *prAdapter; |
| WLAN_STATUS rStatus; |
| UINT_32 u4BufLen; |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| /* 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(CMD_PEER_ADD_T), 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() */ |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| CMD_PEER_ADD_T rCmdCreate; |
| ADAPTER_T *prAdapter; |
| WLAN_STATUS rStatus; |
| UINT_32 u4BufLen; |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| /* 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(CMD_PEER_ADD_T), 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; |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| ADAPTER_T *prAdapter; |
| STA_RECORD_T *prStaRec; |
| u8 deleteMac[MAC_ADDR_LEN]; |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| 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, (UINT_8) 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() */ |
| |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| ADAPTER_T *prAdapter; |
| STA_RECORD_T *prStaRec; |
| u8 deleteMac[MAC_ADDR_LEN]; |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| 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, (UINT_8) 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() */ |
| |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| ADAPTER_T *prAdapter; |
| STA_RECORD_T *prStaRec; |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| prAdapter = prGlueInfo->prAdapter; |
| |
| prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) 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) |
| { |
| GLUE_INFO_T *prGlueInfo; |
| TDLS_CMD_LINK_MGT_T rCmdMgt; |
| UINT_32 u4BufLen; |
| |
| /* sanity check */ |
| if ((wiphy == NULL) || (peer == NULL) || (buf == NULL)) |
| return -EINVAL; |
| |
| /* init */ |
| prGlueInfo = (GLUE_INFO_T *) 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); |
| kalMemCopy(&(rCmdMgt.aucSecBuf), buf, len); |
| |
| kalIoctl(prGlueInfo, TdlsexLinkMgt, &rCmdMgt, sizeof(TDLS_CMD_LINK_MGT_T), 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) |
| { |
| GLUE_INFO_T *prGlueInfo; |
| TDLS_CMD_LINK_MGT_T rCmdMgt; |
| UINT_32 u4BufLen; |
| |
| /* sanity check */ |
| if ((wiphy == NULL) || (peer == NULL) || (buf == NULL)) |
| return -EINVAL; |
| |
| /* init */ |
| prGlueInfo = (GLUE_INFO_T *) 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); |
| kalMemCopy(&(rCmdMgt.aucSecBuf), buf, len); |
| |
| kalIoctl(prGlueInfo, TdlsexLinkMgt, &rCmdMgt, sizeof(TDLS_CMD_LINK_MGT_T), 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) |
| { |
| GLUE_INFO_T *prGlueInfo; |
| TDLS_CMD_LINK_MGT_T rCmdMgt; |
| UINT_32 u4BufLen; |
| |
| /* sanity check */ |
| if ((wiphy == NULL) || (peer == NULL) || (buf == NULL)) |
| return -EINVAL; |
| |
| /* init */ |
| prGlueInfo = (GLUE_INFO_T *) 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"); |
| else |
| kalMemCopy(&(rCmdMgt.aucSecBuf), buf, len); |
| |
| kalIoctl(prGlueInfo, TdlsexLinkMgt, &rCmdMgt, sizeof(TDLS_CMD_LINK_MGT_T), 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) |
| { |
| |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| UINT_32 u4BufLen; |
| ADAPTER_T *prAdapter; |
| TDLS_CMD_LINK_OPER_T rCmdOper; |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| prAdapter = prGlueInfo->prAdapter; |
| |
| kalMemZero(&rCmdOper, sizeof(rCmdOper)); |
| kalMemCopy(rCmdOper.aucPeerMac, peer, 6); |
| |
| rCmdOper.oper = oper; |
| |
| kalIoctl(prGlueInfo, TdlsexLinkOper, &rCmdOper, sizeof(TDLS_CMD_LINK_OPER_T), FALSE, FALSE, FALSE, |
| /* FALSE, //6628 -> 6630 fgIsP2pOid-> x */ |
| &u4BufLen); |
| return 0; |
| } |
| #else |
| int mtk_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, u8 *peer, enum nl80211_tdls_operation oper) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| UINT_32 u4BufLen; |
| ADAPTER_T *prAdapter; |
| TDLS_CMD_LINK_OPER_T rCmdOper; |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| prAdapter = prGlueInfo->prAdapter; |
| |
| kalMemZero(&rCmdOper, sizeof(rCmdOper)); |
| kalMemCopy(rCmdOper.aucPeerMac, peer, 6); |
| |
| rCmdOper.oper = oper; |
| |
| kalIoctl(prGlueInfo, TdlsexLinkOper, &rCmdOper, sizeof(TDLS_CMD_LINK_OPER_T), FALSE, FALSE, FALSE, |
| /* FALSE, //6628 -> 6630 fgIsP2pOid-> x */ |
| &u4BufLen); |
| return 0; |
| } |
| #endif |
| #endif |
| #if (CFG_SUPPORT_SINGLE_SKU == 1) |
| |
| #if (CFG_BUILT_IN_DRIVER == 0) |
| bool is_world_regdom(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, "regd_state_machine: SET_BY_COUNTRY_IE\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); |
| } |
| |
| void |
| mtk_reg_notify(IN struct wiphy *pWiphy, |
| IN struct regulatory_request *pRequest) |
| { |
| P_GLUE_INFO_T prGlueInfo; |
| P_ADAPTER_T prAdapter; |
| u8 send_cmd_request = 0; |
| enum regd_state old_state; |
| |
| |
| if (!pWiphy) { |
| DBGLOG(RLM, ERROR, "%s(): pWiphy = NULL.\n", __func__); |
| return; |
| } |
| |
| if (g_u4HaltFlag) { |
| DBGLOG(RLM, WARN, "wlan is halt, skip reg callback\n"); |
| return; |
| } |
| |
| /* |
| * 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 (rlmDomainIsCtrlStateEqualTo(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", |
| rlmDomainGetCtrlState()); |
| return; |
| } |
| } else if ((rlmDomainIsCtrlStateEqualTo(REGD_STATE_SET_WW_CORE)) |
| || (rlmDomainIsCtrlStateEqualTo(REGD_STATE_SET_COUNTRY_USER)) |
| || (rlmDomainIsCtrlStateEqualTo(REGD_STATE_SET_COUNTRY_DRIVER))) { |
| |
| send_cmd_request = 1; |
| |
| goto DOMAIN_SEND_CMD; |
| } else { |
| DBGLOG(RLM, ERROR, "Invalid REG state happened. state = 0x%x\n", rlmDomainGetCtrlState()); |
| 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*/ |
| |
| |
| /* |
| * State machine transition |
| */ |
| DBGLOG(RLM, INFO, "request->alpha2=%s, initiator=%x, intersect=%d\n", |
| pRequest->alpha2, pRequest->initiator, pRequest->intersect); |
| |
| old_state = rlmDomainGetCtrlState(); |
| 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); |
| #if 0 |
| return; /*error state*/ |
| #endif |
| } |
| |
| /* |
| * 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 = %s\n", |
| __func__, rlmDomainGetCountryCode()); |
| |
| rlmDomainAssert(0); |
| return; |
| } |
| |
| |
| mtk_apply_custom_regulatory(pWiphy, pRegdom); |
| } |
| |
| |
| /* |
| * Parsing channels |
| */ |
| if (send_cmd_request) |
| rlmDomainParsingChannel(rlmDomainGetRefWiphy()); |
| else |
| rlmDomainParsingChannel(pWiphy);/*real regd update*/ |
| |
| |
| /* |
| * Always use the wlan GlueInfo as parameter, |
| * because P2P stores it as a different way |
| * and I do not want to make a detection about |
| * which wiphy, wlan wiphy or p2p wiphy is. |
| */ |
| |
| prGlueInfo = rlmDomainGetGlueInfo(); |
| |
| /* |
| * Prepare to send channel information to firmware |
| */ |
| if (!prGlueInfo) |
| return; /*interface is not up yet.*/ |
| |
| prAdapter = prGlueInfo->prAdapter; |
| if (!prAdapter) |
| return; /*interface is not up yet.*/ |
| |
| |
| /* |
| * Check if firmawre support single sku |
| */ |
| if (!regd_is_single_sku_en()) |
| return; /*no need to send information to firmware due to firmware is not supported*/ |
| |
| |
| /* |
| * Send commands to firmware |
| */ |
| prAdapter->rWifiVar.rConnSettings.u2CountryCode = (UINT_16)rlmDomainGetCountryCode(); |
| rlmDomainSendCmd(prAdapter, FALSE); |
| } |
| |
| void |
| cfg80211_regd_set_wiphy(IN struct wiphy *prWiphy) |
| { |
| /* |
| * register callback |
| */ |
| prWiphy->reg_notifier = mtk_reg_notify; |
| |
| |
| /* |
| * 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; |
| #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()); |
| #endif |
| |
| |
| /* |
| * Initialize regd control information |
| */ |
| rlmDomainResetCtrlInfo(); |
| } |
| |
| #else |
| void |
| cfg80211_regd_set_wiphy(IN struct wiphy *prWiphy) |
| { |
| } |
| #endif |
| |
| int mtk_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow) |
| { |
| P_GLUE_INFO_T prGlueInfo; |
| ADAPTER_T *prAdapter; |
| UINT_32 u4BufLen; |
| WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; |
| |
| DBGLOG(REQ, INFO, "CFG80211 suspend CB\n"); |
| if (!wlanGetGlueInfo()) { |
| DBGLOG(REQ, ERROR, "NIC does not exist!\n"); |
| return 0; |
| } |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| prAdapter = prGlueInfo->prAdapter; |
| |
| DBGLOG(REQ, WARN, "Wow:%d, WowEnable:%d, state:%d\n", |
| prGlueInfo->prAdapter->rWifiVar.ucWow, prGlueInfo->prAdapter->rWowCtrl.fgWowEnable, |
| kalGetMediaStateIndicated(prGlueInfo)); |
| |
| /* 1) wifi cfg "Wow" must be true, 2) wow is disable 3) WIfI connected => execute link down flow */ |
| if (prGlueInfo->prAdapter->rWifiVar.ucWow && !prGlueInfo->prAdapter->rWowCtrl.fgWowEnable) { |
| if (kalGetMediaStateIndicated(prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { |
| DBGLOG(REQ, WARN, "CFG80211 suspend link down\n"); |
| rStatus = kalIoctl(prGlueInfo, wlanoidLinkDown, NULL, 0, TRUE, FALSE, FALSE, &u4BufLen); |
| } |
| } |
| |
| if (rStatus != WLAN_STATUS_SUCCESS) { |
| DBGLOG(REQ, WARN, "cfg 80211 suspend fail!\n"); |
| return -EINVAL; |
| } |
| return 0; |
| } |
| |