blob: 4f0837b5832b95e33592b362bbf5364bfcf41062 [file] [log] [blame]
/******************************************************************************
*
* This file is provided under a dual license. When you use or
* distribute this software, you may choose to be licensed under
* version 2 of the GNU General Public License ("GPLv2 License")
* or BSD License.
*
* GPLv2 License
*
* Copyright(C) 2016 MediaTek Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See http://www.gnu.org/licenses/gpl-2.0.html for more details.
*
* BSD LICENSE
*
* Copyright(C) 2016 MediaTek Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
/*
** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/gl_wext.c#5
*/
/*! \file gl_wext.c
* \brief ioctl() (mostly Linux Wireless Extensions) routines for STA driver.
*/
/*******************************************************************************
* 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 "config.h"
#include "wlan_oid.h"
#include "gl_wext.h"
#include "gl_wext_priv.h"
#include "precomp.h"
#if CFG_SUPPORT_WAPI
#include "gl_sec.h"
#endif
/* compatibility to wireless extensions */
#ifdef WIRELESS_EXT
/*******************************************************************************
* C O N S T A N T S
********************************************************************************
*/
const long channel_freq[] = {
2412, 2417, 2422, 2427, 2432, 2437, 2442,
2447, 2452, 2457, 2462, 2467, 2472, 2484
};
#define NUM_CHANNELS (ARRAY_SIZE(channel_freq))
#define MAX_SSID_LEN 32
/*******************************************************************************
* D A T A T Y P E S
********************************************************************************
*/
/*******************************************************************************
* P U B L I C D A T A
********************************************************************************
*/
/* NOTE: name in iwpriv_args only have 16 bytes */
static const struct iw_priv_args rIwPrivTable[] = {
{IOCTL_SET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, ""},
{IOCTL_GET_INT, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ""},
{IOCTL_SET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, ""},
{IOCTL_GET_INT, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, ""},
{IOCTL_SET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, ""},
{IOCTL_GET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ""},
{IOCTL_GET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ""},
{IOCTL_SET_INTS, IW_PRIV_TYPE_INT | 4, 0, ""},
{IOCTL_GET_INT, 0, IW_PRIV_TYPE_INT | 50, ""},
/* added for set_oid and get_oid */
{IOCTL_SET_STRUCT, 256, 0, ""},
{IOCTL_GET_STRUCT, 0, 256, ""},
{IOCTL_GET_DRIVER, IW_PRIV_TYPE_CHAR | 2000, IW_PRIV_TYPE_CHAR | 2000, "driver"},
#if CFG_SUPPORT_QA_TOOL
/* added for ATE iwpriv Command */
{IOCTL_IWPRIV_ATE, IW_PRIV_TYPE_CHAR | 2000, 0, ""},
#endif
/* sub-ioctl definitions */
#if 0
{PRIV_CMD_REG_DOMAIN, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_reg_domain"},
{PRIV_CMD_REG_DOMAIN, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_reg_domain"},
#endif
#if CFG_TCP_IP_CHKSUM_OFFLOAD
{PRIV_CMD_CSUM_OFFLOAD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_tcp_csum"},
#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */
{PRIV_CMD_POWER_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_power_mode"},
{PRIV_CMD_POWER_MODE, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_power_mode"},
{PRIV_CMD_WMM_PS, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "set_wmm_ps"},
{PRIV_CMD_TEST_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_test_mode"},
{PRIV_CMD_TEST_CMD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_test_cmd"},
{PRIV_CMD_TEST_CMD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_test_result"},
#if CFG_SUPPORT_PRIV_MCR_RW
{PRIV_CMD_ACCESS_MCR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_mcr"},
{PRIV_CMD_ACCESS_MCR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_mcr"},
#endif
#if CFG_SUPPORT_QA_TOOL
{PRIV_QACMD_SET, IW_PRIV_TYPE_CHAR | 2000, 0, "set"},
#endif
{PRIV_CMD_SW_CTRL, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_sw_ctrl"},
{PRIV_CMD_SW_CTRL, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_sw_ctrl"},
#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS
{PRIV_CUSTOM_BWCS_CMD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_bwcs"},
/* GET STRUCT sub-ioctls commands */
{PRIV_CUSTOM_BWCS_CMD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_bwcs"},
#endif
/* SET STRUCT sub-ioctls commands */
{PRIV_CMD_OID, 256, 0, "set_oid"},
/* GET STRUCT sub-ioctls commands */
{PRIV_CMD_OID, 0, 256, "get_oid"},
{PRIV_CMD_BAND_CONFIG, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_band"},
{PRIV_CMD_BAND_CONFIG, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_band"},
{PRIV_CMD_SET_TX_POWER, IW_PRIV_TYPE_INT | 4, 0, "set_txpower"},
{PRIV_CMD_GET_CH_LIST, 0, IW_PRIV_TYPE_INT | 50, "get_ch_list"},
{PRIV_CMD_DUMP_MEM, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_mem"},
#if CFG_ENABLE_WIFI_DIRECT
{PRIV_CMD_P2P_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_p2p_mode"},
#endif
{PRIV_CMD_MET_PROFILING, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_met_prof"},
};
static const iw_handler rIwPrivHandler[] = {
[IOCTL_SET_INT - SIOCIWFIRSTPRIV] = priv_set_int,
[IOCTL_GET_INT - SIOCIWFIRSTPRIV] = priv_get_int,
[IOCTL_SET_ADDRESS - SIOCIWFIRSTPRIV] = NULL,
[IOCTL_GET_ADDRESS - SIOCIWFIRSTPRIV] = NULL,
[IOCTL_SET_STR - SIOCIWFIRSTPRIV] = NULL,
[IOCTL_GET_STR - SIOCIWFIRSTPRIV] = NULL,
[IOCTL_SET_KEY - SIOCIWFIRSTPRIV] = NULL,
[IOCTL_GET_KEY - SIOCIWFIRSTPRIV] = NULL,
[IOCTL_SET_STRUCT - SIOCIWFIRSTPRIV] = priv_set_struct,
[IOCTL_GET_STRUCT - SIOCIWFIRSTPRIV] = priv_get_struct,
[IOCTL_SET_STRUCT_FOR_EM - SIOCIWFIRSTPRIV] = priv_set_struct,
[IOCTL_SET_INTS - SIOCIWFIRSTPRIV] = priv_set_ints,
[IOCTL_GET_INTS - SIOCIWFIRSTPRIV] = priv_get_ints,
[IOCTL_GET_DRIVER - SIOCIWFIRSTPRIV] = priv_set_driver,
#if CFG_SUPPORT_QA_TOOL
[IOCTL_IWPRIV_ATE - SIOCIWFIRSTPRIV] = priv_ate_set
#endif
};
const struct iw_handler_def wext_handler_def = {
.num_standard = 0,
#if defined(CONFIG_WEXT_PRIV) || LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
.num_private = (__u16) sizeof(rIwPrivHandler) / sizeof(iw_handler),
.num_private_args = (__u16) sizeof(rIwPrivTable) / sizeof(struct iw_priv_args),
#endif /* CONFIG_WEXT_PRIV || LINUX_VERSION_CODE <= 2.6.32 */
.standard = (iw_handler *) NULL,
#if defined(CONFIG_WEXT_PRIV) || LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
.private = rIwPrivHandler,
.private_args = rIwPrivTable,
#endif /* CONFIG_WEXT_PRIV || LINUX_VERSION_CODE <= 2.6.32 */
.get_wireless_stats = wext_get_wireless_stats,
};
/*******************************************************************************
* 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
********************************************************************************
*/
static void wext_support_ioctl_SIOCSIWGENIE(IN P_GLUE_INFO_T prGlueInfo, IN char *prExtraBuf, IN UINT_32 u4ExtraSize);
static void
wext_support_ioctl_SIOCSIWPMKSA_Action(IN struct net_device *prDev, IN char *prExtraBuf, IN int ioMode, OUT int *ret);
/*******************************************************************************
* F U N C T I O N S
********************************************************************************
*/
void MAP_CHANNEL_ID_TO_KHZ(UINT_32 ch, UINT_32 khz)
{
switch (ch) {
case 1:
khz = 2412000;
break;
case 2:
khz = 2417000;
break;
case 3:
khz = 2422000;
break;
case 4:
khz = 2427000;
break;
case 5:
khz = 2432000;
break;
case 6:
khz = 2437000;
break;
case 7:
khz = 2442000;
break;
case 8:
khz = 2447000;
break;
case 9:
khz = 2452000;
break;
case 10:
khz = 2457000;
break;
case 11:
khz = 2462000;
break;
case 12:
khz = 2467000;
break;
case 13:
khz = 2472000;
break;
case 14:
khz = 2484000;
break;
case 36: /* UNII */
khz = 5180000;
break;
case 40: /* UNII */
khz = 5200000;
break;
case 44:
khz = 5220000;
break;
case 48:
khz = 5240000;
break;
case 52:
khz = 5260000;
break;
case 56:
khz = 5280000;
break;
case 60:
khz = 5300000;
break;
case 64:
khz = 5320000;
break;
case 149:
khz = 5745000;
break;
case 153:
khz = 5765000;
break;
case 157:
khz = 5785000;
break;
case 161: /* UNII */
khz = 5805000;
break;
case 165: /* UNII */
khz = 5825000;
break;
case 100: /* HiperLAN2 */
khz = 5500000;
break;
case 104: /* HiperLAN2 */
khz = 5520000;
break;
case 108: /* HiperLAN2 */
khz = 5540000;
break;
case 112: /* HiperLAN2 */
khz = 5560000;
break;
case 116: /* HiperLAN2 */
khz = 5580000;
break;
case 120: /* HiperLAN2 */
khz = 5600000;
break;
case 124: /* HiperLAN2 */
khz = 5620000;
break;
case 128: /* HiperLAN2 */
khz = 5640000;
break;
case 132: /* HiperLAN2 */
khz = 5660000;
break;
case 136: /* HiperLAN2 */
khz = 5680000;
break;
case 140: /* HiperLAN2 */
khz = 5700000;
break;
case 34: /* Japan MMAC */
khz = 5170000;
break;
case 38: /* Japan MMAC */
khz = 5190000;
break;
case 42: /* Japan MMAC */
khz = 5210000;
break;
case 46: /* Japan MMAC */
khz = 5230000;
break;
case 184: /* Japan */
khz = 4920000;
break;
case 188: /* Japan */
khz = 4940000;
break;
case 192: /* Japan */
khz = 4960000;
break;
case 196: /* Japan */
khz = 4980000;
break;
case 208: /* Japan, means J08 */
khz = 5040000;
break;
case 212: /* Japan, means J12 */
khz = 5060000;
break;
case 216: /* Japan, means J16 */
khz = 5080000;
break;
default:
khz = 2412000;
break;
}
}
/*----------------------------------------------------------------------------*/
/*!
* \brief Find the desired WPA/RSN Information Element according to desiredElemID.
*
* \param[in] pucIEStart IE starting address.
* \param[in] i4TotalIeLen Total length of all the IE.
* \param[in] ucDesiredElemId Desired element ID.
* \param[out] ppucDesiredIE Pointer to the desired IE.
*
* \retval TRUE Find the desired IE.
* \retval FALSE Desired IE not found.
*
* \note
*/
/*----------------------------------------------------------------------------*/
BOOLEAN
wextSrchDesiredWPAIE(IN PUINT_8 pucIEStart,
IN INT_32 i4TotalIeLen, IN UINT_8 ucDesiredElemId, OUT PUINT_8 *ppucDesiredIE)
{
INT_32 i4InfoElemLen;
ASSERT(pucIEStart);
ASSERT(ppucDesiredIE);
while (i4TotalIeLen >= 2) {
i4InfoElemLen = (INT_32) pucIEStart[1] + 2;
if (pucIEStart[0] == ucDesiredElemId && i4InfoElemLen <= i4TotalIeLen) {
if (ucDesiredElemId != 0xDD) {
/* Non 0xDD, OK! */
*ppucDesiredIE = &pucIEStart[0];
return TRUE;
} /* EID == 0xDD, check WPA IE */
if (pucIEStart[1] >= 4) {
if (memcmp(&pucIEStart[2], "\x00\x50\xf2\x01", 4) == 0) {
*ppucDesiredIE = &pucIEStart[0];
return TRUE;
}
} /* check WPA IE length */
/* check EID == 0xDD */
}
/* check desired EID */
/* Select next information element. */
i4TotalIeLen -= i4InfoElemLen;
pucIEStart += i4InfoElemLen;
}
return FALSE;
} /* parseSearchDesiredWPAIE */
#if CFG_SUPPORT_WAPI
/*----------------------------------------------------------------------------*/
/*!
* \brief Find the desired WAPI Information Element .
*
* \param[in] pucIEStart IE starting address.
* \param[in] i4TotalIeLen Total length of all the IE.
* \param[out] ppucDesiredIE Pointer to the desired IE.
*
* \retval TRUE Find the desired IE.
* \retval FALSE Desired IE not found.
*
* \note
*/
/*----------------------------------------------------------------------------*/
BOOLEAN wextSrchDesiredWAPIIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE)
{
INT_32 i4InfoElemLen;
ASSERT(pucIEStart);
ASSERT(ppucDesiredIE);
while (i4TotalIeLen >= 2) {
i4InfoElemLen = (INT_32) pucIEStart[1] + 2;
if (pucIEStart[0] == ELEM_ID_WAPI && i4InfoElemLen <= i4TotalIeLen) {
*ppucDesiredIE = &pucIEStart[0];
return TRUE;
}
/* check desired EID */
/* Select next information element. */
i4TotalIeLen -= i4InfoElemLen;
pucIEStart += i4InfoElemLen;
}
return FALSE;
} /* wextSrchDesiredWAPIIE */
#endif
#if CFG_SUPPORT_PASSPOINT
/*----------------------------------------------------------------------------*/
/*!
* \brief Check if exist the desired HS2.0 Information Element according to desiredElemID.
*
* \param[in] pucIEStart IE starting address.
* \param[in] i4TotalIeLen Total length of all the IE.
* \param[in] ucDesiredElemId Desired element ID.
* \param[out] ppucDesiredIE Pointer to the desired IE.
*
* \retval TRUE Find the desired IE.
* \retval FALSE Desired IE not found.
*
* \note
*/
/*----------------------------------------------------------------------------*/
BOOLEAN wextIsDesiredHS20IE(IN PUINT_8 pucCurIE, IN INT_32 i4TotalIeLen)
{
INT_32 i4InfoElemLen;
ASSERT(pucCurIE);
i4InfoElemLen = (INT_32) pucCurIE[1] + 2;
if (pucCurIE[0] == ELEM_ID_VENDOR && i4InfoElemLen <= i4TotalIeLen) {
if (pucCurIE[1] >= ELEM_MIN_LEN_HS20_INDICATION) {
if (memcmp(&pucCurIE[2], "\x50\x6f\x9a\x10", 4) == 0)
return TRUE;
}
}
/* check desired EID */
return FALSE;
} /* wextIsDesiredHS20IE */
/*----------------------------------------------------------------------------*/
/*!
* \brief Check if exist the desired interworking Information Element according to desiredElemID.
*
* \param[in] pucIEStart IE starting address.
* \param[in] i4TotalIeLen Total length of all the IE.
* \param[in] ucDesiredElemId Desired element ID.
* \param[out] ppucDesiredIE Pointer to the desired IE.
*
* \retval TRUE Find the desired IE.
* \retval FALSE Desired IE not found.
*
* \note
*/
/*----------------------------------------------------------------------------*/
BOOLEAN wextIsDesiredInterworkingIE(IN PUINT_8 pucCurIE, IN INT_32 i4TotalIeLen)
{
INT_32 i4InfoElemLen;
ASSERT(pucCurIE);
i4InfoElemLen = (INT_32) pucCurIE[1] + 2;
if (pucCurIE[0] == ELEM_ID_INTERWORKING && i4InfoElemLen <= i4TotalIeLen) {
switch (pucCurIE[1]) {
case IW_IE_LENGTH_ANO:
case IW_IE_LENGTH_ANO_HESSID:
case IW_IE_LENGTH_ANO_VENUE:
case IW_IE_LENGTH_ANO_VENUE_HESSID:
return TRUE;
default:
break;
}
}
/* check desired EID */
return FALSE;
} /* wextIsDesiredInterworkingIE */
/*----------------------------------------------------------------------------*/
/*!
* \brief Check if exist the desired Adv Protocol Information Element according to desiredElemID.
*
* \param[in] pucIEStart IE starting address.
* \param[in] i4TotalIeLen Total length of all the IE.
* \param[in] ucDesiredElemId Desired element ID.
* \param[out] ppucDesiredIE Pointer to the desired IE.
*
* \retval TRUE Find the desired IE.
* \retval FALSE Desired IE not found.
*
* \note
*/
/*----------------------------------------------------------------------------*/
BOOLEAN wextIsDesiredAdvProtocolIE(IN PUINT_8 pucCurIE, IN INT_32 i4TotalIeLen)
{
INT_32 i4InfoElemLen;
ASSERT(pucCurIE);
i4InfoElemLen = (INT_32) pucCurIE[1] + 2;
if (pucCurIE[0] == ELEM_ID_ADVERTISEMENT_PROTOCOL && i4InfoElemLen <= i4TotalIeLen)
return TRUE;
/* check desired EID */
return FALSE;
} /* wextIsDesiredAdvProtocolIE */
/*----------------------------------------------------------------------------*/
/*!
* \brief Check if exist the desired Roaming Consortium Information Element according to desiredElemID.
*
* \param[in] pucIEStart IE starting address.
* \param[in] i4TotalIeLen Total length of all the IE.
* \param[in] ucDesiredElemId Desired element ID.
* \param[out] ppucDesiredIE Pointer to the desired IE.
*
* \retval TRUE Find the desired IE.
* \retval FALSE Desired IE not found.
*
* \note
*/
/*----------------------------------------------------------------------------*/
BOOLEAN wextIsDesiredRoamingConsortiumIE(IN PUINT_8 pucCurIE, IN INT_32 i4TotalIeLen)
{
INT_32 i4InfoElemLen;
ASSERT(pucCurIE);
i4InfoElemLen = (INT_32) pucCurIE[1] + 2;
if (pucCurIE[0] == ELEM_ID_ROAMING_CONSORTIUM && i4InfoElemLen <= i4TotalIeLen)
return TRUE;
/* check desired EID */
return FALSE;
} /* wextIsDesiredRoamingConsortiumIE */
/*----------------------------------------------------------------------------*/
/*!
* \brief Find the desired HS2.0 Information Element according to desiredElemID.
*
* \param[in] pucIEStart IE starting address.
* \param[in] i4TotalIeLen Total length of all the IE.
* \param[in] ucDesiredElemId Desired element ID.
* \param[out] ppucDesiredIE Pointer to the desired IE.
*
* \retval TRUE Find the desired IE.
* \retval FALSE Desired IE not found.
*
* \note
*/
/*----------------------------------------------------------------------------*/
BOOLEAN wextSrchDesiredHS20IE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE)
{
INT_32 i4InfoElemLen;
ASSERT(pucIEStart);
ASSERT(ppucDesiredIE);
while (i4TotalIeLen >= 2) {
i4InfoElemLen = (INT_32) pucIEStart[1] + 2;
if (pucIEStart[0] == ELEM_ID_VENDOR && i4InfoElemLen <= i4TotalIeLen) {
if (pucIEStart[1] >= ELEM_MIN_LEN_HS20_INDICATION) {
if (memcmp(&pucIEStart[2], "\x50\x6f\x9a\x10", 4) == 0) {
*ppucDesiredIE = &pucIEStart[0];
return TRUE;
}
}
}
/* check desired EID */
/* Select next information element. */
i4TotalIeLen -= i4InfoElemLen;
pucIEStart += i4InfoElemLen;
}
return FALSE;
} /* wextSrchDesiredHS20IE */
/*----------------------------------------------------------------------------*/
/*!
* \brief Find the desired interworking Information Element according to desiredElemID.
*
* \param[in] pucIEStart IE starting address.
* \param[in] i4TotalIeLen Total length of all the IE.
* \param[in] ucDesiredElemId Desired element ID.
* \param[out] ppucDesiredIE Pointer to the desired IE.
*
* \retval TRUE Find the desired IE.
* \retval FALSE Desired IE not found.
*
* \note
*/
/*----------------------------------------------------------------------------*/
BOOLEAN wextSrchDesiredInterworkingIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE)
{
INT_32 i4InfoElemLen;
ASSERT(pucIEStart);
ASSERT(ppucDesiredIE);
while (i4TotalIeLen >= 2) {
i4InfoElemLen = (INT_32) pucIEStart[1] + 2;
if (pucIEStart[0] == ELEM_ID_INTERWORKING && i4InfoElemLen <= i4TotalIeLen) {
*ppucDesiredIE = &pucIEStart[0];
return TRUE;
}
/* check desired EID */
/* Select next information element. */
i4TotalIeLen -= i4InfoElemLen;
pucIEStart += i4InfoElemLen;
}
return FALSE;
} /* wextSrchDesiredInterworkingIE */
/*----------------------------------------------------------------------------*/
/*!
* \brief Find the desired Adv Protocol Information Element according to desiredElemID.
*
* \param[in] pucIEStart IE starting address.
* \param[in] i4TotalIeLen Total length of all the IE.
* \param[in] ucDesiredElemId Desired element ID.
* \param[out] ppucDesiredIE Pointer to the desired IE.
*
* \retval TRUE Find the desired IE.
* \retval FALSE Desired IE not found.
*
* \note
*/
/*----------------------------------------------------------------------------*/
BOOLEAN wextSrchDesiredAdvProtocolIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE)
{
INT_32 i4InfoElemLen;
ASSERT(pucIEStart);
ASSERT(ppucDesiredIE);
while (i4TotalIeLen >= 2) {
i4InfoElemLen = (INT_32) pucIEStart[1] + 2;
if (pucIEStart[0] == ELEM_ID_ADVERTISEMENT_PROTOCOL && i4InfoElemLen <= i4TotalIeLen) {
*ppucDesiredIE = &pucIEStart[0];
return TRUE;
}
/* check desired EID */
/* Select next information element. */
i4TotalIeLen -= i4InfoElemLen;
pucIEStart += i4InfoElemLen;
}
return FALSE;
} /* wextSrchDesiredAdvProtocolIE */
/*----------------------------------------------------------------------------*/
/*!
* \brief Find the desired Roaming Consortium Information Element according to desiredElemID.
*
* \param[in] pucIEStart IE starting address.
* \param[in] i4TotalIeLen Total length of all the IE.
* \param[in] ucDesiredElemId Desired element ID.
* \param[out] ppucDesiredIE Pointer to the desired IE.
*
* \retval TRUE Find the desired IE.
* \retval FALSE Desired IE not found.
*
* \note
*/
/*----------------------------------------------------------------------------*/
BOOLEAN wextSrchDesiredRoamingConsortiumIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE)
{
INT_32 i4InfoElemLen;
ASSERT(pucIEStart);
ASSERT(ppucDesiredIE);
while (i4TotalIeLen >= 2) {
i4InfoElemLen = (INT_32) pucIEStart[1] + 2;
if (pucIEStart[0] == ELEM_ID_ROAMING_CONSORTIUM && i4InfoElemLen <= i4TotalIeLen) {
*ppucDesiredIE = &pucIEStart[0];
return TRUE;
}
/* check desired EID */
/* Select next information element. */
i4TotalIeLen -= i4InfoElemLen;
pucIEStart += i4InfoElemLen;
}
return FALSE;
} /* wextSrchDesiredRoamingConsortiumIE */
#endif /* CFG_SUPPORT_PASSPOINT */
#if CFG_SUPPORT_WPS
/*----------------------------------------------------------------------------*/
/*!
* \brief Find the desired WPS Information Element according to desiredElemID.
*
* \param[in] pucIEStart IE starting address.
* \param[in] i4TotalIeLen Total length of all the IE.
* \param[in] ucDesiredElemId Desired element ID.
* \param[out] ppucDesiredIE Pointer to the desired IE.
*
* \retval TRUE Find the desired IE.
* \retval FALSE Desired IE not found.
*
* \note
*/
/*----------------------------------------------------------------------------*/
BOOLEAN
wextSrchDesiredWPSIE(IN PUINT_8 pucIEStart,
IN INT_32 i4TotalIeLen, IN UINT_8 ucDesiredElemId, OUT PUINT_8 *ppucDesiredIE)
{
INT_32 i4InfoElemLen;
ASSERT(pucIEStart);
ASSERT(ppucDesiredIE);
while (i4TotalIeLen >= 2) {
i4InfoElemLen = (INT_32) pucIEStart[1] + 2;
if (pucIEStart[0] == ucDesiredElemId && i4InfoElemLen <= i4TotalIeLen) {
if (ucDesiredElemId != 0xDD) {
/* Non 0xDD, OK! */
*ppucDesiredIE = &pucIEStart[0];
return TRUE;
}
/* EID == 0xDD, check WPS IE */
if (pucIEStart[1] >= 4) {
if (memcmp(&pucIEStart[2], "\x00\x50\xf2\x04", 4) == 0) {
*ppucDesiredIE = &pucIEStart[0];
return TRUE;
}
} /* check WPS IE length */
/* check EID == 0xDD */
}
/* check desired EID */
/* Select next information element. */
i4TotalIeLen -= i4InfoElemLen;
pucIEStart += i4InfoElemLen;
}
return FALSE;
} /* parseSearchDesiredWPSIE */
#endif
/*----------------------------------------------------------------------------*/
/*!
* \brief Get the name of the protocol used on the air.
*
* \param[in] prDev Net device requested.
* \param[in] prIwrInfo NULL.
* \param[out] pcName Buffer to store protocol name string
* \param[in] pcExtra NULL.
*
* \retval 0 For success.
*
* \note If netif_carrier_ok, protocol name is returned;
* otherwise, "disconnected" is returned.
*/
/*----------------------------------------------------------------------------*/
static int
wext_get_name(IN struct net_device *prNetDev, IN struct iw_request_info *prIwrInfo, OUT char *pcName, IN char *pcExtra)
{
ENUM_PARAM_NETWORK_TYPE_T eNetWorkType;
P_GLUE_INFO_T prGlueInfo = NULL;
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
UINT_32 u4BufLen = 0;
ASSERT(prNetDev);
ASSERT(pcName);
if (GLUE_CHK_PR2(prNetDev, pcName) == FALSE)
return -EINVAL;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
if (netif_carrier_ok(prNetDev)) {
rStatus = kalIoctl(prGlueInfo,
wlanoidQueryNetworkTypeInUse,
&eNetWorkType, sizeof(eNetWorkType), TRUE, FALSE, FALSE, &u4BufLen);
switch (eNetWorkType) {
case PARAM_NETWORK_TYPE_DS:
strncpy(pcName, "IEEE 802.11b", sizeof(((struct iwreq *)0)->u.name));
break;
case PARAM_NETWORK_TYPE_OFDM24:
strncpy(pcName, "IEEE 802.11bgn", sizeof(((struct iwreq *)0)->u.name));
break;
case PARAM_NETWORK_TYPE_AUTOMODE:
case PARAM_NETWORK_TYPE_OFDM5:
strncpy(pcName, "IEEE 802.11abgn", sizeof(((struct iwreq *)0)->u.name));
break;
case PARAM_NETWORK_TYPE_FH:
default:
strncpy(pcName, "IEEE 802.11", sizeof(((struct iwreq *)0)->u.name));
break;
}
} else {
strncpy(pcName, "Disconnected", sizeof(((struct iwreq *)0)->u.name));
}
return 0;
} /* wext_get_name */
/*----------------------------------------------------------------------------*/
/*!
* \brief To set the operating channel in the wireless device.
*
* \param[in] prDev Net device requested.
* \param[in] prIwrInfo NULL
* \param[in] prFreq Buffer to store frequency information
* \param[in] pcExtra NULL
*
* \retval 0 For success.
* \retval -EOPNOTSUPP If infrastructure mode is not NET NET_TYPE_IBSS.
* \retval -EINVAL Invalid channel frequency.
*
* \note If infrastructure mode is IBSS, new channel frequency is set to device.
* The range of channel number depends on different regulatory domain.
*/
/*----------------------------------------------------------------------------*/
static int
wext_set_freq(IN struct net_device *prNetDev,
IN struct iw_request_info *prIwReqInfo, IN struct iw_freq *prIwFreq, IN char *pcExtra)
{
#if 0
UINT_32 u4ChnlFreq; /* Store channel or frequency information */
P_GLUE_INFO_T prGlueInfo = NULL;
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
UINT_32 u4BufLen = 0;
ASSERT(prNetDev);
ASSERT(prIwFreq);
if (GLUE_CHK_PR2(prNetDev, prIwFreq) == FALSE)
return -EINVAL;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
/*
* printk("set m:%d, e:%d, i:%d, flags:%d\n",
* prIwFreq->m, prIwFreq->e, prIwFreq->i, prIwFreq->flags);
*/
/* If setting by frequency, convert to a channel */
if ((prIwFreq->e == 1) && (prIwFreq->m >= (int)2.412e8) && (prIwFreq->m <= (int)2.484e8)) {
/* Change to KHz format */
u4ChnlFreq = (UINT_32) (prIwFreq->m / (KILO / 10));
rStatus = kalIoctl(prGlueInfo,
wlanoidSetFrequency,
&u4ChnlFreq, sizeof(u4ChnlFreq), FALSE, FALSE, FALSE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
return -EINVAL;
}
/* Setting by channel number */
else if ((prIwFreq->m > KILO) || (prIwFreq->e > 0))
return -EOPNOTSUPP;
/* Change to channel number format */
u4ChnlFreq = (UINT_32) prIwFreq->m;
rStatus = kalIoctl(prGlueInfo,
wlanoidSetChannel, &u4ChnlFreq, sizeof(u4ChnlFreq), FALSE, FALSE, FALSE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
return -EINVAL;
#endif
return 0;
} /* wext_set_freq */
/*----------------------------------------------------------------------------*/
/*!
* \brief To get the operating channel in the wireless device.
*
* \param[in] prDev Net device requested.
* \param[in] prIwrInfo NULL.
* \param[out] prFreq Buffer to store frequency information.
* \param[in] pcExtra NULL.
*
* \retval 0 If netif_carrier_ok.
* \retval -ENOTCONN Otherwise
*
* \note If netif_carrier_ok, channel frequency information is stored in pFreq.
*/
/*----------------------------------------------------------------------------*/
static int
wext_get_freq(IN struct net_device *prNetDev,
IN struct iw_request_info *prIwrInfo, OUT struct iw_freq *prIwFreq, IN char *pcExtra)
{
UINT_32 u4Channel = 0;
P_GLUE_INFO_T prGlueInfo = NULL;
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
UINT_32 u4BufLen = 0;
ASSERT(prNetDev);
ASSERT(prIwFreq);
if (GLUE_CHK_PR2(prNetDev, prIwFreq) == FALSE)
return -EINVAL;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
/* GeorgeKuo: TODO skip checking in IBSS mode */
if (!netif_carrier_ok(prNetDev))
return -ENOTCONN;
rStatus = kalIoctl(prGlueInfo,
wlanoidQueryFrequency, &u4Channel, sizeof(u4Channel), TRUE, FALSE, FALSE, &u4BufLen);
prIwFreq->m = (int)u4Channel; /* freq in KHz */
prIwFreq->e = 3;
return 0;
} /* wext_get_freq */
/*----------------------------------------------------------------------------*/
/*!
* \brief To set operating mode.
*
* \param[in] prDev Net device requested.
* \param[in] prIwrInfo NULL.
* \param[in] pu4Mode Pointer to new operation mode.
* \param[in] pcExtra NULL.
*
* \retval 0 For success.
* \retval -EOPNOTSUPP If new mode is not supported.
*
* \note Device will run in new operation mode if it is valid.
*/
/*----------------------------------------------------------------------------*/
static int
wext_set_mode(IN struct net_device *prNetDev,
IN struct iw_request_info *prIwReqInfo, IN unsigned int *pu4Mode, IN char *pcExtra)
{
ENUM_PARAM_OP_MODE_T eOpMode;
P_GLUE_INFO_T prGlueInfo = NULL;
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
UINT_32 u4BufLen = 0;
ASSERT(prNetDev);
ASSERT(pu4Mode);
if (GLUE_CHK_PR2(prNetDev, pu4Mode) == FALSE)
return -EINVAL;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
switch (*pu4Mode) {
case IW_MODE_AUTO:
eOpMode = NET_TYPE_AUTO_SWITCH;
break;
case IW_MODE_ADHOC:
eOpMode = NET_TYPE_IBSS;
break;
case IW_MODE_INFRA:
eOpMode = NET_TYPE_INFRA;
break;
default:
DBGLOG(INIT, INFO, "%s(): Set UNSUPPORTED Mode = %d.\n", __func__, *pu4Mode);
return -EOPNOTSUPP;
}
/* printk("%s(): Set Mode = %d\n", __FUNCTION__, *pu4Mode); */
rStatus = kalIoctl(prGlueInfo,
wlanoidSetInfrastructureMode, &eOpMode, sizeof(eOpMode), FALSE, FALSE, TRUE, &u4BufLen);
/* 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
return 0;
} /* wext_set_mode */
/*----------------------------------------------------------------------------*/
/*!
* \brief To get operating mode.
*
* \param[in] prNetDev Net device requested.
* \param[in] prIwReqInfo NULL.
* \param[out] pu4Mode Buffer to store operating mode information.
* \param[in] pcExtra NULL.
*
* \retval 0 If data is valid.
* \retval -EINVAL Otherwise.
*
* \note If netif_carrier_ok, operating mode information is stored in pu4Mode.
*/
/*----------------------------------------------------------------------------*/
static int
wext_get_mode(IN struct net_device *prNetDev,
IN struct iw_request_info *prIwReqInfo, OUT unsigned int *pu4Mode, IN char *pcExtra)
{
ENUM_PARAM_OP_MODE_T eOpMode;
P_GLUE_INFO_T prGlueInfo = NULL;
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
UINT_32 u4BufLen = 0;
ASSERT(prNetDev);
ASSERT(pu4Mode);
if (GLUE_CHK_PR2(prNetDev, pu4Mode) == FALSE)
return -EINVAL;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
rStatus = kalIoctl(prGlueInfo,
wlanoidQueryInfrastructureMode, &eOpMode, sizeof(eOpMode), TRUE, FALSE, FALSE, &u4BufLen);
switch (eOpMode) {
case NET_TYPE_IBSS:
*pu4Mode = IW_MODE_ADHOC;
break;
case NET_TYPE_INFRA:
*pu4Mode = IW_MODE_INFRA;
break;
case NET_TYPE_AUTO_SWITCH:
*pu4Mode = IW_MODE_AUTO;
break;
default:
DBGLOG(INIT, INFO, "%s(): Get UNKNOWN Mode.\n", __func__);
return -EINVAL;
}
return 0;
} /* wext_get_mode */
/*----------------------------------------------------------------------------*/
/*!
* \brief To get the valid range for each configurable STA setting value.
*
* \param[in] prDev Net device requested.
* \param[in] prIwrInfo NULL.
* \param[in] prData Pointer to iw_point structure, not used.
* \param[out] pcExtra Pointer to buffer which is allocated by caller of this
* function, wext_support_ioctl() or ioctl_standard_call() in
* wireless.c.
*
* \retval 0 If data is valid.
*
* \note The extra buffer (pcExtra) is filled with information from driver.
*/
/*----------------------------------------------------------------------------*/
static int
wext_get_range(IN struct net_device *prNetDev,
IN struct iw_request_info *prIwrInfo, IN struct iw_point *prData, OUT char *pcExtra)
{
struct iw_range *prRange = NULL;
PARAM_RATES_EX aucSuppRate = { 0 }; /* data buffers */
int i = 0;
P_GLUE_INFO_T prGlueInfo = NULL;
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
UINT_32 u4BufLen = 0;
ASSERT(prNetDev);
ASSERT(pcExtra);
if (GLUE_CHK_PR2(prNetDev, pcExtra) == FALSE)
return -EINVAL;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
prRange = (struct iw_range *)pcExtra;
memset(prRange, 0, sizeof(*prRange));
prRange->throughput = 20000000; /* 20Mbps */
prRange->min_nwid = 0; /* not used */
prRange->max_nwid = 0; /* not used */
/* scan_capa not implemented */
/* event_capa[6]: kernel + driver capabilities */
prRange->event_capa[0] = (IW_EVENT_CAPA_K_0 | IW_EVENT_CAPA_MASK(SIOCGIWAP)
| IW_EVENT_CAPA_MASK(SIOCGIWSCAN)
/* can't display meaningful string in iwlist
* | IW_EVENT_CAPA_MASK(SIOCGIWTXPOW)
* | IW_EVENT_CAPA_MASK(IWEVMICHAELMICFAILURE)
* | IW_EVENT_CAPA_MASK(IWEVASSOCREQIE)
* | IW_EVENT_CAPA_MASK(IWEVPMKIDCAND)
*/
);
prRange->event_capa[1] = IW_EVENT_CAPA_K_1;
/* report 2.4G channel and frequency only */
prRange->num_channels = (__u16) NUM_CHANNELS;
prRange->num_frequency = (__u8) NUM_CHANNELS;
for (i = 0; i < NUM_CHANNELS; i++) {
/* iwlib takes this number as channel number */
prRange->freq[i].i = i + 1;
prRange->freq[i].m = channel_freq[i];
prRange->freq[i].e = 6; /* Values in table in MHz */
}
rStatus = kalIoctl(prGlueInfo,
wlanoidQuerySupportedRates,
&aucSuppRate, sizeof(aucSuppRate), TRUE, FALSE, FALSE, &u4BufLen);
for (i = 0; i < IW_MAX_BITRATES && i < PARAM_MAX_LEN_RATES_EX; i++) {
if (aucSuppRate[i] == 0)
break;
prRange->bitrate[i] = (aucSuppRate[i] & 0x7F) * 500000; /* 0.5Mbps */
}
prRange->num_bitrates = i;
prRange->min_rts = 0;
prRange->max_rts = 2347;
prRange->min_frag = 256;
prRange->max_frag = 2346;
prRange->min_pmp = 0; /* power management by driver */
prRange->max_pmp = 0; /* power management by driver */
prRange->min_pmt = 0; /* power management by driver */
prRange->max_pmt = 0; /* power management by driver */
prRange->pmp_flags = IW_POWER_RELATIVE; /* pm default flag */
prRange->pmt_flags = IW_POWER_ON; /* pm timeout flag */
prRange->pm_capa = IW_POWER_ON; /* power management by driver */
prRange->encoding_size[0] = 5; /* wep40 */
prRange->encoding_size[1] = 16; /* tkip */
prRange->encoding_size[2] = 16; /* ckip */
prRange->encoding_size[3] = 16; /* ccmp */
prRange->encoding_size[4] = 13; /* wep104 */
prRange->encoding_size[5] = 16; /* wep128 */
prRange->num_encoding_sizes = 6;
prRange->max_encoding_tokens = 6; /* token? */
#if WIRELESS_EXT < 17
prRange->txpower_capa = 0x0002; /* IW_TXPOW_RELATIVE */
#else
prRange->txpower_capa = IW_TXPOW_RELATIVE;
#endif
prRange->num_txpower = 5;
prRange->txpower[0] = 0; /* minimum */
prRange->txpower[1] = 25; /* 25% */
prRange->txpower[2] = 50; /* 50% */
prRange->txpower[3] = 100; /* 100% */
prRange->we_version_compiled = WIRELESS_EXT;
prRange->we_version_source = WIRELESS_EXT;
prRange->retry_capa = IW_RETRY_LIMIT;
prRange->retry_flags = IW_RETRY_LIMIT;
prRange->min_retry = 7;
prRange->max_retry = 7;
prRange->r_time_flags = IW_RETRY_ON;
prRange->min_r_time = 0;
prRange->max_r_time = 0;
/* signal strength and link quality */
/* Just define range here, reporting value moved to wext_get_stats() */
prRange->sensitivity = -83; /* fixed value */
prRange->max_qual.qual = 100; /* max 100% */
prRange->max_qual.level = (__u8) (0x100 - 0); /* max 0 dbm */
prRange->max_qual.noise = (__u8) (0x100 - 0); /* max 0 dbm */
/* enc_capa */
#if WIRELESS_EXT > 17
prRange->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
#endif
/* min_pms; Minimal PM saving */
/* max_pms; Maximal PM saving */
/* pms_flags; How to decode max/min PM saving */
/* modul_capa; IW_MODUL_* bit field */
/* bitrate_capa; Types of bitrates supported */
return 0;
} /* wext_get_range */
/*----------------------------------------------------------------------------*/
/*!
* \brief To set BSSID of AP to connect.
*
* \param[in] prDev Net device requested.
* \param[in] prIwrInfo NULL.
* \param[in] prAddr Pointer to struct sockaddr structure containing AP's BSSID.
* \param[in] pcExtra NULL.
*
* \retval 0 For success.
*
* \note Desired AP's BSSID is set to driver.
*/
/*----------------------------------------------------------------------------*/
static int
wext_set_ap(IN struct net_device *prDev,
IN struct iw_request_info *prIwrInfo, IN struct sockaddr *prAddr, IN char *pcExtra)
{
return 0;
} /* wext_set_ap */
/*----------------------------------------------------------------------------*/
/*!
* \brief To get AP MAC address.
*
* \param[in] prDev Net device requested.
* \param[in] prIwrInfo NULL.
* \param[out] prAddr Pointer to struct sockaddr structure storing AP's BSSID.
* \param[in] pcExtra NULL.
*
* \retval 0 If netif_carrier_ok.
* \retval -ENOTCONN Otherwise.
*
* \note If netif_carrier_ok, AP's mac address is stored in pAddr->sa_data.
*/
/*----------------------------------------------------------------------------*/
static int
wext_get_ap(IN struct net_device *prNetDev,
IN struct iw_request_info *prIwrInfo, OUT struct sockaddr *prAddr, IN char *pcExtra)
{
P_GLUE_INFO_T prGlueInfo = NULL;
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
UINT_32 u4BufLen = 0;
ASSERT(prNetDev);
ASSERT(prAddr);
if (GLUE_CHK_PR2(prNetDev, prAddr) == FALSE)
return -EINVAL;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
/* if (!netif_carrier_ok(prNetDev)) { */
/* return -ENOTCONN; */
/* } */
if (prGlueInfo->eParamMediaStateIndicated == PARAM_MEDIA_STATE_DISCONNECTED) {
memset(prAddr, 0, sizeof(*prAddr));
return 0;
}
rStatus = kalIoctl(prGlueInfo, wlanoidQueryBssid, prAddr->sa_data, ETH_ALEN, TRUE, FALSE, FALSE, &u4BufLen);
return 0;
} /* wext_get_ap */
/*----------------------------------------------------------------------------*/
/*!
* \brief To set mlme operation request.
*
* \param[in] prDev Net device requested.
* \param[in] prIwrInfo NULL.
* \param[in] prData Pointer of iw_point header.
* \param[in] pcExtra Pointer to iw_mlme structure mlme request information.
*
* \retval 0 For success.
* \retval -EOPNOTSUPP unsupported IW_MLME_ command.
* \retval -EINVAL Set MLME Fail, different bssid.
*
* \note Driver will start mlme operation if valid.
*/
/*----------------------------------------------------------------------------*/
static int
wext_set_mlme(IN struct net_device *prNetDev,
IN struct iw_request_info *prIwrInfo, IN struct iw_point *prData, IN char *pcExtra)
{
struct iw_mlme *prMlme = NULL;
P_GLUE_INFO_T prGlueInfo = NULL;
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
UINT_32 u4BufLen = 0;
ASSERT(prNetDev);
ASSERT(pcExtra);
if (GLUE_CHK_PR2(prNetDev, pcExtra) == FALSE)
return -EINVAL;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
prMlme = (struct iw_mlme *)pcExtra;
if (prMlme->cmd == IW_MLME_DEAUTH || prMlme->cmd == IW_MLME_DISASSOC) {
if (!netif_carrier_ok(prNetDev)) {
DBGLOG(INIT, INFO, "[wifi] Set MLME Deauth/Disassoc, but netif_carrier_off\n");
return 0;
}
rStatus = kalIoctl(prGlueInfo, wlanoidSetDisassociate, NULL, 0, FALSE, FALSE, TRUE, &u4BufLen);
return 0;
}
DBGLOG(INIT, INFO, "[wifi] unsupported IW_MLME_ command :%d\n", prMlme->cmd);
return -EOPNOTSUPP;
} /* wext_set_mlme */
/*----------------------------------------------------------------------------*/
/*!
* \brief To issue scan request.
*
* \param[in] prDev Net device requested.
* \param[in] prIwrInfo NULL.
* \param[in] prData NULL.
* \param[in] pcExtra NULL.
*
* \retval 0 For success.
* \retval -EFAULT Tx power is off.
*
* \note Device will start scanning.
*/
/*----------------------------------------------------------------------------*/
static int
wext_set_scan(IN struct net_device *prNetDev,
IN struct iw_request_info *prIwrInfo, IN union iwreq_data *prData, IN char *pcExtra)
{
P_GLUE_INFO_T prGlueInfo = NULL;
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
UINT_32 u4BufLen = 0;
int essid_len = 0;
ASSERT(prNetDev);
if (GLUE_CHK_DEV(prNetDev) == FALSE)
return -EINVAL;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
#if WIRELESS_EXT > 17
/* retrieve SSID */
if (prData)
essid_len = ((struct iw_scan_req *)(((struct iw_point *)prData)->pointer))->essid_len;
#endif
init_completion(&prGlueInfo->rScanComp);
/* TODO: parse flags and issue different scan requests? */
rStatus = kalIoctl(prGlueInfo, wlanoidSetBssidListScan, pcExtra, essid_len, FALSE, FALSE, FALSE, &u4BufLen);
/* wait_for_completion_interruptible_timeout(&prGlueInfo->rScanComp, 2 * KAL_HZ); */
/* kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_SCAN_COMPLETE, NULL, 0); */
return 0;
} /* wext_set_scan */
/*----------------------------------------------------------------------------*/
/*!
* \brief To write the ie to buffer
*
*/
/*----------------------------------------------------------------------------*/
static inline int snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len)
{
size_t i;
char *pos = buf, *end = buf + buf_size;
int ret;
if (buf_size == 0)
return 0;
for (i = 0; i < len; i++) {
ret = snprintf(pos, end - pos, "%02x", data[i]);
if (ret < 0 || ret >= end - pos) {
end[-1] = '\0';
return pos - buf;
}
pos += ret;
}
end[-1] = '\0';
return pos - buf;
}
/*----------------------------------------------------------------------------*/
/*!
* \brief To get scan results, transform results from driver's format to WE's.
*
* \param[in] prDev Net device requested.
* \param[in] prIwrInfo NULL.
* \param[out] prData Pointer to iw_point structure, pData->length is the size of
* pcExtra buffer before used, and is updated after filling scan
* results.
* \param[out] pcExtra Pointer to buffer which is allocated by caller of this
* function, wext_support_ioctl() or ioctl_standard_call() in
* wireless.c.
*
* \retval 0 For success.
* \retval -ENOMEM If dynamic memory allocation fail.
* \retval -E2BIG Invalid length.
*
* \note Scan results is filled into pcExtra buffer, data size is updated in
* pData->length.
*/
/*----------------------------------------------------------------------------*/
static int
wext_get_scan(IN struct net_device *prNetDev,
IN struct iw_request_info *prIwrInfo, IN OUT struct iw_point *prData, IN char *pcExtra)
{
UINT_32 i = 0;
UINT_32 j = 0;
P_PARAM_BSSID_LIST_EX_T prList = NULL;
P_PARAM_BSSID_EX_T prBss = NULL;
P_PARAM_VARIABLE_IE_T prDesiredIE = NULL;
struct iw_event iwEvent; /* local iw_event buffer */
/* write pointer of extra buffer */
char *pcCur = NULL;
/* pointer to the end of last full entry in extra buffer */
char *pcValidEntryEnd = NULL;
char *pcEnd = NULL; /* end of extra buffer */
UINT_32 u4AllocBufLen = 0;
/* arrange rate information */
UINT_32 u4HighestRate = 0;
char aucRatesBuf[64];
UINT_32 u4BufIndex;
/* return value */
int ret = 0;
P_GLUE_INFO_T prGlueInfo = NULL;
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
UINT_32 u4BufLen = 0;
ASSERT(prNetDev);
ASSERT(prData);
ASSERT(pcExtra);
if (GLUE_CHK_PR3(prNetDev, prData, pcExtra) == FALSE)
return -EINVAL;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
/* Initialize local variables */
pcCur = pcExtra;
pcValidEntryEnd = pcExtra;
pcEnd = pcExtra + prData->length; /* end of extra buffer */
/* Allocate another query buffer with the same size of extra buffer */
u4AllocBufLen = prData->length;
prList = kalMemAlloc(u4AllocBufLen, VIR_MEM_TYPE);
if (prList == NULL) {
DBGLOG(INIT, INFO, "[wifi] no memory for scan list:%d\n", prData->length);
ret = -ENOMEM;
goto error;
}
prList->u4NumberOfItems = 0;
/* wait scan done */
/* printk ("wait for scan results\n"); */
/* wait_for_completion_interruptible_timeout(&prGlueInfo->rScanComp, 4 * KAL_HZ); */
rStatus = kalIoctl(prGlueInfo, wlanoidQueryBssidList, prList, u4AllocBufLen, TRUE, FALSE, FALSE, &u4BufLen);
if (rStatus == WLAN_STATUS_INVALID_LENGTH) {
/* Buffer length is not large enough. */
/* printk(KERN_INFO "[wifi] buf:%d result:%ld\n", pData->length, u4BufLen); */
#if WIRELESS_EXT >= 17
/* This feature is supported in WE-17 or above, limited by iwlist.
** Return -E2BIG and iwlist will request again with a larger buffer.
*/
ret = -E2BIG;
/* Update length to give application a hint on result length */
prData->length = (__u16) u4BufLen;
goto error;
#else
/* Realloc a larger query buffer here, but don't write too much to extra
** buffer when filling it later.
*/
kalMemFree(prList, VIR_MEM_TYPE, u4AllocBufLen);
u4AllocBufLen = u4BufLen;
prList = kalMemAlloc(u4AllocBufLen, VIR_MEM_TYPE);
if (prList == NULL) {
DBGLOG(INIT, INFO, "[wifi] no memory for larger scan list :%ld\n", u4BufLen);
ret = -ENOMEM;
goto error;
}
prList->NumberOfItems = 0;
rStatus = kalIoctl(prGlueInfo,
wlanoidQueryBssidList, prList, u4AllocBufLen, TRUE, FALSE, FALSE, &u4BufLen);
if (rStatus == WLAN_STATUS_INVALID_LENGTH) {
DBGLOG(INIT, INFO, "[wifi] larger buf:%d result:%ld\n", u4AllocBufLen, u4BufLen);
ret = -E2BIG;
prData->length = (__u16) u4BufLen;
goto error;
}
#endif /* WIRELESS_EXT >= 17 */
}
if (prList->u4NumberOfItems > CFG_MAX_NUM_BSS_LIST) {
DBGLOG(INIT, INFO, "[wifi] strange scan result count:%ld\n", prList->u4NumberOfItems);
goto error;
}
/* Copy required data from pList to pcExtra */
prBss = &prList->arBssid[0]; /* set to the first entry */
for (i = 0; i < prList->u4NumberOfItems; ++i) {
/* BSSID */
iwEvent.cmd = SIOCGIWAP;
iwEvent.len = IW_EV_ADDR_LEN;
if ((pcCur + iwEvent.len) > pcEnd)
break;
iwEvent.u.ap_addr.sa_family = ARPHRD_ETHER;
kalMemCopy(iwEvent.u.ap_addr.sa_data, prBss->arMacAddress, ETH_ALEN);
memcpy(pcCur, &iwEvent, IW_EV_ADDR_LEN);
pcCur += IW_EV_ADDR_LEN;
/* SSID */
iwEvent.cmd = SIOCGIWESSID;
/* Modification to user space pointer(essid.pointer) is not needed. */
iwEvent.u.essid.length = (__u16) prBss->rSsid.u4SsidLen;
iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.essid.length;
if ((pcCur + iwEvent.len) > pcEnd)
break;
iwEvent.u.essid.flags = 1;
iwEvent.u.essid.pointer = NULL;
#if WIRELESS_EXT <= 18
memcpy(pcCur, &iwEvent, iwEvent.len);
#else
memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN);
memcpy(pcCur + IW_EV_LCP_LEN, &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF);
#endif
memcpy(pcCur + IW_EV_POINT_LEN, prBss->rSsid.aucSsid, iwEvent.u.essid.length);
pcCur += iwEvent.len;
/* Frequency */
iwEvent.cmd = SIOCGIWFREQ;
iwEvent.len = IW_EV_FREQ_LEN;
if ((pcCur + iwEvent.len) > pcEnd)
break;
iwEvent.u.freq.m = prBss->rConfiguration.u4DSConfig;
iwEvent.u.freq.e = 3; /* (in KHz) */
iwEvent.u.freq.i = 0;
memcpy(pcCur, &iwEvent, IW_EV_FREQ_LEN);
pcCur += IW_EV_FREQ_LEN;
/* Operation Mode */
iwEvent.cmd = SIOCGIWMODE;
iwEvent.len = IW_EV_UINT_LEN;
if ((pcCur + iwEvent.len) > pcEnd)
break;
if (prBss->eOpMode == NET_TYPE_IBSS)
iwEvent.u.mode = IW_MODE_ADHOC;
else if (prBss->eOpMode == NET_TYPE_INFRA)
iwEvent.u.mode = IW_MODE_INFRA;
else
iwEvent.u.mode = IW_MODE_AUTO;
memcpy(pcCur, &iwEvent, IW_EV_UINT_LEN);
pcCur += IW_EV_UINT_LEN;
/* Quality */
iwEvent.cmd = IWEVQUAL;
iwEvent.len = IW_EV_QUAL_LEN;
if ((pcCur + iwEvent.len) > pcEnd)
break;
iwEvent.u.qual.qual = 0; /* Quality not available now */
/* -100 < Rssi < -10, normalized by adding 0x100 */
iwEvent.u.qual.level = 0x100 + prBss->rRssi;
iwEvent.u.qual.noise = 0; /* Noise not available now */
iwEvent.u.qual.updated = IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID;
memcpy(pcCur, &iwEvent, IW_EV_QUAL_LEN);
pcCur += IW_EV_QUAL_LEN;
/* Security Mode */
iwEvent.cmd = SIOCGIWENCODE;
iwEvent.len = IW_EV_POINT_LEN;
if ((pcCur + iwEvent.len) > pcEnd)
break;
iwEvent.u.data.pointer = NULL;
iwEvent.u.data.flags = 0;
iwEvent.u.data.length = 0;
if (!prBss->u4Privacy)
iwEvent.u.data.flags |= IW_ENCODE_DISABLED;
#if WIRELESS_EXT <= 18
memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN);
#else
memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN);
memcpy(pcCur + IW_EV_LCP_LEN, &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF);
#endif
pcCur += IW_EV_POINT_LEN;
/* rearrange rate information */
u4BufIndex = sprintf(aucRatesBuf, "Rates (Mb/s):");
u4HighestRate = 0;
for (j = 0; j < PARAM_MAX_LEN_RATES_EX; ++j) {
UINT_8 curRate = prBss->rSupportedRates[j] & 0x7F;
if (curRate == 0)
break;
if (curRate > u4HighestRate)
u4HighestRate = curRate;
if (curRate == RATE_5_5M)
u4BufIndex += sprintf(aucRatesBuf + u4BufIndex, " 5.5");
else
u4BufIndex += sprintf(aucRatesBuf + u4BufIndex, " %d", curRate / 2);
#if DBG
if (u4BufIndex > sizeof(aucRatesBuf)) {
/* printk("rate info too long\n"); */
break;
}
#endif
}
/* Report Highest Rates */
iwEvent.cmd = SIOCGIWRATE;
iwEvent.len = IW_EV_PARAM_LEN;
if ((pcCur + iwEvent.len) > pcEnd)
break;
iwEvent.u.bitrate.value = u4HighestRate * 500000;
iwEvent.u.bitrate.fixed = 0;
iwEvent.u.bitrate.disabled = 0;
iwEvent.u.bitrate.flags = 0;
memcpy(pcCur, &iwEvent, iwEvent.len);
pcCur += iwEvent.len;
#if WIRELESS_EXT >= 15 /* IWEVCUSTOM is available in WE-15 or above */
/* Report Residual Rates */
iwEvent.cmd = IWEVCUSTOM;
iwEvent.u.data.length = u4BufIndex;
iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length;
if ((pcCur + iwEvent.len) > pcEnd)
break;
iwEvent.u.data.flags = 0;
#if WIRELESS_EXT <= 18
memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN);
#else
memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN);
memcpy(pcCur + IW_EV_LCP_LEN, &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF);
#endif
memcpy(pcCur + IW_EV_POINT_LEN, aucRatesBuf, u4BufIndex);
pcCur += iwEvent.len;
#endif /* WIRELESS_EXT >= 15 */
if (wextSrchDesiredWPAIE(&prBss->aucIEs[sizeof(PARAM_FIXED_IEs)],
prBss->u4IELength - sizeof(PARAM_FIXED_IEs),
0xDD, (PUINT_8 *) &prDesiredIE)) {
iwEvent.cmd = IWEVGENIE;
iwEvent.u.data.flags = 1;
iwEvent.u.data.length = 2 + (__u16) prDesiredIE->ucLength;
iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length;
if ((pcCur + iwEvent.len) > pcEnd)
break;
#if WIRELESS_EXT <= 18
memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN);
#else
memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN);
memcpy(pcCur + IW_EV_LCP_LEN,
&iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF);
#endif
memcpy(pcCur + IW_EV_POINT_LEN, prDesiredIE, 2 + prDesiredIE->ucLength);
pcCur += iwEvent.len;
}
#if CFG_SUPPORT_WPS /* search WPS IE (0xDD, 221, OUI: 0x0050f204 ) */
if (wextSrchDesiredWPSIE(&prBss->aucIEs[sizeof(PARAM_FIXED_IEs)],
prBss->u4IELength - sizeof(PARAM_FIXED_IEs),
0xDD, (PUINT_8 *) &prDesiredIE)) {
iwEvent.cmd = IWEVGENIE;
iwEvent.u.data.flags = 1;
iwEvent.u.data.length = 2 + (__u16) prDesiredIE->ucLength;
iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length;
if ((pcCur + iwEvent.len) > pcEnd)
break;
#if WIRELESS_EXT <= 18
memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN);
#else
memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN);
memcpy(pcCur + IW_EV_LCP_LEN,
&iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF);
#endif
memcpy(pcCur + IW_EV_POINT_LEN, prDesiredIE, 2 + prDesiredIE->ucLength);
pcCur += iwEvent.len;
}
#endif
/* Search RSN IE (0x30, 48). pBss->IEs starts from timestamp. */
/* pBss->IEs starts from timestamp */
if (wextSrchDesiredWPAIE(&prBss->aucIEs[sizeof(PARAM_FIXED_IEs)],
prBss->u4IELength - sizeof(PARAM_FIXED_IEs),
0x30, (PUINT_8 *) &prDesiredIE)) {
iwEvent.cmd = IWEVGENIE;
iwEvent.u.data.flags = 1;
iwEvent.u.data.length = 2 + (__u16) prDesiredIE->ucLength;
iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length;
if ((pcCur + iwEvent.len) > pcEnd)
break;
#if WIRELESS_EXT <= 18
memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN);
#else
memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN);
memcpy(pcCur + IW_EV_LCP_LEN,
&iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF);
#endif
memcpy(pcCur + IW_EV_POINT_LEN, prDesiredIE, 2 + prDesiredIE->ucLength);
pcCur += iwEvent.len;
}
#if CFG_SUPPORT_WAPI /* Android+ */
if (wextSrchDesiredWAPIIE(&prBss->aucIEs[sizeof(PARAM_FIXED_IEs)],
prBss->u4IELength - sizeof(PARAM_FIXED_IEs), (PUINT_8 *) &prDesiredIE)) {
#if 0
iwEvent.cmd = IWEVGENIE;
iwEvent.u.data.flags = 1;
iwEvent.u.data.length = 2 + (__u16) prDesiredIE->ucLength;
iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length;
if ((pcCur + iwEvent.len) > pcEnd)
break;
#if WIRELESS_EXT <= 18
memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN);
#else
memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN);
memcpy(pcCur + IW_EV_LCP_LEN,
&iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF);
#endif
memcpy(pcCur + IW_EV_POINT_LEN, prDesiredIE, 2 + prDesiredIE->ucLength);
pcCur += iwEvent.len;
#else
iwEvent.cmd = IWEVCUSTOM;
iwEvent.u.data.length = (2 + prDesiredIE->ucLength) * 2 + 8 /* wapi_ie= */;
iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length;
if ((pcCur + iwEvent.len) > pcEnd)
break;
iwEvent.u.data.flags = 1;
memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN);
memcpy(pcCur + IW_EV_LCP_LEN,
&iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF);
pcCur += (IW_EV_POINT_LEN);
pcCur += sprintf(pcCur, "wapi_ie=");
snprintf_hex(pcCur, pcEnd - pcCur, (UINT_8 *) prDesiredIE, prDesiredIE->ucLength + 2);
pcCur += (2 + prDesiredIE->ucLength) * 2 /* iwEvent.len */;
#endif
}
#endif
/* Complete an entry. Update end of valid entry */
pcValidEntryEnd = pcCur;
/* Extract next bss */
prBss = (P_PARAM_BSSID_EX_T) ((char *)prBss + prBss->u4Length);
}
/* Update valid data length for caller function and upper layer
* applications.
*/
prData->length = (pcValidEntryEnd - pcExtra);
/* printk(KERN_INFO "[wifi] buf:%d result:%ld\n", pData->length, u4BufLen); */
/* kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_SCAN_COMPLETE, NULL, 0); */
error:
/* free local query buffer */
if (prList)
kalMemFree(prList, VIR_MEM_TYPE, u4AllocBufLen);
return ret;
} /* wext_get_scan */
/*----------------------------------------------------------------------------*/
/*!
* \brief To set desired network name ESSID.
*
* \param[in] prDev Net device requested.
* \param[in] prIwrInfo NULL.
* \param[in] prEssid Pointer of iw_point header.
* \param[in] pcExtra Pointer to buffer srtoring essid string.
*
* \retval 0 If netif_carrier_ok.
* \retval -E2BIG Essid string length is too big.
* \retval -EINVAL pcExtra is null pointer.
* \retval -EFAULT Driver fail to set new essid.
*
* \note If string length is ok, device will try connecting to the new network.
*/
/*----------------------------------------------------------------------------*/
static int
wext_set_essid(IN struct net_device *prNetDev,
IN struct iw_request_info *prIwrInfo, IN struct iw_point *prEssid, IN char *pcExtra)
{
PARAM_SSID_T rNewSsid;
UINT_32 cipher;
ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus;
ENUM_PARAM_AUTH_MODE_T eAuthMode;
P_GLUE_INFO_T prGlueInfo = NULL;
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
UINT_32 u4BufLen = 0;
ASSERT(prNetDev);
ASSERT(prEssid);
ASSERT(pcExtra);
if (GLUE_CHK_PR3(prNetDev, prEssid, pcExtra) == FALSE)
return -EINVAL;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
if (prEssid->length > IW_ESSID_MAX_SIZE)
return -E2BIG;
/* set auth mode */
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;
/* printk(KERN_INFO "IW_AUTH_WPA_VERSION_DISABLED->Param_AuthMode%s\n", */
/* (eAuthMode == AUTH_MODE_OPEN) ? "Open" : "Shared"); */
} else {
/* set auth mode */
switch (prGlueInfo->rWpaInfo.u4KeyMgmt) {
case IW_AUTH_KEY_MGMT_802_1X:
eAuthMode =
(prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_WPA) ?
AUTH_MODE_WPA : AUTH_MODE_WPA2;
/* printk("IW_AUTH_KEY_MGMT_802_1X->AUTH_MODE_WPA%s\n", */
/* (eAuthMode == AUTH_MODE_WPA) ? "" : "2"); */
break;
case IW_AUTH_KEY_MGMT_PSK:
eAuthMode =
(prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_WPA) ?
AUTH_MODE_WPA_PSK : AUTH_MODE_WPA2_PSK;
/* printk("IW_AUTH_KEY_MGMT_PSK->AUTH_MODE_WPA%sPSK\n", */
/* (eAuthMode == AUTH_MODE_WPA_PSK) ? "" : "2"); */
break;
#if CFG_SUPPORT_WAPI /* Android+ */
case IW_AUTH_KEY_MGMT_WAPI_PSK:
break;
case IW_AUTH_KEY_MGMT_WAPI_CERT:
break;
#endif
/* #if defined (IW_AUTH_KEY_MGMT_WPA_NONE) */
/* case IW_AUTH_KEY_MGMT_WPA_NONE: */
/* eAuthMode = AUTH_MODE_WPA_NONE; */
/* //printk("IW_AUTH_KEY_MGMT_WPA_NONE->AUTH_MODE_WPA_NONE\n"); */
/* break; */
/* #endif */
#if CFG_SUPPORT_802_11W
case IW_AUTH_KEY_MGMT_802_1X_SHA256:
eAuthMode = AUTH_MODE_WPA2;
break;
case IW_AUTH_KEY_MGMT_PSK_SHA256:
eAuthMode = AUTH_MODE_WPA2_PSK;
break;
#endif
default:
/* printk(KERN_INFO DRV_NAME"strange IW_AUTH_KEY_MGMT : %ld set auto switch\n", */
/* prGlueInfo->rWpaInfo.u4KeyMgmt); */
eAuthMode = AUTH_MODE_AUTO_SWITCH;
break;
}
}
rStatus = kalIoctl(prGlueInfo,
wlanoidSetAuthMode, &eAuthMode, sizeof(eAuthMode), FALSE, FALSE, FALSE, &u4BufLen);
/* set encryption status */
cipher = prGlueInfo->rWpaInfo.u4CipherGroup | prGlueInfo->rWpaInfo.u4CipherPairwise;
if (cipher & IW_AUTH_CIPHER_CCMP) {
/* printk("IW_AUTH_CIPHER_CCMP->ENUM_ENCRYPTION3_ENABLED\n"); */
eEncStatus = ENUM_ENCRYPTION3_ENABLED;
} else if (cipher & IW_AUTH_CIPHER_TKIP) {
/* printk("IW_AUTH_CIPHER_TKIP->ENUM_ENCRYPTION2_ENABLED\n"); */
eEncStatus = ENUM_ENCRYPTION2_ENABLED;
} else if (cipher & (IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40)) {
/* printk("IW_AUTH_CIPHER_WEPx->ENUM_ENCRYPTION1_ENABLED\n"); */
eEncStatus = ENUM_ENCRYPTION1_ENABLED;
} else if (cipher & IW_AUTH_CIPHER_NONE) {
/* printk("IW_AUTH_CIPHER_NONE->ENUM_ENCRYPTION_DISABLED\n"); */
if (prGlueInfo->rWpaInfo.fgPrivacyInvoke)
eEncStatus = ENUM_ENCRYPTION1_ENABLED;
else
eEncStatus = ENUM_ENCRYPTION_DISABLED;
} else {
/* printk("unknown IW_AUTH_CIPHER->Param_EncryptionDisabled\n"); */
eEncStatus = ENUM_ENCRYPTION_DISABLED;
}
rStatus = kalIoctl(prGlueInfo,
wlanoidSetEncryptionStatus, &eEncStatus, sizeof(eEncStatus), FALSE, FALSE, FALSE, &u4BufLen);
#if WIRELESS_EXT < 21
/* GeorgeKuo: a length error bug exists in (WE < 21) cases, kernel before
** 2.6.19. Cut the trailing '\0'.
*/
rNewSsid.u4SsidLen = (prEssid->length) ? prEssid->length - 1 : 0;
#else
rNewSsid.u4SsidLen = prEssid->length;
#endif
kalMemCopy(rNewSsid.aucSsid, pcExtra, rNewSsid.u4SsidLen);
/*
* rNewSsid.aucSsid[rNewSsid.u4SsidLen] = '\0';
* printk("set ssid(%lu): %s\n", rNewSsid.u4SsidLen, rNewSsid.aucSsid);
*/
if (kalIoctl(prGlueInfo,
wlanoidSetSsid,
(PVOID)&rNewSsid, sizeof(PARAM_SSID_T), FALSE, FALSE, TRUE, &u4BufLen) != WLAN_STATUS_SUCCESS) {
/* printk(KERN_WARNING "Fail to set ssid\n"); */
return -EFAULT;
}
return 0;
} /* wext_set_essid */
/*----------------------------------------------------------------------------*/
/*!
* \brief To get current network name ESSID.
*
* \param[in] prDev Net device requested.
* \param[in] prIwrInfo NULL.
* \param[in] prEssid Pointer to iw_point structure containing essid information.
* \param[out] pcExtra Pointer to buffer srtoring essid string.
*
* \retval 0 If netif_carrier_ok.
* \retval -ENOTCONN Otherwise.
*
* \note If netif_carrier_ok, network essid is stored in pcExtra.
*/
/*----------------------------------------------------------------------------*/
/* static PARAM_SSID_T ssid; */
static int
wext_get_essid(IN struct net_device *prNetDev,
IN struct iw_request_info *prIwrInfo, IN struct iw_point *prEssid, OUT char *pcExtra)
{
/* PARAM_SSID_T ssid; */
P_PARAM_SSID_T prSsid;
P_GLUE_INFO_T prGlueInfo = NULL;
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
UINT_32 u4BufLen = 0;
ASSERT(prNetDev);
ASSERT(prEssid);
ASSERT(pcExtra);
if (GLUE_CHK_PR3(prNetDev, prEssid, pcExtra) == FALSE)
return -EINVAL;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
/* if (!netif_carrier_ok(prNetDev)) { */
/* return -ENOTCONN; */
/* } */
prSsid = kalMemAlloc(sizeof(PARAM_SSID_T), VIR_MEM_TYPE);
if (!prSsid)
return -ENOMEM;
rStatus = kalIoctl(prGlueInfo, wlanoidQuerySsid, prSsid, sizeof(PARAM_SSID_T), TRUE, FALSE, FALSE, &u4BufLen);
if ((rStatus == WLAN_STATUS_SUCCESS) && (prSsid->u4SsidLen <= MAX_SSID_LEN)) {
kalMemCopy(pcExtra, prSsid->aucSsid, prSsid->u4SsidLen);
prEssid->length = prSsid->u4SsidLen;
prEssid->flags = 1;
}
kalMemFree(prSsid, VIR_MEM_TYPE, sizeof(PARAM_SSID_T));
return rStatus;
} /* wext_get_essid */
#if 0
/*----------------------------------------------------------------------------*/
/*!
* \brief To set tx desired bit rate. Three cases here
* iwconfig wlan0 auto -> Set to origianl supported rate set.
* iwconfig wlan0 18M -> Imply "fixed" case, set to 18Mbps as desired rate.
* iwconfig wlan0 18M auto -> Set to auto rate lower and equal to 18Mbps
*
* \param[in] prNetDev Pointer to the net_device handler.
* \param[in] prIwReqInfo Pointer to the Request Info.
* \param[in] prRate Pointer to the Rate Parameter.
* \param[in] pcExtra Pointer to the extra buffer.
*
* \retval 0 Update desired rate.
* \retval -EINVAL Wrong parameter
*/
/*----------------------------------------------------------------------------*/
int
wext_set_rate(IN struct net_device *prNetDev,
IN struct iw_request_info *prIwReqInfo, IN struct iw_param *prRate, IN char *pcExtra)
{
PARAM_RATES_EX aucSuppRate = { 0 };
PARAM_RATES_EX aucNewRate = { 0 };
UINT_32 u4NewRateLen = 0;
UINT_32 i;
P_GLUE_INFO_T prGlueInfo = NULL;
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
UINT_32 u4BufLen = 0;
ASSERT(prNetDev);
ASSERT(prRate);
if (GLUE_CHK_PR2(prNetDev, prRate) == FALSE)
return -EINVAL;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
/*
* printk("value = %d, fixed = %d, disable = %d, flags = %d\n",
* prRate->value, prRate->fixed, prRate->disabled, prRate->flags);
*/
rStatus = wlanQueryInformation(prGlueInfo->prAdapter,
wlanoidQuerySupportedRates, &aucSuppRate, sizeof(aucSuppRate), &u4BufLen);
/* Case: AUTO */
if (prRate->value < 0) {
if (prRate->fixed == 0) {
/* iwconfig wlan0 rate auto */
/* set full supported rate to device */
/* printk("wlanoidQuerySupportedRates():u4BufLen = %ld\n", u4BufLen); */
rStatus = wlanSetInformation(prGlueInfo->prAdapter,
wlanoidSetDesiredRates,
&aucSuppRate, sizeof(aucSuppRate), &u4BufLen);
return 0;
}
/* iwconfig wlan0 rate fixed */
/* fix rate to what? DO NOTHING */
return -EINVAL;
}
aucNewRate[0] = prRate->value / 500000; /* In unit of 500k */
for (i = 0; i < PARAM_MAX_LEN_RATES_EX; i++) {
/* check the given value is supported */
if (aucSuppRate[i] == 0)
break;
if (aucNewRate[0] == aucSuppRate[i]) {
u4NewRateLen = 1;
break;
}
}
if (u4NewRateLen == 0) {
/* the given value is not supported */
/* return error or use given rate as upper bound? */
return -EINVAL;
}
if (prRate->fixed == 0) {
/* add all rates lower than desired rate */
for (i = 0; i < PARAM_MAX_LEN_RATES_EX; ++i) {
if (aucSuppRate[i] == 0)
break;
if (aucSuppRate[i] < aucNewRate[0])
aucNewRate[u4NewRateLen++] = aucSuppRate[i];
}
}
rStatus = wlanSetInformation(prGlueInfo->prAdapter,
wlanoidSetDesiredRates, &aucNewRate, sizeof(aucNewRate), &u4BufLen);
return 0;
} /* wext_set_rate */
#endif
/*----------------------------------------------------------------------------*/
/*!
* \brief To get current tx bit rate.
*
* \param[in] prDev Net device requested.
* \param[in] prIwrInfo NULL.
* \param[out] prRate Pointer to iw_param structure to store current tx rate.
* \param[in] pcExtra NULL.
*
* \retval 0 If netif_carrier_ok.
* \retval -ENOTCONN Otherwise.
*
* \note If netif_carrier_ok, current tx rate is stored in pRate.
*/
/*----------------------------------------------------------------------------*/
static int
wext_get_rate(IN struct net_device *prNetDev,
IN struct iw_request_info *prIwrInfo, OUT struct iw_param *prRate, IN char *pcExtra)
{
P_GLUE_INFO_T prGlueInfo = NULL;
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
UINT_32 u4BufLen = 0;
UINT_32 u4Rate = 0;
ASSERT(prNetDev);
ASSERT(prRate);
if (GLUE_CHK_PR2(prNetDev, prRate) == FALSE)
return -EINVAL;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
if (!netif_carrier_ok(prNetDev))
return -ENOTCONN;
rStatus = kalIoctl(prGlueInfo, wlanoidQueryLinkSpeed, &u4Rate, sizeof(u4Rate), TRUE, FALSE, FALSE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
return -EFAULT;
prRate->value = u4Rate * 100; /* u4Rate is in unit of 100bps */
prRate->fixed = 0;
return 0;
} /* wext_get_rate */
/*----------------------------------------------------------------------------*/
/*!
* \brief To set RTS/CTS theshold.
*
* \param[in] prDev Net device requested.
* \param[in] prIwrInfo NULL.
* \param[in] prRts Pointer to iw_param structure containing rts threshold.
* \param[in] pcExtra NULL.
*
* \retval 0 For success.
* \retval -EINVAL Given value is out of range.
*
* \note If given value is valid, device will follow the new setting.
*/
/*----------------------------------------------------------------------------*/
static int
wext_set_rts(IN struct net_device *prNetDev,
IN struct iw_request_info *prIwrInfo, IN struct iw_param *prRts, IN char *pcExtra)
{
PARAM_RTS_THRESHOLD u4RtsThresh;
P_GLUE_INFO_T prGlueInfo = NULL;
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
UINT_32 u4BufLen = 0;
ASSERT(prNetDev);
ASSERT(prRts);
if (GLUE_CHK_PR2(prNetDev, prRts) == FALSE)
return -EINVAL;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
if (prRts->value < 0 || prRts->value > 2347)
return -EINVAL;
if (prRts->disabled == 1)
u4RtsThresh = 2347;
else
u4RtsThresh = (PARAM_RTS_THRESHOLD) prRts->value;
rStatus = kalIoctl(prGlueInfo,
wlanoidSetRtsThreshold, &u4RtsThresh, sizeof(u4RtsThresh), FALSE, FALSE, FALSE, &u4BufLen);
prRts->value = (typeof(prRts->value)) u4RtsThresh;
prRts->disabled = (prRts->value > 2347) ? 1 : 0;
prRts->fixed = 1;
return 0;
} /* wext_set_rts */
/*----------------------------------------------------------------------------*/
/*!
* \brief To get RTS/CTS theshold.
*
* \param[in] prDev Net device requested.
* \param[in] prIwrInfo NULL.
* \param[out] prRts Pointer to iw_param structure containing rts threshold.
* \param[in] pcExtra NULL.
*
* \retval 0 Success.
*
* \note RTS threshold is stored in pRts.
*/
/*----------------------------------------------------------------------------*/
static int
wext_get_rts(IN struct net_device *prNetDev,
IN struct iw_request_info *prIwrInfo, OUT struct iw_param *prRts, IN char *pcExtra)
{
PARAM_RTS_THRESHOLD u4RtsThresh;
P_GLUE_INFO_T prGlueInfo = NULL;
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
UINT_32 u4BufLen = 0;
ASSERT(prNetDev);
ASSERT(prRts);
if (GLUE_CHK_PR2(prNetDev, prRts) == FALSE)
return -EINVAL;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
rStatus = kalIoctl(prGlueInfo,
wlanoidQueryRtsThreshold, &u4RtsThresh, sizeof(u4RtsThresh), TRUE, FALSE, FALSE, &u4BufLen);
prRts->value = (typeof(prRts->value)) u4RtsThresh;
prRts->disabled = (prRts->value > 2347 || prRts->value < 0) ? 1 : 0;
prRts->fixed = 1;
return 0;
} /* wext_get_rts */
/*----------------------------------------------------------------------------*/
/*!
* \brief To get fragmentation threshold.
*
* \param[in] prDev Net device requested.
* \param[in] prIwrInfo NULL.
* \param[out] prFrag Pointer to iw_param structure containing frag threshold.
* \param[in] pcExtra NULL.
*
* \retval 0 Success.
*
* \note RTS threshold is stored in pFrag. Fragmentation is disabled.
*/
/*----------------------------------------------------------------------------*/
static int
wext_get_frag(IN struct net_device *prNetDev,
IN struct iw_request_info *prIwrInfo, OUT struct iw_param *prFrag, IN char *pcExtra)
{
ASSERT(prFrag);
prFrag->value = 2346;
prFrag->fixed = 1;
prFrag->disabled = 1;
return 0;
} /* wext_get_frag */
#if 1
/*----------------------------------------------------------------------------*/
/*!
* \brief To set TX power, or enable/disable the radio.
*
* \param[in] prDev Net device requested.
* \param[in] prIwrInfo NULL.
* \param[in] prTxPow Pointer to iw_param structure containing tx power setting.
* \param[in] pcExtra NULL.
*
* \retval 0 Success.
*
* \note Tx power is stored in pTxPow. iwconfig wlan0 txpow on/off are used
* to enable/disable the radio.
*/
/*----------------------------------------------------------------------------*/
static int
wext_set_txpow(IN struct net_device *prNetDev,
IN struct iw_request_info *prIwrInfo, IN struct iw_param *prTxPow, IN char *pcExtra)
{
int ret = 0;
/* PARAM_DEVICE_POWER_STATE ePowerState; */
ENUM_ACPI_STATE_T ePowerState;
P_GLUE_INFO_T prGlueInfo = NULL;
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
UINT_32 u4BufLen = 0;
ASSERT(prNetDev);
ASSERT(prTxPow);
if (GLUE_CHK_PR2(prNetDev, prTxPow) == FALSE)
return -EINVAL;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
if (prTxPow->disabled) {
/* <1> disconnect */
rStatus = kalIoctl(prGlueInfo, wlanoidSetDisassociate, NULL, 0, FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
/* ToDo:: DBGLOG */
DBGLOG(INIT, INFO, "######set disassoc failed\n");
} else {
DBGLOG(INIT, INFO, "######set assoc ok\n");
}
/* <2> mark to power state flag */
ePowerState = ACPI_STATE_D0;
DBGLOG(INIT, INFO, "set to acpi d3(0)\n");
wlanSetAcpiState(prGlueInfo->prAdapter, ePowerState);
} else {
ePowerState = ACPI_STATE_D0;
DBGLOG(INIT, INFO, "set to acpi d0\n");
wlanSetAcpiState(prGlueInfo->prAdapter, ePowerState);
}
prGlueInfo->ePowerState = ParamDeviceStateD0;
return ret;
} /* wext_set_txpow */
#endif
/*----------------------------------------------------------------------------*/
/*!
* \brief To get TX power.
*
* \param[in] prDev Net device requested.
* \param[in] prIwrInfo NULL.
* \param[out] prTxPow Pointer to iw_param structure containing tx power setting.
* \param[in] pcExtra NULL.
*
* \retval 0 Success.
*
* \note Tx power is stored in pTxPow.
*/
/*----------------------------------------------------------------------------*/
static int
wext_get_txpow(IN struct net_device *prNetDev,
IN struct iw_request_info *prIwrInfo, OUT struct iw_param *prTxPow, IN char *pcExtra)
{
/* PARAM_DEVICE_POWER_STATE ePowerState; */
P_GLUE_INFO_T prGlueInfo = NULL;
ASSERT(prNetDev);
ASSERT(prTxPow);
if (GLUE_CHK_PR2(prNetDev, prTxPow) == FALSE)
return -EINVAL;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
/* GeorgeKuo: wlanoidQueryAcpiDevicePowerState() reports capability, not
* current state. Use GLUE_INFO_T to store state.
*/
/* ePowerState = prGlueInfo->ePowerState; */
/* TxPow parameters: Fixed at relative 100% */
#if WIRELESS_EXT < 17
prTxPow->flags = 0x0002; /* IW_TXPOW_RELATIVE */
#else
prTxPow->flags = IW_TXPOW_RELATIVE;
#endif
prTxPow->value = 100;
prTxPow->fixed = 1;
/* prTxPow->disabled = (ePowerState != ParamDeviceStateD3) ? FALSE : TRUE; */
prTxPow->disabled = TRUE;
return 0;
} /* wext_get_txpow */
/*----------------------------------------------------------------------------*/
/*!
* \brief To get encryption cipher and key.
*
* \param[in] prDev Net device requested.
* \param[in] prIwrInfo NULL.
* \param[out] prEnc Pointer to iw_point structure containing securiry information.
* \param[in] pcExtra Buffer to store key content.
*
* \retval 0 Success.
*
* \note Securiry information is stored in pEnc except key content.
*/
/*----------------------------------------------------------------------------*/
static int
wext_get_encode(IN struct net_device *prNetDev,
IN struct iw_request_info *prIwrInfo, OUT struct iw_point *prEnc, IN char *pcExtra)
{
#if 1
/* ENUM_ENCRYPTION_STATUS_T eEncMode; */
ENUM_PARAM_ENCRYPTION_STATUS_T eEncMode;
P_GLUE_INFO_T prGlueInfo = NULL;
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
UINT_32 u4BufLen = 0;
ASSERT(prNetDev);
ASSERT(prEnc);
if (GLUE_CHK_PR2(prNetDev, prEnc) == FALSE)
return -EINVAL;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
rStatus = kalIoctl(prGlueInfo,
wlanoidQueryEncryptionStatus, &eEncMode, sizeof(eEncMode), TRUE, FALSE, FALSE, &u4BufLen);
switch (eEncMode) {
case ENUM_WEP_DISABLED:
prEnc->flags = IW_ENCODE_DISABLED;
break;
case ENUM_WEP_ENABLED:
prEnc->flags = IW_ENCODE_ENABLED;
break;
case ENUM_WEP_KEY_ABSENT:
prEnc->flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
break;
default:
prEnc->flags = IW_ENCODE_ENABLED;
break;
}
/* Cipher, Key Content, Key ID can't be queried */
prEnc->flags |= IW_ENCODE_NOKEY;
#endif
return 0;
} /* wext_get_encode */
/*----------------------------------------------------------------------------*/
/*!
* \brief To set encryption cipher and key.
*
* \param[in] prDev Net device requested.
* \param[in] prIwrInfo NULL.
* \param[in] prEnc Pointer to iw_point structure containing securiry information.
* \param[in] pcExtra Pointer to key string buffer.
*
* \retval 0 Success.
* \retval -EINVAL Key ID error for WEP.
* \retval -EFAULT Setting parameters to driver fail.
* \retval -EOPNOTSUPP Key size not supported.
*
* \note Securiry information is stored in pEnc.
*/
/*----------------------------------------------------------------------------*/
static UINT_8 wepBuf[48];
static int
wext_set_encode(IN struct net_device *prNetDev,
IN struct iw_request_info *prIwrInfo, IN struct iw_point *prEnc, IN char *pcExtra)
{
#if 1
ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus;
ENUM_PARAM_AUTH_MODE_T eAuthMode;
/* UINT_8 wepBuf[48]; */
P_PARAM_WEP_T prWepKey = (P_PARAM_WEP_T) wepBuf;
P_GLUE_INFO_T prGlueInfo = NULL;
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
UINT_32 u4BufLen = 0;
ASSERT(prNetDev);
ASSERT(prEnc);
ASSERT(pcExtra);
if (GLUE_CHK_PR3(prNetDev, prEnc, pcExtra) == FALSE)
return -EINVAL;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
/* reset to default mode */
prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED;
prGlueInfo->rWpaInfo.u4KeyMgmt = 0;
prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE;
prGlueInfo->rWpaInfo.u4CipherGroup = 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
/* iwconfig wlan0 key off */
if ((prEnc->flags & IW_ENCODE_MODE) == IW_ENCODE_DISABLED) {
eAuthMode = AUTH_MODE_OPEN;
rStatus = kalIoctl(prGlueInfo,
wlanoidSetAuthMode, &eAuthMode, sizeof(eAuthMode), FALSE, FALSE, FALSE, &u4BufLen);
eEncStatus = ENUM_ENCRYPTION_DISABLED;
rStatus = kalIoctl(prGlueInfo,
wlanoidSetEncryptionStatus,
&eEncStatus, sizeof(eEncStatus), FALSE, FALSE, FALSE, &u4BufLen);
return 0;
}
/* iwconfig wlan0 key 0123456789 */
/* iwconfig wlan0 key s:abcde */
/* iwconfig wlan0 key 0123456789 [1] */
/* iwconfig wlan0 key 01234567890123456789012345 [1] */
/* check key size for WEP */
if (prEnc->length == 5 || prEnc->length == 13 || prEnc->length == 16) {
/* prepare PARAM_WEP key structure */
prWepKey->u4KeyIndex = (prEnc->flags & IW_ENCODE_INDEX) ? (prEnc->flags & IW_ENCODE_INDEX) - 1 : 0;
if (prWepKey->u4KeyIndex > 3) {
/* key id is out of range */
return -EINVAL;
}
prWepKey->u4KeyIndex |= 0x80000000;
prWepKey->u4Length = 12 + prEnc->length;
prWepKey->u4KeyLength = prEnc->length;
kalMemCopy(prWepKey->aucKeyMaterial, pcExtra, prEnc->length);
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;
}
/* change to auto switch */
prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_SHARED_KEY | IW_AUTH_ALG_OPEN_SYSTEM;
eAuthMode = AUTH_MODE_AUTO_SWITCH;
rStatus = kalIoctl(prGlueInfo,
wlanoidSetAuthMode, &eAuthMode, sizeof(eAuthMode), FALSE, FALSE, FALSE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
/* printk(KERN_INFO DRV_NAME"wlanoidSetAuthMode fail 0x%lx\n", rStatus); */
return -EFAULT;
}
prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40;
prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40;
eEncStatus = ENUM_WEP_ENABLED;
rStatus = kalIoctl(prGlueInfo,
wlanoidSetEncryptionStatus,
&eEncStatus, sizeof(ENUM_PARAM_ENCRYPTION_STATUS_T), FALSE, FALSE, FALSE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
/* printk(KERN_INFO DRV_NAME"wlanoidSetEncryptionStatus fail 0x%lx\n", rStatus); */
return -EFAULT;
}
return 0;
}
#endif
return -EOPNOTSUPP;
} /* wext_set_encode */
/*----------------------------------------------------------------------------*/
/*!
* \brief To set power management.
*
* \param[in] prDev Net device requested.
* \param[in] prIwrInfo NULL.
* \param[in] prPower Pointer to iw_param structure containing tx power setting.
* \param[in] pcExtra NULL.
*
* \retval 0 Success.
*
* \note New Power Management Mode is set to driver.
*/
/*----------------------------------------------------------------------------*/
static int
wext_set_power(IN struct net_device *prNetDev,
IN struct iw_request_info *prIwrInfo, IN struct iw_param *prPower, IN char *pcExtra)
{
#if 1
PARAM_POWER_MODE ePowerMode;
INT_32 i4PowerValue;
P_GLUE_INFO_T prGlueInfo = NULL;
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
UINT_32 u4BufLen = 0;
PARAM_POWER_MODE_T rPowerMode;
ASSERT(prNetDev);
ASSERT(prPower);
if (GLUE_CHK_PR2(prNetDev, prPower) == FALSE)
return -EINVAL;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
if (!prGlueInfo)
return -EFAULT;
if (!prGlueInfo->prAdapter->prAisBssInfo)
return -EFAULT;
/* printk(KERN_INFO "wext_set_power value(%d) disabled(%d) flag(0x%x)\n", */
/* prPower->value, prPower->disabled, prPower->flags); */
if (prPower->disabled) {
ePowerMode = Param_PowerModeCAM;
} else {
i4PowerValue = prPower->value;
#if WIRELESS_EXT < 21
i4PowerValue /= 1000000;
#endif
if (i4PowerValue == 0) {
ePowerMode = Param_PowerModeCAM;
} else if (i4PowerValue == 1) {
ePowerMode = Param_PowerModeMAX_PSP;
} else if (i4PowerValue == 2) {
ePowerMode = Param_PowerModeFast_PSP;
} else {
DBGLOG(INIT, INFO, "%s(): unsupported power management mode value = %d.\n",
__func__, prPower->value);
return -EINVAL;
}
}
rPowerMode.ePowerMode = ePowerMode;
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) {
/* printk(KERN_INFO DRV_NAME"wlanoidSet802dot11PowerSaveProfile fail 0x%lx\n", rStatus); */
return -EFAULT;
}
#endif
return 0;
} /* wext_set_power */
/*----------------------------------------------------------------------------*/
/*!
* \brief To get power management.
*
* \param[in] prDev Net device requested.
* \param[in] prIwrInfo NULL.
* \param[out] prPower Pointer to iw_param structure containing tx power setting.
* \param[in] pcExtra NULL.
*
* \retval 0 Success.
*
* \note Power management mode is stored in pTxPow->value.
*/
/*----------------------------------------------------------------------------*/
static int
wext_get_power(IN struct net_device *prNetDev,
IN struct iw_request_info *prIwrInfo, OUT struct iw_param *prPower, IN char *pcExtra)
{
P_GLUE_INFO_T prGlueInfo = NULL;
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
UINT_32 u4BufLen = 0;
PARAM_POWER_MODE ePowerMode = Param_PowerModeCAM;
ASSERT(prNetDev);
ASSERT(prPower);
if (GLUE_CHK_PR2(prNetDev, prPower) == FALSE)
return -EINVAL;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
#if 0
#if defined(_HIF_SDIO)
rStatus = sdio_io_ctrl(prGlueInfo,
wlanoidQuery802dot11PowerSaveProfile,
&ePowerMode, sizeof(ePowerMode), TRUE, TRUE, &u4BufLen);
#else
rStatus = wlanQueryInformation(prGlueInfo->prAdapter,
wlanoidQuery802dot11PowerSaveProfile,
&ePowerMode, sizeof(ePowerMode), &u4BufLen);
#endif
#else
rStatus = wlanQueryInformation(prGlueInfo->prAdapter,
wlanoidQuery802dot11PowerSaveProfile,
&ePowerMode, sizeof(ePowerMode), &u4BufLen);
#endif
if (rStatus != WLAN_STATUS_SUCCESS)
return -EFAULT;
prPower->value = 0;
prPower->disabled = 1;
if (Param_PowerModeCAM == ePowerMode) {
prPower->value = 0;
prPower->disabled = 1;
} else if (Param_PowerModeMAX_PSP == ePowerMode) {
prPower->value = 1;
prPower->disabled = 0;
} else if (Param_PowerModeFast_PSP == ePowerMode) {
prPower->value = 2;
prPower->disabled = 0;
}
prPower->flags = IW_POWER_PERIOD | IW_POWER_RELATIVE;
#if WIRELESS_EXT < 21
prPower->value *= 1000000;
#endif
/* printk(KERN_INFO "wext_get_power value(%d) disabled(%d) flag(0x%x)\n", */
/* prPower->value, prPower->disabled, prPower->flags); */
return 0;
} /* wext_get_power */
/*----------------------------------------------------------------------------*/
/*!
* \brief To set authentication parameters.
*
* \param[in] prDev Net device requested.
* \param[in] prIwrInfo NULL.
* \param[in] rpAuth Pointer to iw_param structure containing authentication information.
* \param[in] pcExtra Pointer to key string buffer.
*
* \retval 0 Success.
* \retval -EINVAL Key ID error for WEP.
* \retval -EFAULT Setting parameters to driver fail.
* \retval -EOPNOTSUPP Key size not supported.
*
* \note Securiry information is stored in pEnc.
*/
/*----------------------------------------------------------------------------*/
static int
wext_set_auth(IN struct net_device *prNetDev,
IN struct iw_request_info *prIwrInfo, IN struct iw_param *prAuth, IN char *pcExtra)
{
P_GLUE_INFO_T prGlueInfo = NULL;
ASSERT(prNetDev);
ASSERT(prAuth);
if (GLUE_CHK_PR2(prNetDev, prAuth) == FALSE)
return -EINVAL;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
/* Save information to glue info and process later when ssid is set. */
switch (prAuth->flags & IW_AUTH_INDEX) {
case IW_AUTH_WPA_VERSION:
#if CFG_SUPPORT_WAPI
if (wlanQueryWapiMode(prGlueInfo->prAdapter)) {
prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED;
prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM;
} else {
prGlueInfo->rWpaInfo.u4WpaVersion = prAuth->value;
}
#else
prGlueInfo->rWpaInfo.u4WpaVersion = prAuth->value;
#endif
break;
case IW_AUTH_CIPHER_PAIRWISE:
prGlueInfo->rWpaInfo.u4CipherPairwise = prAuth->value;
break;
case IW_AUTH_CIPHER_GROUP:
prGlueInfo->rWpaInfo.u4CipherGroup = prAuth->value;
break;
case IW_AUTH_KEY_MGMT:
prGlueInfo->rWpaInfo.u4KeyMgmt = prAuth->value;
#if CFG_SUPPORT_WAPI
if (prGlueInfo->rWpaInfo.u4KeyMgmt == IW_AUTH_KEY_MGMT_WAPI_PSK ||
prGlueInfo->rWpaInfo.u4KeyMgmt == IW_AUTH_KEY_MGMT_WAPI_CERT) {
UINT_32 u4BufLen;
WLAN_STATUS rStatus;
rStatus = kalIoctl(prGlueInfo,
wlanoidSetWapiMode,
&prAuth->value, sizeof(UINT_32), FALSE, FALSE, TRUE, &u4BufLen);
DBGLOG(INIT, INFO, "IW_AUTH_WAPI_ENABLED :%d\n", prAuth->value);
}
#endif
if (prGlueInfo->rWpaInfo.u4KeyMgmt == IW_AUTH_KEY_MGMT_WPS)
prGlueInfo->fgWpsActive = TRUE;
else
prGlueInfo->fgWpsActive = FALSE;
break;
case IW_AUTH_80211_AUTH_ALG:
prGlueInfo->rWpaInfo.u4AuthAlg = prAuth->value;
break;
case IW_AUTH_PRIVACY_INVOKED:
prGlueInfo->rWpaInfo.fgPrivacyInvoke = prAuth->value;
break;
#if CFG_SUPPORT_802_11W
case IW_AUTH_MFP:
/* printk("wext_set_auth IW_AUTH_MFP=%d\n", prAuth->value); */
prGlueInfo->rWpaInfo.u4Mfp = prAuth->value;
break;
#endif
#if CFG_SUPPORT_WAPI
case IW_AUTH_WAPI_ENABLED:
{
UINT_32 u4BufLen;
WLAN_STATUS rStatus;
rStatus = kalIoctl(prGlueInfo,
wlanoidSetWapiMode,
&prAuth->value, sizeof(UINT_32), FALSE, FALSE, TRUE, &u4BufLen);
}
DBGLOG(INIT, INFO, "IW_AUTH_WAPI_ENABLED :%d\n", prAuth->value);
break;
#endif
default:
/*
* printk(KERN_INFO "[wifi] unsupported IW_AUTH_INDEX :%d\n", prAuth->flags);
*/
break;
}
return 0;
} /* wext_set_auth */
/*----------------------------------------------------------------------------*/
/*!
* \brief To set encryption cipher and key.
*
* \param[in] prDev Net device requested.
* \param[in] prIwrInfo NULL.
* \param[in] prEnc Pointer to iw_point structure containing securiry information.
* \param[in] pcExtra Pointer to key string buffer.
*
* \retval 0 Success.
* \retval -EINVAL Key ID error for WEP.
* \retval -EFAULT Setting parameters to driver fail.
* \retval -EOPNOTSUPP Key size not supported.
*
* \note Securiry information is stored in pEnc.
*/
/*----------------------------------------------------------------------------*/
#if CFG_SUPPORT_WAPI
UINT_8 keyStructBuf[1024]; /* add/remove key shared buffer */
#else
UINT_8 keyStructBuf[100]; /* add/remove key shared buffer */
#endif
static int
wext_set_encode_ext(IN struct net_device *prNetDev,
IN struct iw_request_info *prIwrInfo, IN struct iw_point *prEnc, IN char *pcExtra)
{
P_PARAM_REMOVE_KEY_T prRemoveKey = (P_PARAM_REMOVE_KEY_T) keyStructBuf;
P_PARAM_KEY_T prKey = (P_PARAM_KEY_T) keyStructBuf;
P_PARAM_WEP_T prWepKey = (P_PARAM_WEP_T) wepBuf;
struct iw_encode_ext *prIWEncExt = (struct iw_encode_ext *)pcExtra;
ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus;
ENUM_PARAM_AUTH_MODE_T eAuthMode;
/* ENUM_PARAM_OP_MODE_T eOpMode = NET_TYPE_AUTO_SWITCH; */
#if CFG_SUPPORT_WAPI
P_PARAM_WPI_KEY_T prWpiKey = (P_PARAM_WPI_KEY_T) keyStructBuf;
#endif
P_GLUE_INFO_T prGlueInfo = NULL;
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
UINT_32 u4BufLen = 0;
ASSERT(prNetDev);
ASSERT(prEnc);
if (GLUE_CHK_PR3(prNetDev, prEnc, pcExtra) == FALSE)
return -EINVAL;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
memset(keyStructBuf, 0, sizeof(keyStructBuf));
#if CFG_SUPPORT_WAPI
if (prIWEncExt->alg == IW_ENCODE_ALG_SMS4) {
if (prEnc->flags & IW_ENCODE_DISABLED) {
/* printk(KERN_INFO "[wapi] IW_ENCODE_DISABLED\n"); */
return 0;
}
/* KeyID */
prWpiKey->ucKeyID = (prEnc->flags & IW_ENCODE_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;
}
/* PN */
memcpy(&prWpiKey->aucPN[0], &prIWEncExt->tx_seq[0], IW_ENCODE_SEQ_MAX_SIZE);
memcpy(&prWpiKey->aucPN[8], &prIWEncExt->rx_seq[0], IW_ENCODE_SEQ_MAX_SIZE);
/* BSSID */
memcpy(prWpiKey->aucAddrIndex, prIWEncExt->addr.sa_data, 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, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
/* do nothing */
/* printk(KERN_INFO "[wapi] add key error:%lx\n", rStatus); */
}
} else
#endif
{
if ((prEnc->flags & IW_ENCODE_MODE) == IW_ENCODE_DISABLED) {
prRemoveKey->u4Length = sizeof(*prRemoveKey);
memcpy(prRemoveKey->arBSSID, prIWEncExt->addr.sa_data, 6);
/*
* printk("IW_ENCODE_DISABLED: ID:%d, Addr:[" MACSTR "]\n",
* prRemoveKey->KeyIndex, MAC2STR(prRemoveKey->BSSID));
*/
rStatus = kalIoctl(prGlueInfo,
wlanoidSetRemoveKey,
prRemoveKey, prRemoveKey->u4Length, FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
DBGLOG(INIT, INFO, "remove key error:%lx\n", rStatus);
return 0;
}
/* return 0; */
/* printk ("alg %x\n", prIWEncExt->alg); */
switch (prIWEncExt->alg) {
case IW_ENCODE_ALG_NONE:
break;
case IW_ENCODE_ALG_WEP:
/* iwconfig wlan0 key 0123456789 */
/* iwconfig wlan0 key s:abcde */
/* iwconfig wlan0 key 0123456789 [1] */
/* iwconfig wlan0 key 01234567890123456789012345 [1] */
/* check key size for WEP */
if (prIWEncExt->key_len == 5 || prIWEncExt->key_len == 13 || prIWEncExt->key_len == 16) {
/* prepare PARAM_WEP key structure */
prWepKey->u4KeyIndex = (prEnc->flags & IW_ENCODE_INDEX) ?
(prEnc->flags & IW_ENCODE_INDEX) - 1 : 0;
if (prWepKey->u4KeyIndex > 3) {
/* key id is out of range */
return -EINVAL;
}
prWepKey->u4KeyIndex |= 0x80000000;
prWepKey->u4Length = 12 + prIWEncExt->key_len;
prWepKey->u4KeyLength = prIWEncExt->key_len;
/* kalMemCopy(prWepKey->aucKeyMaterial, pcExtra, prIWEncExt->key_len); */
kalMemCopy(prWepKey->aucKeyMaterial, prIWEncExt->key, prIWEncExt->key_len);
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;
}
/* change to auto switch */
prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_SHARED_KEY | IW_AUTH_ALG_OPEN_SYSTEM;
eAuthMode = AUTH_MODE_AUTO_SWITCH;
rStatus = kalIoctl(prGlueInfo,
wlanoidSetAuthMode,
&eAuthMode, sizeof(eAuthMode), FALSE, FALSE, FALSE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, INFO, "wlanoidSetAuthMode fail 0x%lx\n", rStatus);
return -EFAULT;
}
prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40;
prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40;
eEncStatus = ENUM_WEP_ENABLED;
rStatus = kalIoctl(prGlueInfo,
wlanoidSetEncryptionStatus,
&eEncStatus,
sizeof(ENUM_PARAM_ENCRYPTION_STATUS_T),
FALSE, FALSE, FALSE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, INFO, "wlanoidSetEncryptionStatus fail 0x%lx\n", rStatus);
return -EFAULT;
}
} else {
DBGLOG(INIT, INFO, "key length %x\n", prIWEncExt->key_len);
DBGLOG(INIT, INFO, "key error\n");
}
break;
case IW_ENCODE_ALG_TKIP:
case IW_ENCODE_ALG_CCMP:
#if CFG_SUPPORT_802_11W
case IW_ENCODE_ALG_AES_CMAC:
#endif
{
/* KeyID */
prKey->u4KeyIndex = (prEnc->flags & IW_ENCODE_INDEX) ?
(prEnc->flags & IW_ENCODE_INDEX) - 1 : 0;
#if CFG_SUPPORT_802_11W
if (prKey->u4KeyIndex > 5) {
#else
if (prKey->u4KeyIndex > 3) {
#endif
DBGLOG(INIT, INFO, "key index error:0x%lx\n", prKey->u4KeyIndex);
/* key id is out of range */
return -EINVAL;
}
/* bit(31) and bit(30) are shared by pKey and pRemoveKey */
/* Tx Key Bit(31) */
if (prIWEncExt->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
prKey->u4KeyIndex |= 0x1UL << 31;
/* Pairwise Key Bit(30) */
if (prIWEncExt->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
/* group key */
} else {
/* pairwise key */
prKey->u4KeyIndex |= 0x1UL << 30;
}
}
/* Rx SC Bit(29) */
if (prIWEncExt->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
prKey->u4KeyIndex |= 0x1UL << 29;
memcpy(&prKey->rKeyRSC, prIWEncExt->rx_seq, IW_ENCODE_SEQ_MAX_SIZE);
}
/* BSSID */
memcpy(prKey->arBSSID, prIWEncExt->addr.sa_data, 6);
/* switch tx/rx MIC key for sta */
if (prIWEncExt->alg == IW_ENCODE_ALG_TKIP && prIWEncExt->key_len == 32) {
memcpy(prKey->aucKeyMaterial, prIWEncExt->key, 16);
memcpy(((PUINT_8) prKey->aucKeyMaterial) + 16, prIWEncExt->key + 24, 8);
memcpy((prKey->aucKeyMaterial) + 24, prIWEncExt->key + 16, 8);
} else {
/* aucKeyMaterial is defined as a 32-elements array */
if (prIWEncExt->key_len > 32) {
DBGLOG(REQ, ERROR, "prIWEncExt->key_len: %d is too long!\n",
prIWEncExt->key_len);
return -EFAULT;
}
memcpy(prKey->aucKeyMaterial, prIWEncExt->key, prIWEncExt->key_len);
}
prKey->u4KeyLength = prIWEncExt->key_len;
prKey->u4Length = ((ULONG)&(((P_PARAM_KEY_T) 0)->aucKeyMaterial)) + prKey->u4KeyLength;
rStatus = kalIoctl(prGlueInfo,
wlanoidSetAddKey, prKey, prKey->u4Length, FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, INFO, "add key error:%lx\n", rStatus);
return -EFAULT;
}
break;
}
}
return 0;
} /* wext_set_encode_ext */
/*----------------------------------------------------------------------------*/
/*!
* \brief Set country code
*
* \param[in] prNetDev Net device requested.
* \param[in] prData iwreq.u.data carries country code value.
*
* \retval 0 For success.
* \retval -EEFAULT For fail.
*
* \note Country code is stored and channel list is updated based on current country domain.
*/
/*----------------------------------------------------------------------------*/
static int wext_set_country(IN struct net_device *prNetDev, IN struct iw_point *prData)
{
P_GLUE_INFO_T prGlueInfo;
WLAN_STATUS rStatus;
UINT_32 u4BufLen;
UINT_8 aucCountry[2];
ASSERT(prNetDev);
/* prData->pointer should be like "COUNTRY US", "COUNTRY EU"
* and "COUNTRY JP"
*/
if (GLUE_CHK_PR2(prNetDev, prData) == FALSE || !prData->pointer || prData->length < 10)
return -EINVAL;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
aucCountry[0] = *((PUINT_8)prData->pointer + 8);
aucCountry[1] = *((PUINT_8)prData->pointer + 9);
rStatus = kalIoctl(prGlueInfo, wlanoidSetCountryCode, &aucCountry[0], 2, FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(REQ, ERROR, "Set country code error: %x\n", rStatus);
return -EFAULT;
}
return 0;
}
/*----------------------------------------------------------------------------*/
/*!
* \brief To report the iw private args table to user space.
*
* \param[in] prNetDev Net device requested.
* \param[out] prData iwreq.u.data to carry the private args table.
*
* \retval 0 For success.
* \retval -E2BIG For user's buffer size is too small.
* \retval -EFAULT For fail.
*
*/
/*----------------------------------------------------------------------------*/
int wext_get_priv(IN struct net_device *prNetDev, OUT struct iw_point *prData)
{
UINT_16 u2BufferSize = prData->length;
/* Update our private args table size */
prData->length = (__u16)sizeof(rIwPrivTable);
if (u2BufferSize < prData->length)
return -E2BIG;
if (prData->length) {
if (copy_to_user(prData->pointer, rIwPrivTable, sizeof(rIwPrivTable)))
return -EFAULT;
}
return 0;
} /* wext_get_priv */
/*----------------------------------------------------------------------------*/
/*!
* \brief ioctl() (Linux Wireless Extensions) routines
*
* \param[in] prDev Net device requested.
* \param[in] ifr The ifreq structure for seeting the wireless extension.
* \param[in] i4Cmd The wireless extension ioctl command.
*
* \retval zero On success.
* \retval -EOPNOTSUPP If the cmd is not supported.
* \retval -EFAULT If copy_to_user goes wrong.
* \retval -EINVAL If any value's out of range.
*
* \note
*/
/*----------------------------------------------------------------------------*/
int wext_support_ioctl(IN struct net_device *prDev, IN struct ifreq *prIfReq, IN int i4Cmd)
{
/* prIfReq is verified in the caller function wlanDoIOCTL() */
struct iwreq *iwr = (struct iwreq *)prIfReq;
struct iw_request_info rIwReqInfo;
int ret = 0;
char *prExtraBuf = NULL;
UINT_32 u4ExtraSize = 0;
/* prDev is verified in the caller function wlanDoIOCTL() */
/* printk("%d CMD:0x%x\n", jiffies_to_msecs(jiffies), i4Cmd); */
/* Prepare the call */
rIwReqInfo.cmd = (__u16) i4Cmd;
rIwReqInfo.flags = 0;
switch (i4Cmd) {
case SIOCGIWNAME: /* 0x8B01, get wireless protocol name */
ret = wext_get_name(prDev, &rIwReqInfo, (char *)&iwr->u.name, NULL);
break;
/* case SIOCSIWNWID: 0x8B02, deprecated */
/* case SIOCGIWNWID: 0x8B03, deprecated */
case SIOCSIWFREQ: /* 0x8B04, set channel */
ret = wext_set_freq(prDev, NULL, &iwr->u.freq, NULL);
break;
case SIOCGIWFREQ: /* 0x8B05, get channel */
ret = wext_get_freq(prDev, NULL, &iwr->u.freq, NULL);
break;
case SIOCSIWMODE: /* 0x8B06, set operation mode */
ret = wext_set_mode(prDev, NULL, &iwr->u.mode, NULL);
/* ret = 0; */
break;
case SIOCGIWMODE: /* 0x8B07, get operation mode */
ret = wext_get_mode(prDev, NULL, &iwr->u.mode, NULL);
break;
/* case SIOCSIWSENS: 0x8B08, unsupported */
/* case SIOCGIWSENS: 0x8B09, unsupported */
/* case SIOCSIWRANGE: 0x8B0A, unused */
case SIOCGIWRANGE: /* 0x8B0B, get range of parameters */
if (iwr->u.data.pointer != NULL) {
/* Buffer size should be large enough */
if (iwr->u.data.length < sizeof(struct iw_range)) {
ret = -E2BIG;
break;
}
prExtraBuf = kalMemAlloc(sizeof(struct iw_range), VIR_MEM_TYPE);
if (!prExtraBuf) {
ret = -ENOMEM;
break;
}
/* reset all fields */
memset(prExtraBuf, 0, sizeof(struct iw_range));
iwr->u.data.length = sizeof(struct iw_range);
ret = wext_get_range(prDev, NULL, &iwr->u.data, prExtraBuf);
/* Push up to the caller */
if (copy_to_user(iwr->u.data.pointer, prExtraBuf, iwr->u.data.length))
ret = -EFAULT;
kalMemFree(prExtraBuf, VIR_MEM_TYPE, sizeof(struct iw_range));
prExtraBuf = NULL;
} else {
ret = -EINVAL;
}
break;
case SIOCSIWPRIV: /* 0x8B0C, set country code */
ret = wext_set_country(prDev, &iwr->u.data);
break;
case SIOCGIWPRIV: /* 0x8B0D, get private args table */
ret = wext_get_priv(prDev, &iwr->u.data);
break;
/* caes SIOCSIWSTATS: 0x8B0E, unused */
/* case SIOCGIWSTATS:
* get statistics, intercepted by wireless_process_ioctl() in wireless.c,
* redirected to dev_iwstats(), dev->get_wireless_stats().
*/
/* case SIOCSIWSPY: 0x8B10, unsupported */
/* case SIOCGIWSPY: 0x8B11, unsupported */
/* case SIOCSIWTHRSPY: 0x8B12, unsupported */
/* case SIOCGIWTHRSPY: 0x8B13, unsupported */
case SIOCSIWAP: /* 0x8B14, set access point MAC addresses (BSSID) */
if (iwr->u.ap_addr.sa_data[0] == 0 &&
iwr->u.ap_addr.sa_data[1] == 0 &&
iwr->u.ap_addr.sa_data[2] == 0 &&
iwr->u.ap_addr.sa_data[3] == 0 &&
iwr->u.ap_addr.sa_data[4] == 0 && iwr->u.ap_addr.sa_data[5] == 0) {
/* WPA Supplicant will set 000000000000 in
** wpa_driver_wext_deinit(), do nothing here or disassoc again?
*/
ret = 0;
break;
}
ret = wext_set_ap(prDev, NULL, &iwr->u.ap_addr, NULL);
break;
case SIOCGIWAP: /* 0x8B15, get access point MAC addresses (BSSID) */
ret = wext_get_ap(prDev, NULL, &iwr->u.ap_addr, NULL);
break;
case SIOCSIWMLME: /* 0x8B16, request MLME operation */
/* Fixed length structure */
if (iwr->u.data.length != sizeof(struct iw_mlme)) {
DBGLOG(INIT, INFO, "MLME buffer strange:%d\n", iwr->u.data.length);
ret = -EINVAL;
break;
}
if (!iwr->u.data.pointer) {
ret = -EINVAL;
break;
}
prExtraBuf = kalMemAlloc(sizeof(struct iw_mlme), VIR_MEM_TYPE);
if (!prExtraBuf) {
ret = -ENOMEM;
break;
}
if (copy_from_user(prExtraBuf, iwr->u.data.pointer, sizeof(struct iw_mlme)))
ret = -EFAULT;
else
ret = wext_set_mlme(prDev, NULL, &(iwr->u.data), prExtraBuf);
kalMemFree(prExtraBuf, VIR_MEM_TYPE, sizeof(struct iw_mlme));
prExtraBuf = NULL;
break;
/* case SIOCGIWAPLIST: 0x8B17, deprecated */
case SIOCSIWSCAN: /* 0x8B18, scan request */
if (iwr->u.data.pointer == NULL)
ret = wext_set_scan(prDev, NULL, NULL, NULL);
#if WIRELESS_EXT > 17
else if (iwr->u.data.length == sizeof(struct iw_scan_req)) {
prExtraBuf = kalMemAlloc(MAX_SSID_LEN, VIR_MEM_TYPE);
if (!prExtraBuf) {
ret = -ENOMEM;
break;
}
if (copy_from_user
(prExtraBuf, ((struct iw_scan_req *)(iwr->u.data.pointer))->essid,
((struct iw_scan_req *)(iwr->u.data.pointer))->essid_len)) {
ret = -EFAULT;
} else {
ret = wext_set_scan(prDev, NULL, (union iwreq_data *)&(iwr->u.data), prExtraBuf);
}
kalMemFree(prExtraBuf, VIR_MEM_TYPE, MAX_SSID_LEN);
prExtraBuf = NULL;
}
#endif
else
ret = -EINVAL;
break;
#if 1
case SIOCGIWSCAN: /* 0x8B19, get scan results */
if (!iwr->u.data.pointer || !iwr->u.essid.pointer) {
ret = -EINVAL;
break;
}
u4ExtraSize = iwr->u.data.length;
/* allocate the same size of kernel buffer to store scan results. */
prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE);
if (!prExtraBuf) {
ret = -ENOMEM;
break;
}
/* iwr->u.data.length may be updated by wext_get_scan() */
ret = wext_get_scan(prDev, NULL, &iwr->u.data, prExtraBuf);
if (ret != 0) {
if (ret == -E2BIG)
DBGLOG(INIT, INFO, "[wifi] wext_get_scan -E2BIG\n");
} else {
/* check updated length is valid */
ASSERT(iwr->u.data.length <= u4ExtraSize);
if (iwr->u.data.length > u4ExtraSize) {
DBGLOG(INIT, INFO,
"Updated result length is larger than allocated (%d > %ld)\n",
iwr->u.data.length, u4ExtraSize);
iwr->u.data.length = u4ExtraSize;
}
if (copy_to_user(iwr->u.data.pointer, prExtraBuf, iwr->u.data.length))
ret = -EFAULT;
}
kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize);
prExtraBuf = NULL;
break;
#endif
#if 1
case SIOCSIWESSID: /* 0x8B1A, set SSID (network name) */
if (iwr->u.essid.length > IW_ESSID_MAX_SIZE) {
ret = -E2BIG;
break;
}
if (!iwr->u.essid.pointer) {
ret = -EINVAL;
break;
}
prExtraBuf = kalMemAlloc(IW_ESSID_MAX_SIZE + 4, VIR_MEM_TYPE);
if (!prExtraBuf) {
ret = -ENOMEM;
break;
}
if (copy_from_user(prExtraBuf, iwr->u.essid.pointer, iwr->u.essid.length)) {
ret = -EFAULT;
} else {
/* Add trailing '\0' for printk */
/* prExtraBuf[iwr->u.essid.length] = 0; */
/* printk(KERN_INFO "wext_set_essid: %s (%d)\n", prExtraBuf, iwr->u.essid.length); */
ret = wext_set_essid(prDev, NULL, &iwr->u.essid, prExtraBuf);
/* printk ("set essid %d\n", ret); */
}
kalMemFree(prExtraBuf, VIR_MEM_TYPE, IW_ESSID_MAX_SIZE + 4);
prExtraBuf = NULL;
break;
#endif
case SIOCGIWESSID: /* 0x8B1B, get SSID */
if (!iwr->u.essid.pointer) {
ret = -EINVAL;
break;
}
if (iwr->u.essid.length < IW_ESSID_MAX_SIZE) {
DBGLOG(INIT, INFO, "[wifi] iwr->u.essid.length:%d too small\n", iwr->u.essid.length);
ret = -E2BIG; /* let caller try larger buffer */
break;
}
prExtraBuf = kalMemAlloc(IW_ESSID_MAX_SIZE, VIR_MEM_TYPE);
if (!prExtraBuf) {
ret = -ENOMEM;
break;
}
/* iwr->u.essid.length is updated by wext_get_essid() */
ret = wext_get_essid(prDev, NULL, &iwr->u.essid, prExtraBuf);
if (ret == 0) {
if (copy_to_user(iwr->u.essid.pointer, prExtraBuf, IW_ESSID_MAX_SIZE))
ret = -EFAULT;
}
kalMemFree(prExtraBuf, VIR_MEM_TYPE, IW_ESSID_MAX_SIZE);
prExtraBuf = NULL;
break;
/* case SIOCSIWNICKN: 0x8B1C, not supported */
/* case SIOCGIWNICKN: 0x8B1D, not supported */
case SIOCSIWRATE: /* 0x8B20, set default bit rate (bps) */
/* ret = wext_set_rate(prDev, &rIwReqInfo, &iwr->u.bitrate, NULL); */
break;
case SIOCGIWRATE: /* 0x8B21, get current bit rate (bps) */
ret = wext_get_rate(prDev, NULL, &iwr->u.bitrate, NULL);
break;
case SIOCSIWRTS: /* 0x8B22, set rts/cts threshold */
ret = wext_set_rts(prDev, NULL, &iwr->u.rts, NULL);
break;
case SIOCGIWRTS: /* 0x8B23, get rts/cts threshold */
ret = wext_get_rts(prDev, NULL, &iwr->u.rts, NULL);
break;
/* case SIOCSIWFRAG: 0x8B24, unsupported */
case SIOCGIWFRAG: /* 0x8B25, get frag threshold */
ret = wext_get_frag(prDev, NULL, &iwr->u.frag, NULL);
break;
case SIOCSIWTXPOW: /* 0x8B26, set relative tx power (in %) */
ret = wext_set_txpow(prDev, NULL, &iwr->u.txpower, NULL);
break;
case SIOCGIWTXPOW: /* 0x8B27, get relative tx power (in %) */
ret = wext_get_txpow(prDev, NULL, &iwr->u.txpower, NULL);
break;
/* case SIOCSIWRETRY: 0x8B28, unsupported */
/* case SIOCGIWRETRY: 0x8B29, unsupported */
#if 1
case SIOCSIWENCODE: /* 0x8B2A, set encoding token & mode */
/* Only DISABLED case has NULL pointer and length == 0 */
if (iwr->u.encoding.pointer) {
if (iwr->u.encoding.length > 16) {
ret = -E2BIG;
break;
}
u4ExtraSize = iwr->u.encoding.length;
prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE);
if (!prExtraBuf) {
ret = -ENOMEM;
break;
}
if (copy_from_user(prExtraBuf, iwr->u.encoding.pointer, iwr->u.encoding.length))
ret = -EFAULT;
} else if (iwr->u.encoding.length != 0) {
ret = -EINVAL;
break;
}
if (ret == 0)
ret = wext_set_encode(prDev, NULL, &iwr->u.encoding, prExtraBuf);
if (prExtraBuf) {
kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize);
prExtraBuf = NULL;
}
break;
case SIOCGIWENCODE: /* 0x8B2B, get encoding token & mode */
/* check pointer */
ret = wext_get_encode(prDev, NULL, &iwr->u.encoding, NULL);
break;
case SIOCSIWPOWER: /* 0x8B2C, set power management */
ret = wext_set_power(prDev, NULL, &iwr->u.power, NULL);
break;
case SIOCGIWPOWER: /* 0x8B2D, get power management */
ret = wext_get_power(prDev, NULL, &iwr->u.power, NULL);
break;
#if WIRELESS_EXT > 17
case SIOCSIWGENIE: /* 0x8B30, set gen ie */
if (iwr->u.data.pointer) {
P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev));
if (1 /* wlanQueryWapiMode(prGlueInfo->prAdapter) */) {
/* Fixed length structure */
#if CFG_SUPPORT_WAPI
if (iwr->u.data.length > 42 /* The max wapi ie buffer */) {
ret = -EINVAL;
break;
}
#endif
u4ExtraSize = iwr->u.data.length;
if (u4ExtraSize) {
prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE);
if (!prExtraBuf) {
ret = -ENOMEM;
break;
}
if (copy_from_user(prExtraBuf, iwr->u.data.pointer, iwr->u.data.length))
ret = -EFAULT;
else
wext_support_ioctl_SIOCSIWGENIE(prGlueInfo, prExtraBuf, u4ExtraSize);
kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize);
prExtraBuf = NULL;
}
}
}
break;
case SIOCGIWGENIE: /* 0x8B31, get gen ie, unused */
break;
#endif
case SIOCSIWAUTH: /* 0x8B32, set auth mode params */
ret = wext_set_auth(prDev, NULL, &iwr->u.param, NULL);
break;
/* case SIOCGIWAUTH: 0x8B33, unused? */
case SIOCSIWENCODEEXT: /* 0x8B34, set extended encoding token & mode */
if (iwr->u.encoding.pointer) {
u4ExtraSize = iwr->u.encoding.length;
if (u4ExtraSize > sizeof(struct iw_encode_ext)) {
ret = -EINVAL;
break;
}
prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE);
if (!prExtraBuf) {
ret = -ENOMEM;
break;
}
if (copy_from_user(prExtraBuf, iwr->u.encoding.pointer, u4ExtraSize))
ret = -EFAULT;
} else if (iwr->u.encoding.length != 0) {
ret = -EINVAL;
break;
}
if (ret == 0)
ret = wext_set_encode_ext(prDev, NULL, &iwr->u.encoding, prExtraBuf);
if (prExtraBuf) {
kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize);
prExtraBuf = NULL;
}
break;
/* case SIOCGIWENCODEEXT: 0x8B35, unused? */
case SIOCSIWPMKSA: /* 0x8B36, pmksa cache operation */
#if 1
if (iwr->u.data.pointer) {
/* Fixed length structure */
if (iwr->u.data.length != sizeof(struct iw_pmksa)) {
ret = -EINVAL;
break;
}
u4ExtraSize = sizeof(struct iw_pmksa);
prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE);
if (!prExtraBuf) {
ret = -ENOMEM;
break;
}
if (copy_from_user(prExtraBuf, iwr->u.data.pointer, sizeof(struct iw_pmksa))) {
ret = -EFAULT;
} else {
switch (((struct iw_pmksa *)prExtraBuf)->cmd) {
case IW_PMKSA_ADD:
/*
* printk(KERN_INFO "IW_PMKSA_ADD [" MACSTR "]\n",
* MAC2STR(((struct iw_pmksa *)pExtraBuf)->bssid.sa_data));
*/
{
wext_support_ioctl_SIOCSIWPMKSA_Action(prDev, prExtraBuf, IW_PMKSA_ADD,
&ret);
}
break;
case IW_PMKSA_REMOVE:
/*
* printk(KERN_INFO "IW_PMKSA_REMOVE [" MACSTR "]\n",
* MAC2STR(((struct iw_pmksa *)buf)->bssid.sa_data));
*/
break;
case IW_PMKSA_FLUSH:
/*
* printk(KERN_INFO "IW_PMKSA_FLUSH\n");
*/
{
wext_support_ioctl_SIOCSIWPMKSA_Action(prDev, prExtraBuf,
IW_PMKSA_FLUSH, &ret);
}
break;
default:
DBGLOG(INIT, INFO, "UNKNOWN iw_pmksa command:%d\n",
((struct iw_pmksa *)prExtraBuf)->cmd);
ret = -EFAULT;
break;
}
}
if (prExtraBuf) {
kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize);
prExtraBuf = NULL;
}
} else if (iwr->u.data.length != 0) {
ret = -EINVAL;
break;
}
#endif
break;
#endif
default:
/* printk(KERN_NOTICE "unsupported IOCTL: 0x%x\n", i4Cmd); */
ret = -EOPNOTSUPP;
break;
}
/* printk("%ld CMD:0x%x ret:%d\n", jiffies_to_msecs(jiffies), i4Cmd, ret); */
return ret;
} /* wext_support_ioctl */
static void wext_support_ioctl_SIOCSIWGENIE(IN P_GLUE_INFO_T prGlueInfo, IN char *prExtraBuf, IN UINT_32 u4ExtraSize)
{
WLAN_STATUS rStatus;
UINT_32 u4BufLen;
#if CFG_SUPPORT_WAPI
rStatus = kalIoctl(prGlueInfo, wlanoidSetWapiAssocInfo, prExtraBuf, u4ExtraSize, FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
#endif
#if CFG_SUPPORT_WPS2
PUINT_8 prDesiredIE = NULL;
if (wextSrchDesiredWPSIE(prExtraBuf, u4ExtraSize, 0xDD, (PUINT_8 *) &prDesiredIE)) {
rStatus =
kalIoctl(prGlueInfo,
wlanoidSetWSCAssocInfo,
prDesiredIE, IE_SIZE(prDesiredIE), FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
/* do nothing */
/* printk(KERN_INFO "[WSC] set WSC assoc info error:%lx\n", rStatus); */
}
}
#endif
#if CFG_SUPPORT_WAPI
}
#endif
}
static void
wext_support_ioctl_SIOCSIWPMKSA_Action(IN struct net_device *prDev, IN char *prExtraBuf, IN int ioMode, OUT int *ret)
{
P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev));
WLAN_STATUS rStatus;
UINT_32 u4BufLen;
P_PARAM_PMKID_T prPmkid;
switch (ioMode) {
case IW_PMKSA_ADD:
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");
*ret = -ENOMEM;
break;
}
prPmkid->u4Length = 8 + sizeof(PARAM_BSSID_INFO_T);
prPmkid->u4BSSIDInfoCount = 1;
kalMemCopy(prPmkid->arBSSIDInfo->arBSSID, ((struct iw_pmksa *)prExtraBuf)->bssid.sa_data, 6);
kalMemCopy(prPmkid->arBSSIDInfo->arPMKID, ((struct iw_pmksa *)prExtraBuf)->pmkid, IW_PMKID_LEN);
rStatus = kalIoctl(prGlueInfo,
wlanoidSetPmkid, prPmkid, sizeof(PARAM_PMKID_T), FALSE, FALSE, TRUE, &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));
break;
case IW_PMKSA_FLUSH:
prPmkid = (P_PARAM_PMKID_T) kalMemAlloc(8, VIR_MEM_TYPE);
if (!prPmkid) {
DBGLOG(INIT, INFO, "Can not alloc memory for IW_PMKSA_FLUSH\n");
*ret = -ENOMEM;
break;
}
prPmkid->u4Length = 8;
prPmkid->u4BSSIDInfoCount = 0;
rStatus = kalIoctl(prGlueInfo,
wlanoidSetPmkid, prPmkid, sizeof(PARAM_PMKID_T), FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS)
DBGLOG(INIT, INFO, "flush pmkid error:%lx\n", rStatus);
kalMemFree(prPmkid, VIR_MEM_TYPE, 8);
break;
default:
break;
}
}
/*----------------------------------------------------------------------------*/
/*!
* \brief To send an event (RAW socket pacekt) to user process actively.
*
* \param[in] prGlueInfo Glue layer info.
* \param[in] u4cmd Which event command we want to indicate to user process.
* \param[in] pData Data buffer to be indicated.
* \param[in] dataLen Available data size in pData.
*
* \return (none)
*
* \note Event is indicated to upper layer if cmd is supported and data is valid.
* Using of kernel symbol wireless_send_event(), which is defined in
* <net/iw_handler.h> after WE-14 (2.4.20).
*/
/*----------------------------------------------------------------------------*/
void
wext_indicate_wext_event(IN P_GLUE_INFO_T prGlueInfo,
IN unsigned int u4Cmd, IN unsigned char *pucData, IN unsigned int u4dataLen)
{
union iwreq_data wrqu;
unsigned char *pucExtraInfo = NULL;
#if WIRELESS_EXT >= 15
unsigned char *pucDesiredIE = NULL;
unsigned char aucExtraInfoBuf[200];
#endif
#if WIRELESS_EXT < 18
int i;
#endif
memset(&wrqu, 0, sizeof(wrqu));
switch (u4Cmd) {
case SIOCGIWTXPOW:
memcpy(&wrqu.power, pucData, u4dataLen);
break;
case SIOCGIWSCAN:
complete_all(&prGlueInfo->rScanComp);
break;
case SIOCGIWAP:
if (pucData)
kalMemCopy(&wrqu.ap_addr.sa_data, pucData, ETH_ALEN);
else
eth_zero_addr((u8 *)&wrqu.ap_addr.sa_data);
break;
case IWEVASSOCREQIE:
#if WIRELESS_EXT < 15
/* under WE-15, no suitable Event can be used */
goto skip_indicate_event;
#else
/* do supplicant a favor, parse to the start of WPA/RSN IE */
if (wextSrchDesiredWPAIE(pucData, u4dataLen, 0x30, &pucDesiredIE)) {
/* RSN IE found */
/* RSN IE found */
}
#if 0
else if (wextSrchDesiredWPSIE(pucData, u4dataLen, 0xDD, &pucDesiredIE)) {
/* WPS IE found */
/* WPS IE found */
}
#endif
else if (wextSrchDesiredWPAIE(pucData, u4dataLen, 0xDD, &pucDesiredIE)) {
/* WPA IE found */
/* WPA IE found */
}
#if CFG_SUPPORT_WAPI /* Android+ */
else if (wextSrchDesiredWAPIIE(pucData, u4dataLen, &pucDesiredIE)) {
/* printk("wextSrchDesiredWAPIIE!!\n"); */
/* WAPI IE found */
}
#endif
else {
/* no WPA/RSN IE found, skip this event */
goto skip_indicate_event;
}
#if WIRELESS_EXT < 18
/* under WE-18, only IWEVCUSTOM can be used */
u4Cmd = IWEVCUSTOM;
pucExtraInfo = aucExtraInfoBuf;
pucExtraInfo += sprintf(pucExtraInfo, "ASSOCINFO(ReqIEs=");
/* printk(KERN_DEBUG "assoc info buffer size needed:%d\n", infoElemLen * 2 + 17); */
/* translate binary string to hex string, requirement of IWEVCUSTOM */
for (i = 0; i < pucDesiredIE[1] + 2; ++i)
pucExtraInfo += sprintf(pucExtraInfo, "%02x", pucDesiredIE[i]);
pucExtraInfo = aucExtraInfoBuf;
wrqu.data.length = 17 + (pucDesiredIE[1] + 2) * 2;
#else
/* IWEVASSOCREQIE, indicate binary string */
pucExtraInfo = pucDesiredIE;
wrqu.data.length = pucDesiredIE[1] + 2;
#endif
#endif /* WIRELESS_EXT < 15 */
break;
case IWEVMICHAELMICFAILURE:
#if WIRELESS_EXT < 15
/* under WE-15, no suitable Event can be used */
goto skip_indicate_event;
#else
if (pucData) {
INT_32 i4BufLen = 0;
P_PARAM_AUTH_REQUEST_T pAuthReq = (P_PARAM_AUTH_REQUEST_T) pucData;
/* under WE-18, only IWEVCUSTOM can be used */
u4Cmd = IWEVCUSTOM;
pucExtraInfo = aucExtraInfoBuf;
i4BufLen = scnprintf(pucExtraInfo, sizeof(aucExtraInfoBuf),
"MLME-MICHAELMICFAILURE.indication ");
i4BufLen += scnprintf((pucExtraInfo + i4BufLen),
(sizeof(aucExtraInfoBuf) - i4BufLen),
"%s",
(pAuthReq->u4Flags ==
PARAM_AUTH_REQUEST_GROUP_ERROR) ? "groupcast " : "unicast ");
wrqu.data.length = i4BufLen;
pucExtraInfo = aucExtraInfoBuf;
}
#endif /* WIRELESS_EXT < 15 */
break;
case IWEVPMKIDCAND:
if (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_WPA2 &&
prGlueInfo->rWpaInfo.u4KeyMgmt == IW_AUTH_KEY_MGMT_802_1X) {
/* only used in WPA2 */
#if WIRELESS_EXT >= 18
P_PARAM_PMKID_CANDIDATE_T prPmkidCand = (P_PARAM_PMKID_CANDIDATE_T) pucData;
struct iw_pmkid_cand rPmkidCand;
pucExtraInfo = aucExtraInfoBuf;
rPmkidCand.flags = prPmkidCand->u4Flags;
rPmkidCand.index = 0;
kalMemCopy(rPmkidCand.bssid.sa_data, prPmkidCand->arBSSID, 6);
kalMemCopy(pucExtraInfo, (PUINT_8) &rPmkidCand, sizeof(struct iw_pmkid_cand));
wrqu.data.length = sizeof(struct iw_pmkid_cand);
/* pmkid canadidate list is supported after WE-18 */
/* indicate struct iw_pmkid_cand */
#else
/* printk(KERN_INFO "IWEVPMKIDCAND event skipped, WE < 18\n"); */
goto skip_indicate_event;
#endif
} else {
/* printk(KERN_INFO "IWEVPMKIDCAND event skipped, NOT WPA2\n"); */
goto skip_indicate_event;
}
break;
case IWEVCUSTOM:
u4Cmd = IWEVCUSTOM;
pucExtraInfo = aucExtraInfoBuf;
kalMemCopy(pucExtraInfo, pucData, sizeof(PTA_IPC_T));
wrqu.data.length = sizeof(PTA_IPC_T);
break;
default:
/* printk(KERN_INFO "Unsupported wext event:%x\n", cmd); */
goto skip_indicate_event;
}
/* Send event to user space */
wireless_send_event(prGlueInfo->prDevHandler, u4Cmd, &wrqu, pucExtraInfo);
skip_indicate_event:
return;
} /* wext_indicate_wext_event */
/*----------------------------------------------------------------------------*/
/*!
* \brief A method of struct net_device, to get the network interface statistical
* information.
*
* Whenever an application needs to get statistics for the interface, this method
* is called. This happens, for example, when ifconfig or netstat -i is run.
*
* \param[in] pDev Pointer to struct net_device.
*
* \return net_device_stats buffer pointer.
*
*/
/*----------------------------------------------------------------------------*/
struct iw_statistics *wext_get_wireless_stats(struct net_device *prDev)
{
WLAN_STATUS rStatus = WLAN_STATUS_FAILURE;
P_GLUE_INFO_T prGlueInfo = NULL;
struct iw_statistics *pStats = NULL;
INT_32 i4Rssi;
UINT_32 bufLen = 0;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev));
ASSERT(prGlueInfo);
if (!prGlueInfo)
goto stat_out;
pStats = (struct iw_statistics *)(&(prGlueInfo->rIwStats));
if (!prDev || !netif_carrier_ok(prDev)) {
/* network not connected */
goto stat_out;
}
rStatus = kalIoctl(prGlueInfo, wlanoidQueryRssi, &i4Rssi, sizeof(i4Rssi), TRUE, TRUE, TRUE, &bufLen);
stat_out:
return pStats;
} /* wlan_get_wireless_stats */
#endif /* WIRELESS_EXT */