import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / misc / mediatek / connectivity / combo / drv_wlan / mt6620 / wlan / os / linux / gl_cfg80211.c
diff --git a/drivers/misc/mediatek/connectivity/combo/drv_wlan/mt6620/wlan/os/linux/gl_cfg80211.c b/drivers/misc/mediatek/connectivity/combo/drv_wlan/mt6620/wlan/os/linux/gl_cfg80211.c
new file mode 100644 (file)
index 0000000..4163e8f
--- /dev/null
@@ -0,0 +1,1375 @@
+/*
+** $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.
+*/
+
+
+
+/*
+** $Log: gl_cfg80211.c $
+**
+** 09 12 2012 wcpadmin
+** [ALPS00276400] Remove MTK copyright and legal header on GPL/LGPL related packages
+** .
+**
+** 11 23 2012 yuche.tsai
+** [ALPS00398671] [Acer-Tablet] Remove Wi-Fi Direct completely
+** Fix bug of WiFi may reboot under user load, when WiFi Direct is removed..
+**
+** 08 29 2012 chinglan.wang
+** [ALPS00349655] [Need Patch] [Volunteer Patch] [ALPS.JB] Daily build warning on [mt6575_phone_mhl-eng]
+** .
+ *
+**
+*/
+
+/*******************************************************************************
+*                         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"
+
+/*******************************************************************************
+*                              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
+********************************************************************************
+*/
+
+#if CFG_SUPPORT_WAPI
+extern UINT_8 keyStructBuf[1024];      /* add/remove key shared buffer */
+#else
+extern UINT_8 keyStructBuf[100];       /* add/remove key shared buffer */
+#endif
+
+/*******************************************************************************
+*                           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, FALSE, &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;
+#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];
+       UINT_8 tmp2[8];
+
+       prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy);
+       ASSERT(prGlueInfo);
+
+       kalMemZero(&rKey, sizeof(PARAM_KEY_T));
+
+       rKey.u4KeyIndex = key_index;
+
+       if (mac_addr) {
+               COPY_MAC_ADDR(rKey.arBSSID, mac_addr);
+               if ((rKey.arBSSID[0] == 0x00) && (rKey.arBSSID[1] == 0x00)
+                   && (rKey.arBSSID[2] == 0x00) && (rKey.arBSSID[3] == 0x00)
+                   && (rKey.arBSSID[4] == 0x00) && (rKey.arBSSID[5] == 0x00)) {
+                       rKey.arBSSID[0] = 0xff;
+                       rKey.arBSSID[1] = 0xff;
+                       rKey.arBSSID[2] = 0xff;
+                       rKey.arBSSID[3] = 0xff;
+                       rKey.arBSSID[4] = 0xff;
+                       rKey.arBSSID[5] = 0xff;
+               }
+               if (rKey.arBSSID[0] != 0xFF) {
+                       rKey.u4KeyIndex |= BIT(31);
+                       if ((rKey.arBSSID[0] != 0x00) || (rKey.arBSSID[1] != 0x00)
+                           || (rKey.arBSSID[2] != 0x00) || (rKey.arBSSID[3] != 0x00)
+                           || (rKey.arBSSID[4] != 0x00) || (rKey.arBSSID[5] != 0x00))
+                               rKey.u4KeyIndex |= BIT(30);
+               }
+       } else {
+               rKey.arBSSID[0] = 0xff;
+               rKey.arBSSID[1] = 0xff;
+               rKey.arBSSID[2] = 0xff;
+               rKey.arBSSID[3] = 0xff;
+               rKey.arBSSID[4] = 0xff;
+               rKey.arBSSID[5] = 0xff;
+               /* rKey.u4KeyIndex |= BIT(31); //Enable BIT 31 will make tx use bc key id, should use pairwise key id 0 */
+       }
+
+       if (params->key) {
+               /* rKey.aucKeyMaterial[0] = kalMemAlloc(params->key_len, VIR_MEM_TYPE); */
+               kalMemCopy(rKey.aucKeyMaterial, params->key, params->key_len);
+               if (params->key_len == 32) {
+                       kalMemCopy(tmp1, &params->key[16], 8);
+                       kalMemCopy(tmp2, &params->key[24], 8);
+                       kalMemCopy(&rKey.aucKeyMaterial[16], tmp2, 8);
+                       kalMemCopy(&rKey.aucKeyMaterial[24], tmp1, 8);
+               }
+       }
+
+       rKey.u4KeyLength = params->key_len;
+       rKey.u4Length = ((UINT_32) &(((P_P2P_PARAM_KEY_T) 0)->aucKeyMaterial)) + rKey.u4KeyLength;
+
+       rStatus = kalIoctl(prGlueInfo,
+                          wlanoidSetAddKey,
+                          &rKey, rKey.u4Length, FALSE, FALSE, TRUE, FALSE, &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
+       printk("--> %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);
+
+       kalMemZero(&rRemoveKey, sizeof(PARAM_REMOVE_KEY_T));
+       if (mac_addr)
+               COPY_MAC_ADDR(rRemoveKey.arBSSID, mac_addr);
+       rRemoveKey.u4KeyIndex = key_index;
+       rRemoveKey.u4Length = sizeof(PARAM_REMOVE_KEY_T);
+
+
+       rStatus = kalIoctl(prGlueInfo,
+                          wlanoidSetRemoveKey,
+                          &rRemoveKey, rRemoveKey.u4Length, FALSE, FALSE, TRUE, FALSE, &u4BufLen);
+
+       if (rStatus != WLAN_STATUS_SUCCESS) {
+               DBGLOG(REQ, 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;
+
+       prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy);
+       ASSERT(prGlueInfo);
+
+       printk("--> %s()\n", __func__);
+       /*work around aosp defualt supplicant fail */
+       return WLAN_STATUS_SUCCESS;
+
+}
+
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * @brief This routine is responsible for getting station information such as RSSI
+ *
+ * @param
+ *
+ * @retval 0:       successful
+ *         others:  failure
+ */
+/*----------------------------------------------------------------------------*/
+
+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;
+
+       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 */
+       rStatus = kalIoctl(prGlueInfo,
+                          wlanoidQueryLinkSpeed,
+                          &u4Rate, sizeof(u4Rate), TRUE, FALSE, FALSE, FALSE, &u4BufLen);
+
+       if (rStatus != WLAN_STATUS_SUCCESS) {
+               DBGLOG(REQ, WARN, ("unable to retrieve link speed\n"));
+       } else {
+               sinfo->filled |= STATION_INFO_TX_BITRATE;
+               sinfo->txrate.legacy = u4Rate / 1000;   /* convert from 100bps to 100kbps */
+       }
+
+       if (prGlueInfo->eParamMediaStateIndicated != PARAM_MEDIA_STATE_CONNECTED) {
+               /* not connected */
+               DBGLOG(REQ, WARN, ("not yet connected\n"));
+       } else {
+               /* 3. fill RSSI */
+               rStatus = kalIoctl(prGlueInfo,
+                                  wlanoidQueryRssi,
+                                  &i4Rssi, sizeof(i4Rssi), TRUE, FALSE, FALSE, FALSE, &u4BufLen);
+
+               if (rStatus != WLAN_STATUS_SUCCESS) {
+                       DBGLOG(REQ, WARN, ("unable to retrieve link speed\n"));
+               } else {
+                       sinfo->filled |= STATION_INFO_SIGNAL;
+                       /* in the cfg80211 layer, the signal is a signed char variable. */
+                       if (i4Rssi < -128)
+                               sinfo->signal = -128;
+                       else
+                               sinfo->signal = i4Rssi; /* dBm */
+               }
+       }
+
+       sinfo->rx_packets = prGlueInfo->rNetDevStats.rx_packets;
+       sinfo->filled |= STATION_INFO_TX_PACKETS;
+       sinfo->tx_packets = prGlueInfo->rNetDevStats.tx_packets;
+       sinfo->filled |= STATION_INFO_TX_FAILED;
+
+#if 1
+       {
+               WLAN_STATUS rStatus;
+               UINT_32 u4XmitError = 0;
+/* UINT_32 u4XmitOk = 0; */
+/* UINT_32 u4RecvError = 0; */
+/* UINT_32 u4RecvOk = 0; */
+/* UINT_32 u4BufLen; */
+
+               /* @FIX ME: need a more clear way to do this */
+
+
+               rStatus = kalIoctl(prGlueInfo,
+                                  wlanoidQueryXmitError,
+                                  &u4XmitError,
+                                  sizeof(UINT_32), TRUE, TRUE, TRUE, FALSE, &u4BufLen);
+
+               prGlueInfo->rNetDevStats.tx_errors = u4XmitError;
+
+       }
+#else
+       prGlueInfo->rNetDevStats.tx_errors = 0;
+#endif
+
+       sinfo->tx_failed = prGlueInfo->rNetDevStats.tx_errors;
+
+       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,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
+                     struct net_device *ndev,
+#endif
+                     struct cfg80211_scan_request *request)
+{
+       P_GLUE_INFO_T prGlueInfo = NULL;
+       WLAN_STATUS rStatus;
+       UINT_32 u4BufLen;
+       PARAM_SCAN_REQUEST_EXT_T rScanRequest;
+
+       prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy);
+       ASSERT(prGlueInfo);
+
+       kalMemZero(&rScanRequest, sizeof(PARAM_SCAN_REQUEST_EXT_T));
+
+       /* check if there is any pending scan not yet finished */
+       if (prGlueInfo->prScanRequest != NULL) {
+               return -EBUSY;
+       }
+
+       if (request->n_ssids == 0) {
+               rScanRequest.rSsid.u4SsidLen = 0;
+       } else if (request->n_ssids == 1) {
+               COPY_SSID(rScanRequest.rSsid.aucSsid, rScanRequest.rSsid.u4SsidLen,
+                         request->ssids[0].ssid, request->ssids[0].ssid_len);
+       } else {
+               return -EINVAL;
+       }
+
+       if (request->ie_len > 0) {
+               rScanRequest.u4IELength = request->ie_len;
+               rScanRequest.pucIE = (PUINT_8) (request->ie);
+       } else {
+               rScanRequest.u4IELength = 0;
+       }
+
+       rStatus = kalIoctl(prGlueInfo,
+                          wlanoidSetBssidListScanExt,
+                          &rScanRequest,
+                          sizeof(PARAM_SCAN_REQUEST_EXT_T), FALSE, 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_SSID_T rNewSsid;
+       BOOLEAN fgCarryWPSIE = FALSE;
+       ENUM_PARAM_OP_MODE_T eOpMode;
+
+       prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy);
+       ASSERT(prGlueInfo);
+
+       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, FALSE, &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_802_11W
+       prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED;
+#endif
+
+       if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+               prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_WPA;
+       else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+               prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_WPA2;
+       else
+               prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED;
+
+       switch (sme->auth_type) {
+       case NL80211_AUTHTYPE_OPEN_SYSTEM:
+               prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM;
+               break;
+       case NL80211_AUTHTYPE_SHARED_KEY:
+               prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_SHARED_KEY;
+               break;
+       default:
+               prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM | IW_AUTH_ALG_SHARED_KEY;
+               break;
+       }
+
+       if (sme->crypto.n_ciphers_pairwise) {
+               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;
+               }
+       }
+
+       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;
+                               break;
+                       case WLAN_AKM_SUITE_PSK:
+                               eAuthMode = AUTH_MODE_WPA_PSK;
+                               break;
+                       default:
+                               DBGLOG(REQ, WARN, ("invalid cipher group (%d)\n",
+                                                  sme->crypto.cipher_group));
+                               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;
+                               break;
+                       case WLAN_AKM_SUITE_PSK:
+                               eAuthMode = AUTH_MODE_WPA2_PSK;
+                               break;
+                       default:
+                               DBGLOG(REQ, WARN, ("invalid cipher group (%d)\n",
+                                                  sme->crypto.cipher_group));
+                               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->prAdapter->rWifiVar.rConnSettings.fgWapiMode = FALSE; */
+       /* prGlueInfo->prAdapter->prGlueInfo->u2WapiAssocInfoIESz = 0; */
+       prGlueInfo->fgWpsActive = FALSE;
+       /* prGlueInfo->prAdapter->prGlueInfo->u2WSCAssocInfoIELen = 0; */
+
+       if (sme->ie && sme->ie_len > 0) {
+               WLAN_STATUS rStatus;
+               UINT_32 u4BufLen;
+               PUINT_8 prDesiredIE = NULL;
+
+#if CFG_SUPPORT_WAPI
+               rStatus = kalIoctl(prGlueInfo,
+                                  wlanoidSetWapiAssocInfo,
+                                  sme->ie, sme->ie_len, FALSE, 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(sme->ie, sme->ie_len, 0xDD, (PUINT_8 *) &prDesiredIE)) {
+                       prGlueInfo->fgWpsActive = TRUE;
+                       fgCarryWPSIE = TRUE;
+
+                       rStatus = kalIoctl(prGlueInfo,
+                                          wlanoidSetWSCAssocInfo,
+                                          prDesiredIE,
+                                          IE_SIZE(prDesiredIE),
+                                          FALSE, FALSE, FALSE, FALSE, &u4BufLen);
+                       if (rStatus != WLAN_STATUS_SUCCESS) {
+                               DBGLOG(SEC, WARN, ("WSC] set WSC assoc info error:%lx\n", rStatus));
+                       }
+               }
+#endif
+       }
+
+       /* 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, FALSE, &u4BufLen);
+       if (rStatus != WLAN_STATUS_SUCCESS) {
+               DBGLOG(REQ, WARN, ("set auth mode error:%lx\n", rStatus));
+       }
+
+       cipher = prGlueInfo->rWpaInfo.u4CipherGroup | prGlueInfo->rWpaInfo.u4CipherPairwise;
+
+       if (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, 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) {
+               P_PARAM_WEP_T prWepKey = (P_PARAM_WEP_T) wepBuf;
+
+               kalMemSet(prWepKey, 0, sizeof(prWepKey));
+               prWepKey->u4Length = 12 + sme->key_len;
+               prWepKey->u4KeyLength = (UINT_32) sme->key_len;
+               prWepKey->u4KeyIndex = (UINT_32) sme->key_idx;
+               prWepKey->u4KeyIndex |= BIT(31);
+               if (prWepKey->u4KeyLength > 32) {
+                       DBGLOG(REQ, WARN, ("Too long key length (%u)\n", prWepKey->u4KeyLength));
+                       return -EINVAL;
+               }
+               kalMemCopy(prWepKey->aucKeyMaterial, sme->key, prWepKey->u4KeyLength);
+
+               rStatus = kalIoctl(prGlueInfo,
+                                  wlanoidSetAddWep,
+                                  prWepKey,
+                                  prWepKey->u4Length, FALSE, FALSE, TRUE, FALSE, &u4BufLen);
+
+               if (rStatus != WLAN_STATUS_SUCCESS) {
+                       DBGLOG(INIT, INFO, ("wlanoidSetAddWep fail 0x%lx\n", rStatus));
+                       return -EFAULT;
+               }
+       }
+
+       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;
+               }
+       } else {
+               /* connect by BSSID */
+               rStatus = kalIoctl(prGlueInfo,
+                                  wlanoidSetBssid,
+                                  (PVOID) sme->bssid,
+                                  sizeof(MAC_ADDR_LEN), FALSE, FALSE, TRUE, FALSE, &u4BufLen);
+
+               if (rStatus != WLAN_STATUS_SUCCESS) {
+                       DBGLOG(REQ, WARN, ("set BSSID:%lx\n", rStatus));
+                       return -EINVAL;
+               }
+       }
+
+       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, FALSE, &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 LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0)
+       if (params->channel) {
+               u4ChnlFreq = nicChannelNum2Freq(params->channel->hw_value);
+#else
+       if (params->chandef.chan) {
+               u4ChnlFreq = nicChannelNum2Freq(params->chandef.chan->hw_value);
+#endif
+               rStatus = kalIoctl(prGlueInfo,
+                                  wlanoidSetFrequency,
+                                  &u4ChnlFreq,
+                                  sizeof(u4ChnlFreq), FALSE, 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, FALSE, &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, FALSE, &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 ePowerMode;
+
+       prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy);
+       ASSERT(prGlueInfo);
+
+       if (enabled) {
+               if (timeout == -1) {
+                       ePowerMode = Param_PowerModeFast_PSP;
+               } else {
+                       ePowerMode = Param_PowerModeMAX_PSP;
+               }
+       } else {
+               ePowerMode = Param_PowerModeCAM;
+       }
+
+       rStatus = kalIoctl(prGlueInfo,
+                          wlanoidSet802dot11PowerSaveProfile,
+                          &ePowerMode, sizeof(ePowerMode), FALSE, FALSE, TRUE, FALSE, &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, 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, 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 requesting to stay on a
+ *        specified channel
+ *
+ * @param
+ *
+ * @retval 0:       successful
+ *         others:  failure
+ */
+/*----------------------------------------------------------------------------*/
+int mtk_cfg80211_remain_on_channel(struct wiphy *wiphy,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
+                                  struct net_device *ndev,
+#else
+                                  struct wireless_dev *wdev,
+#endif
+                                  struct ieee80211_channel *chan,
+                                  enum nl80211_channel_type channel_type,
+                                  unsigned int duration, u64 *cookie)
+{
+       P_GLUE_INFO_T prGlueInfo = NULL;
+
+       prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy);
+       ASSERT(prGlueInfo);
+
+#if 1
+       printk("--> %s()\n", __func__);
+#endif
+
+       /* not implemented */
+
+       return -EINVAL;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * @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,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
+                                         struct net_device *ndev,
+#else
+                                         struct wireless_dev *wdev,
+#endif
+                                         u64 cookie)
+{
+       P_GLUE_INFO_T prGlueInfo = NULL;
+
+       prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy);
+       ASSERT(prGlueInfo);
+
+#if 1
+       printk("--> %s()\n", __func__);
+#endif
+
+       /* not implemented */
+
+       return -EINVAL;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * @brief This routine is responsible for requesting to send a management frame
+ *
+ * @param
+ *
+ * @retval 0:       successful
+ *         others:  failure
+ */
+/*----------------------------------------------------------------------------*/
+int mtk_cfg80211_mgmt_tx(struct wiphy *wiphy,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
+                        struct net_device *ndev,
+#else
+                        struct wireless_dev *wdev,
+#endif
+                        struct ieee80211_channel *channel, bool offscan,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
+                        enum nl80211_channel_type channel_type, bool channel_type_valid,
+#endif
+                        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;
+
+       prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy);
+       ASSERT(prGlueInfo);
+
+#if 1
+       printk("--> %s()\n", __func__);
+#endif
+
+       /* not implemented */
+
+       return -EINVAL;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * @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,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
+                                    struct net_device *ndev,
+#else
+                                    struct wireless_dev *wdev,
+#endif
+                                    u64 cookie)
+{
+       P_GLUE_INFO_T prGlueInfo = NULL;
+
+       prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy);
+       ASSERT(prGlueInfo);
+
+#if 1
+       printk("--> %s()\n", __func__);
+#endif
+
+       /* not implemented */
+
+       return -EINVAL;
+}
+
+
+#if CONFIG_NL80211_TESTMODE
+
+#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;
+
+       P_PARAM_WPI_KEY_T prWpiKey = (P_PARAM_WPI_KEY_T) keyStructBuf;
+       memset(keyStructBuf, 0, sizeof(keyStructBuf));
+
+       ASSERT(wiphy);
+
+       prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy);
+
+#if 1
+       printk("--> %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->ucKeyID = prParams->key_index;
+               prWpiKey->ucKeyID--;
+               if (prWpiKey->ucKeyID > 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;
+               }
+               /* printk(KERN_INFO "[wapi] %d ext_flags %d\n", prEnc->flags, prIWEncExt->ext_flags); */
+
+               if (prIWEncExt->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
+                       prWpiKey->eKeyType = ENUM_WPI_GROUP_KEY;
+                       prWpiKey->eDirection = ENUM_WPI_RX;
+               } else if (prIWEncExt->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
+                       prWpiKey->eKeyType = ENUM_WPI_PAIRWISE_KEY;
+                       prWpiKey->eDirection = ENUM_WPI_RX_TX;
+               }
+/* #if CFG_SUPPORT_WAPI */
+               /* handle_sec_msg_final(prIWEncExt->key, 32, prIWEncExt->key, NULL); */
+/* #endif */
+               /* PN */
+               memcpy(prWpiKey->aucPN, prIWEncExt->tx_seq, IW_ENCODE_SEQ_MAX_SIZE * 2);
+
+               /* BSSID */
+               memcpy(prWpiKey->aucAddrIndex, prIWEncExt->addr, 6);
+
+               memcpy(prWpiKey->aucWPIEK, prIWEncExt->key, 16);
+               prWpiKey->u4LenWPIEK = 16;
+
+               memcpy(prWpiKey->aucWPICK, &prIWEncExt->key[16], 16);
+               prWpiKey->u4LenWPICK = 16;
+
+               rstatus = kalIoctl(prGlueInfo,
+                                  wlanoidSetWapiKey,
+                                  prWpiKey,
+                                  sizeof(PARAM_WPI_KEY_T), FALSE, FALSE, TRUE, FALSE, &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_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
+       printk("--> %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, FALSE, &u4SetInfoLen);
+               }
+       }
+
+       if (WLAN_STATUS_SUCCESS != rstatus) {
+               fgIsValid = -EFAULT;
+       }
+
+       return fgIsValid;
+}
+
+int mtk_cfg80211_testmode_cmd(IN struct wiphy *wiphy, IN void *data, IN int len)
+{
+       P_GLUE_INFO_T prGlueInfo = NULL;
+       P_NL80211_DRIVER_TEST_MODE_PARAMS prParams = (P_NL80211_DRIVER_TEST_MODE_PARAMS) NULL;
+       BOOLEAN fgIsValid = 0;
+
+       ASSERT(wiphy);
+
+       prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy);
+
+#if 1
+       printk("--> %s()\n", __func__);
+#endif
+
+       if (data && len)
+               prParams = (P_NL80211_DRIVER_TEST_MODE_PARAMS) data;
+
+       /* Clear the version byte */
+       prParams->index = prParams->index & ~BITS(24, 31);
+
+       if (prParams) {
+               switch (prParams->index) {
+               case 1: /* SW cmd */
+                       if (mtk_cfg80211_testmode_sw_cmd(wiphy, data, len))
+                               fgIsValid = TRUE;
+                       break;
+               case 2: /* WAPI */
+#if CFG_SUPPORT_WAPI
+                       if (mtk_cfg80211_testmode_set_key_ext(wiphy, data, len))
+                               fgIsValid = TRUE;
+#endif
+                       break;
+               default:
+                       fgIsValid = TRUE;
+                       break;
+               }
+       }
+
+       return fgIsValid;
+}
+#endif