nuttx/drivers/wireless/cc3000/wlan.c
Gregory Nutt e42f7b552f This commit is a set of patches 02/11 through 03/11 correcting issues with the CC3000 networking (01/11 was committed separated). Among these 10 patches:
03/11: CC3000 driver was getting stuck at recv() when remote host closed connection and application tried to read data from remotely shutdown socket. This patch adds proper handling for remotely closed socket event.

07/11: Socket state initialization was done in 'register', while it should be initialized in 'open' and deinitialized in 'close'. Old way caused problems when device is closed, power-cycled and then reopened as old socket state was left enabled.

08/11: Select thread was getting stuck after 'close, power-cycle, reopen', since selectsem was not properly setup and cleaned up.

09/11 'maxFD' was not properly reset in select worker and not checked for before calling cc3000_select().

10/11: After wlan_stop()/cc3000_close(), irqsem was left with count '-1'. Therefore on next wlan_start()/cc3000_open(), initial value for irqsem was wrong. Additional repeated wlan_start()/wlan_stop() decreased irqsem value further. Obviously this causes driver not to function correctly and freeze.

Patch moves initialization and destruction of waitsem, irqsem and readysem to cc3000_open/cc3000_close.

All are: Signed-off-by: Jussi Kivilinna <jussi.kivilinna@haltian.com>
2014-11-28 08:52:52 -06:00

1340 lines
41 KiB
C

/*****************************************************************************
* wlan.c - CC3000 Host Driver Implementation.
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
*
* 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 Texas Instruments Incorporated 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
* OWNER 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.
*
*****************************************************************************/
/*****************************************************************************
* Included Files
*****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
#include <string.h>
#include <debug.h>
#include <nuttx/wireless/cc3000/cc3000_common.h>
#include <nuttx/wireless/cc3000/wlan.h>
#include <nuttx/wireless/cc3000/hci.h>
#include <nuttx/wireless/cc3000/nvmem.h>
#include <nuttx/wireless/cc3000/security.h>
#include <nuttx/wireless/cc3000/evnt_handler.h>
#include "cc3000.h"
#include "cc3000drv.h"
/*****************************************************************************
* Preprocessor Definitions
*****************************************************************************/
#define SMART_CONFIG_PROFILE_SIZE 67 /* 67 = 32 (max ssid) + 32 (max key) +
* 1 (SSID length) + 1 (security type) +
* 1 (key length) */
/* SOCKET_SELECT_PARAMS_LEN + SPI_HEADER_SIZE++SIMPLE_LINK_HCI_DATA_HEADER_SIZ */
#define MAX_HCI_CMD_LENGTH (44+SIMPLE_LINK_HCI_DATA_HEADER_SIZE+SPI_HEADER_SIZE)
/* Patches type */
#define PATCHES_HOST_TYPE_WLAN_DRIVER 0x01
#define PATCHES_HOST_TYPE_WLAN_FW 0x02
#define PATCHES_HOST_TYPE_BOOTLOADER 0x03
#define SL_SET_SCAN_PARAMS_INTERVAL_LIST_SIZE (16)
#define SL_SIMPLE_CONFIG_PREFIX_LENGTH (3)
#define ETH_ALEN (6)
#define MAXIMAL_SSID_LENGTH (32)
#define SL_PATCHES_REQUEST_DEFAULT (0)
#define SL_PATCHES_REQUEST_FORCE_HOST (1)
#define SL_PATCHES_REQUEST_FORCE_NONE (2)
#define WLAN_SEC_UNSEC (0)
#define WLAN_SEC_WEP (1)
#define WLAN_SEC_WPA (2)
#define WLAN_SEC_WPA2 (3)
#define WLAN_SL_INIT_START_PARAMS_LEN (1)
#define WLAN_PATCH_PARAMS_LENGTH (8)
#define WLAN_SET_CONNECTION_POLICY_PARAMS_LEN (12)
#define WLAN_DEL_PROFILE_PARAMS_LEN (4)
#define WLAN_SET_MASK_PARAMS_LEN (4)
#define WLAN_SET_SCAN_PARAMS_LEN (100)
#define WLAN_GET_SCAN_RESULTS_PARAMS_LEN (4)
#define WLAN_ADD_PROFILE_NOSEC_PARAM_LEN (24)
#define WLAN_ADD_PROFILE_WEP_PARAM_LEN (36)
#define WLAN_ADD_PROFILE_WPA_PARAM_LEN (44)
#define WLAN_CONNECT_PARAM_LEN (29)
#define WLAN_SMART_CONFIG_START_PARAMS_LEN (4)
/****************************************************************************
* Private Variables
****************************************************************************/
/*****************************************************************************
* Public Data
*****************************************************************************/
volatile sSimplLinkInformation tSLInformation;
#ifndef CC3000_UNENCRYPTED_SMART_CONFIG
uint8_t akey[AES128_KEY_SIZE];
uint8_t profileArray[SMART_CONFIG_PROFILE_SIZE];
#endif /* CC3000_UNENCRYPTED_SMART_CONFIG */
/*****************************************************************************
* Public Functions
*****************************************************************************/
/*****************************************************************************
* Name: SimpleLink_Init_Start
*
* Input Parameters:
* usPatchesAvailableAtHost flag to indicate if patches available
* from host or from EEPROM. Due to the
* fact the patches are burn to the EEPROM
* using the patch programmer utility, the
* patches will be available from the EEPROM
* and not from the host.
*
* Returned Value:
* None
*
* Description:
* Send HCI_CMND_SIMPLE_LINK_START to CC3000
*
*****************************************************************************/
static void SimpleLink_Init_Start(uint16_t usPatchesAvailableAtHost)
{
uint8_t *ptr;
uint8_t *args;
ptr = tSLInformation.pucTxCommandBuffer;
args = (uint8_t *)(ptr + HEADERS_SIZE_CMD);
if (usPatchesAvailableAtHost <= SL_PATCHES_REQUEST_DEFAULT ||
usPatchesAvailableAtHost > SL_PATCHES_REQUEST_FORCE_NONE)
{
usPatchesAvailableAtHost = SL_PATCHES_REQUEST_DEFAULT;
}
UINT8_TO_STREAM(args, usPatchesAvailableAtHost);
/* IRQ Line asserted - send HCI_CMND_SIMPLE_LINK_START to CC3000 */
hci_command_send(HCI_CMND_SIMPLE_LINK_START, ptr, WLAN_SL_INIT_START_PARAMS_LEN);
SimpleLinkWaitEvent(HCI_CMND_SIMPLE_LINK_START, 0);
}
/*****************************************************************************
* Name: wlan_init
*
* Input Parameters:
* sWlanCB Asynchronous events callback.
* 0 no event call back.
* - call back parameters:
* 1) event_type: HCI_EVNT_WLAN_UNSOL_CONNECT connect event,
* HCI_EVNT_WLAN_UNSOL_DISCONNECT disconnect event,
* HCI_EVNT_WLAN_ASYNC_SIMPLE_CONFIG_DONE config done,
* HCI_EVNT_WLAN_UNSOL_DHCP dhcp report,
* HCI_EVNT_WLAN_ASYNC_PING_REPORT ping report OR
* HCI_EVNT_WLAN_KEEPALIVE keepalive.
* 2) data: pointer to extra data that received by the event
* (NULL no data).
* 3) length: data length.
* - Events with extra data:
* HCI_EVNT_WLAN_UNSOL_DHCP: 4 bytes IP, 4 bytes Mask,
* 4 bytes default gateway, 4 bytes DHCP server and 4 bytes
* for DNS server.
* HCI_EVNT_WLAN_ASYNC_PING_REPORT: 4 bytes Packets sent,
* 4 bytes Packets received, 4 bytes Min round time,
* 4 bytes Max round time and 4 bytes for Avg round time.
*
* sFWPatches 0 no patch or pointer to FW patches
* sDriverPatches 0 no patch or pointer to driver patches
* sBootLoaderPatches 0 no patch or pointer to bootloader patches
*
* Returned Value:
* None
*
* Description:
* Initialize wlan driver
*
* WARNING: This function must be called before ANY other wlan driver function
*
*****************************************************************************/
void wlan_init(size_t max_tx_len,
tWlanCB sWlanCB,
tFWPatches sFWPatches,
tDriverPatches sDriverPatches,
tBootLoaderPatches sBootLoaderPatches)
{
void *old = NULL;
cc3000_lib_lock();
tSLInformation.sFWPatches = sFWPatches;
tSLInformation.sDriverPatches = sDriverPatches;
tSLInformation.sBootLoaderPatches = sBootLoaderPatches;
/* Allocate the memory for the RX/TX data transactions */
if (tSLInformation.pucTxCommandBuffer != NULL)
{
old = tSLInformation.pucTxCommandBuffer;
}
tSLInformation.pucTxCommandBuffer = malloc(max_tx_len);
tSLInformation.usrBuffer.pbuffer = &tSLInformation.pucTxCommandBuffer[MAX_HCI_CMD_LENGTH];
tSLInformation.usrBuffer.len = max_tx_len - MAX_HCI_CMD_LENGTH;
/* Init I/O callback */
/* Init asynchronous events callback */
tSLInformation.sWlanCB= sWlanCB;
/* By default TX Complete events are routed to host too */
tSLInformation.InformHostOnTxComplete = 1;
cc3000_lib_unlock();
if (old)
{
free(old);
}
}
/*****************************************************************************
* Name: SpiReceiveHandler
*
* Input Parameters:
* pvBuffer - pointer to the received data buffer
*
* Returned Value:
* None
*
* Description:
* The function triggers Received event/data processing. It is
* called from the SPI library to receive the data
*
*****************************************************************************/
void SpiReceiveHandler(void *pvBuffer)
{
uint16_t event_type;
tSLInformation.pucReceivedData = (uint8_t *)pvBuffer;
tSLInformation.usEventOrDataReceived = 1;
STREAM_TO_UINT16((char *)tSLInformation.pucReceivedData,
HCI_EVENT_OPCODE_OFFSET, event_type);
nllvdbg("Evnt:0x%x\n", event_type);
UNUSED(event_type);
hci_unsolicited_event_handler();
}
/*****************************************************************************
* Name: wlan_start
*
* Input Parameters:
* usPatchesAvailableAtHost - flag to indicate if patches available
* from host or from EEPROM. Due to the
* fact the patches are burn to the EEPROM
* using the patch programmer utility, the
* patches will be available from the EEPROM
* and not from the host.
*
* Returned Value:
* None
*
* Description:
* Start WLAN device. This function asserts the enable pin of
* the device (WLAN_EN), starting the HW initialization process.
* The function blocked until device Initialization is completed.
* Function also configure patches (FW, driver or bootloader)
* and calls appropriate device callbacks.
*
* NOTE: Prior calling the function wlan_init shall be called.
* WARNING: This function must be called after wlan_init and before any
* other wlan API
*
*****************************************************************************/
void wlan_start(uint16_t usPatchesAvailableAtHost)
{
cc3000_lib_lock();
tSLInformation.NumberOfSentPackets = 0;
tSLInformation.NumberOfReleasedPackets = 0;
tSLInformation.usRxEventOpcode = 0;
tSLInformation.usNumberOfFreeBuffers = 0;
tSLInformation.usSlBufferLength = 0;
tSLInformation.usBufferSize = 0;
tSLInformation.usRxDataPending = 0;
tSLInformation.slTransmitDataError = 0;
tSLInformation.usEventOrDataReceived = 0;
tSLInformation.pucReceivedData = 0;
/* Init spi */
cc3000_open(SpiReceiveHandler);
SimpleLink_Init_Start(usPatchesAvailableAtHost);
/* Read Buffer's size and finish */
hci_command_send(HCI_CMND_READ_BUFFER_SIZE, tSLInformation.pucTxCommandBuffer, 0);
SimpleLinkWaitEvent(HCI_CMND_READ_BUFFER_SIZE, 0);
cc3000_lib_unlock();
}
/*****************************************************************************
* Name: wlan_get_buffer
*
* Input Parameters:
* pdes - Location to return the buffer pointer.
*
* Returned Value:
* None
*
*****************************************************************************/
void wlan_get_buffer(wlan_buffer_desc *pdes)
{
*pdes = tSLInformation.usrBuffer;
}
/*****************************************************************************
* Name: wlan_stop
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
* Description:
* Stop WLAN device by putting it into reset state.
*
*****************************************************************************/
void wlan_stop(void)
{
cc3000_lib_lock();
cc3000_close();
cc3000_lib_unlock();
}
/*****************************************************************************
* Name: wlan_connect
*
* Input Parameters:
* sec_type security options:
* WLAN_SEC_UNSEC,
* WLAN_SEC_WEP (ASCII support only),
* WLAN_SEC_WPA or WLAN_SEC_WPA2
* ssid up to 32 bytes and is ASCII SSID of the AP
* ssid_len length of the SSID
* bssid 6 bytes specified the AP bssid
* key up to 16 bytes specified the AP security key
* key_len key length
*
* Returned Value:
* On success, zero is returned. On error, negative is returned.
* Note that even though a zero is returned on success to trigger
* connection operation, it does not mean that CCC3000 is already
* connected. An asynchronous "Connected" event is generated when
* actual association process finishes and CC3000 is connected to
* the AP. If DHCP is set, An asynchronous "DHCP" event is
* generated when DHCP process is finish.
*
* Description:
* Connect to AP
*
* WARNING: Please Note that when connection to AP configured with security
* type WEP, please confirm that the key is set as ASCII and not
* as HEX.
*
*****************************************************************************/
#ifndef CC3000_TINY_DRIVER
long wlan_connect(unsigned long ulSecType, char *ssid, long ssid_len,
uint8_t *bssid, uint8_t *key, long key_len)
{
long ret;
uint8_t *ptr;
uint8_t *args;
uint8_t bssid_zero[] = {0, 0, 0, 0, 0, 0};
cc3000_lib_lock();
ret = EFAIL;
ptr = tSLInformation.pucTxCommandBuffer;
args = (ptr + HEADERS_SIZE_CMD);
/* Fill in command buffer */
args = UINT32_TO_STREAM(args, 0x0000001c);
args = UINT32_TO_STREAM(args, ssid_len);
args = UINT32_TO_STREAM(args, ulSecType);
args = UINT32_TO_STREAM(args, 0x00000010 + ssid_len);
args = UINT32_TO_STREAM(args, key_len);
args = UINT16_TO_STREAM(args, 0);
/* Padding shall be zeroed */
if (bssid)
{
ARRAY_TO_STREAM(args, bssid, ETH_ALEN);
}
else
{
ARRAY_TO_STREAM(args, bssid_zero, ETH_ALEN);
}
ARRAY_TO_STREAM(args, ssid, ssid_len);
if (key_len && key)
{
ARRAY_TO_STREAM(args, key, key_len);
}
/* Initiate a HCI command */
hci_command_send(HCI_CMND_WLAN_CONNECT, ptr, WLAN_CONNECT_PARAM_LEN +
ssid_len + key_len - 1);
/* Wait for command complete event */
SimpleLinkWaitEvent(HCI_CMND_WLAN_CONNECT, &ret);
set_errno(ret);
cc3000_lib_unlock();
return ret;
}
#else
long wlan_connect(char *ssid, long ssid_len)
{
long ret;
uint8_t *ptr;
uint8_t *args;
uint8_t bssid_zero[] = {0, 0, 0, 0, 0, 0};
cc3000_lib_lock();
ret = EFAIL;
ptr = tSLInformation.pucTxCommandBuffer;
args = (ptr + HEADERS_SIZE_CMD);
/* Fill in command buffer */
args = UINT32_TO_STREAM(args, 0x0000001c);
args = UINT32_TO_STREAM(args, ssid_len);
args = UINT32_TO_STREAM(args, 0);
args = UINT32_TO_STREAM(args, 0x00000010 + ssid_len);
args = UINT32_TO_STREAM(args, 0);
args = UINT16_TO_STREAM(args, 0);
/* Padding shall be zeroed */
ARRAY_TO_STREAM(args, bssid_zero, ETH_ALEN);
ARRAY_TO_STREAM(args, ssid, ssid_len);
/* Initiate a HCI command */
hci_command_send(HCI_CMND_WLAN_CONNECT, ptr, WLAN_CONNECT_PARAM_LEN +
ssid_len - 1);
/* Wait for command complete event */
SimpleLinkWaitEvent(HCI_CMND_WLAN_CONNECT, &ret);
set_errno(ret);
cc3000_lib_unlock();
return ret;
}
#endif
/*****************************************************************************
* Name: wlan_disconnect
*
* Input Parameters:
* None
*
* Returned Value:
* 0 disconnected done, other CC3000 already disconnected
*
* Description:
* Disconnect connection from AP.
*
*****************************************************************************/
long wlan_disconnect(void)
{
long ret;
uint8_t *ptr;
cc3000_lib_lock();
ret = EFAIL;
ptr = tSLInformation.pucTxCommandBuffer;
hci_command_send(HCI_CMND_WLAN_DISCONNECT, ptr, 0);
/* Wait for command complete event */
SimpleLinkWaitEvent(HCI_CMND_WLAN_DISCONNECT, &ret);
set_errno(ret);
cc3000_lib_unlock();
return ret;
}
/*****************************************************************************
* Name: wlan_ioctl_set_connection_policy
*
* Input Parameters:
* should_connect_to_open_ap enable(1), disable(0) connect to any
* available AP. This parameter corresponds to the configuration of
* item # 3 in the brief description.
* should_use_fast_connect enable(1), disable(0). if enabled, tries
* to connect to the last connected AP. This parameter corresponds
* to the configuration of item # 1 in the brief description.
* auto_start enable(1), disable(0) auto connect
* after reset and periodically reconnect if needed. This
* configuration configures option 2 in the above description.
*
* Returned Value:
* On success, zero is returned. On error, -1 is returned
*
* Description:
* When auto is enabled, the device tries to connect according
* the following policy:
* 1) If fast connect is enabled and last connection is valid,
* the device will try to connect to it without the scanning
* procedure (fast). The last connection will be marked as
* invalid, due to adding/removing profile.
* 2) If profile exists, the device will try to connect it
* (Up to seven profiles).
* 3) If fast and profiles are not found, and open mode is
* enabled, the device will try to connect to any AP.
* * Note that the policy settings are stored in the CC3000 NVMEM.
*
*****************************************************************************/
long wlan_ioctl_set_connection_policy(unsigned long should_connect_to_open_ap,
unsigned long ulShouldUseFastConnect,
unsigned long ulUseProfiles)
{
long ret;
uint8_t *ptr;
uint8_t *args;
cc3000_lib_lock();
ret = EFAIL;
ptr = tSLInformation.pucTxCommandBuffer;
args = (uint8_t *)(ptr + HEADERS_SIZE_CMD);
/* Fill in HCI packet structure */
args = UINT32_TO_STREAM(args, should_connect_to_open_ap);
args = UINT32_TO_STREAM(args, ulShouldUseFastConnect);
args = UINT32_TO_STREAM(args, ulUseProfiles);
/* Initiate a HCI command */
hci_command_send(HCI_CMND_WLAN_IOCTL_SET_CONNECTION_POLICY,
ptr, WLAN_SET_CONNECTION_POLICY_PARAMS_LEN);
/* Wait for command complete event */
SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_SET_CONNECTION_POLICY, &ret);
cc3000_lib_unlock();
return ret;
}
/*****************************************************************************
* Name: wlan_add_profile
*
* Input Parameters:
* ulSecType WLAN_SEC_UNSEC,WLAN_SEC_WEP,WLAN_SEC_WPA,WLAN_SEC_WPA2
* ucSsid ssid SSID up to 32 bytes
* ulSsidLen ssid length
* ucBssid bssid 6 bytes
* ulPriority ulPriority profile priority. Lowest priority:0.
* ulPairwiseCipher_Or_TxKeyLen key length for WEP security
* ulGroupCipher_TxKeyIndex key index
* ulKeyMgmt KEY management
* ucPf_OrKey security key
* ulPassPhraseLen security key length for WPA\WPA2
*
* Returned Value:
* On success, zero is returned. On error, -1 is returned
*
* Description:
* When auto start is enabled, the device connects to
* station from the profiles table. Up to 7 profiles are supported.
* If several profiles configured the device choose the highest
* priority profile, within each priority group, device will choose
* profile based on security policy, signal strength, etc
* parameters. All the profiles are stored in CC3000 NVMEM.
*
*****************************************************************************/
#ifndef CC3000_TINY_DRIVER
long wlan_add_profile(unsigned long ulSecType, uint8_t* ucSsid,
unsigned long ulSsidLen, uint8_t *ucBssid,
unsigned long ulPriority,
unsigned long ulPairwiseCipher_Or_TxKeyLen,
unsigned long ulGroupCipher_TxKeyIndex,
unsigned long ulKeyMgmt, uint8_t* ucPf_OrKey,
unsigned long ulPassPhraseLen)
{
uint16_t arg_len = 0;
long ret;
uint8_t *ptr;
long i = 0;
uint8_t *args;
uint8_t bssid_zero[] = {0, 0, 0, 0, 0, 0};
cc3000_lib_lock();
ptr = tSLInformation.pucTxCommandBuffer;
args = (ptr + HEADERS_SIZE_CMD);
args = UINT32_TO_STREAM(args, ulSecType);
/* Setup arguments in accordance with the security type */
switch (ulSecType)
{
/* OPEN */
case WLAN_SEC_UNSEC:
{
args = UINT32_TO_STREAM(args, 0x00000014);
args = UINT32_TO_STREAM(args, ulSsidLen);
args = UINT16_TO_STREAM(args, 0);
if (ucBssid)
{
ARRAY_TO_STREAM(args, ucBssid, ETH_ALEN);
}
else
{
ARRAY_TO_STREAM(args, bssid_zero, ETH_ALEN);
}
args = UINT32_TO_STREAM(args, ulPriority);
ARRAY_TO_STREAM(args, ucSsid, ulSsidLen);
arg_len = WLAN_ADD_PROFILE_NOSEC_PARAM_LEN + ulSsidLen;
}
break;
/* WEP */
case WLAN_SEC_WEP:
{
args = UINT32_TO_STREAM(args, 0x00000020);
args = UINT32_TO_STREAM(args, ulSsidLen);
args = UINT16_TO_STREAM(args, 0);
if (ucBssid)
{
ARRAY_TO_STREAM(args, ucBssid, ETH_ALEN);
}
else
{
ARRAY_TO_STREAM(args, bssid_zero, ETH_ALEN);
}
args = UINT32_TO_STREAM(args, ulPriority);
args = UINT32_TO_STREAM(args, 0x0000000C + ulSsidLen);
args = UINT32_TO_STREAM(args, ulPairwiseCipher_Or_TxKeyLen);
args = UINT32_TO_STREAM(args, ulGroupCipher_TxKeyIndex);
ARRAY_TO_STREAM(args, ucSsid, ulSsidLen);
for (i = 0; i < 4; i++)
{
uint8_t *p = &ucPf_OrKey[i * ulPairwiseCipher_Or_TxKeyLen];
ARRAY_TO_STREAM(args, p, ulPairwiseCipher_Or_TxKeyLen);
}
arg_len = WLAN_ADD_PROFILE_WEP_PARAM_LEN + ulSsidLen +
ulPairwiseCipher_Or_TxKeyLen * 4;
}
break;
/*WPA, WPA2 */
case WLAN_SEC_WPA:
case WLAN_SEC_WPA2:
{
args = UINT32_TO_STREAM(args, 0x00000028);
args = UINT32_TO_STREAM(args, ulSsidLen);
args = UINT16_TO_STREAM(args, 0);
if (ucBssid)
{
ARRAY_TO_STREAM(args, ucBssid, ETH_ALEN);
}
else
{
ARRAY_TO_STREAM(args, bssid_zero, ETH_ALEN);
}
args = UINT32_TO_STREAM(args, ulPriority);
args = UINT32_TO_STREAM(args, ulPairwiseCipher_Or_TxKeyLen);
args = UINT32_TO_STREAM(args, ulGroupCipher_TxKeyIndex);
args = UINT32_TO_STREAM(args, ulKeyMgmt);
args = UINT32_TO_STREAM(args, 0x00000008 + ulSsidLen);
args = UINT32_TO_STREAM(args, ulPassPhraseLen);
ARRAY_TO_STREAM(args, ucSsid, ulSsidLen);
ARRAY_TO_STREAM(args, ucPf_OrKey, ulPassPhraseLen);
arg_len = WLAN_ADD_PROFILE_WPA_PARAM_LEN + ulSsidLen + ulPassPhraseLen;
}
break;
}
/* Initiate a HCI command */
hci_command_send(HCI_CMND_WLAN_IOCTL_ADD_PROFILE,
ptr, arg_len);
/* Wait for command complete event */
SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_ADD_PROFILE, &ret);
cc3000_lib_unlock();
return ret;
}
#else
long wlan_add_profile(unsigned long ulSecType, uint8_t * ucSsid, uint8_t ulSsidLen,
uint8_t *ucBssid, unsigned long ulPriority,
unsigned long ulPairwiseCipher_Or_TxKeyLen,
unsigned long ulGroupCipher_TxKeyIndex,
unsigned long ulKeyMgmt, uint8_t * ucPf_OrKey,
unsigned long ulPassPhraseLen)
{
return -1;
}
#endif
/*****************************************************************************
* Name: wlan_ioctl_del_profile
*
* Input Parameters:
* index number of profile to delete
*
* Returned Value:
* On success, zero is returned. On error, -1 is returned
*
* Description:
* Delete WLAN profile
*
* @Note In order to delete all stored profile, set index to 255.
*
*****************************************************************************/
long wlan_ioctl_del_profile(unsigned long ulIndex)
{
long ret;
uint8_t *ptr;
uint8_t *args;
cc3000_lib_lock();
ptr = tSLInformation.pucTxCommandBuffer;
args = (uint8_t *)(ptr + HEADERS_SIZE_CMD);
/* Fill in HCI packet structure */
args = UINT32_TO_STREAM(args, ulIndex);
ret = EFAIL;
/* Initiate a HCI command */
hci_command_send(HCI_CMND_WLAN_IOCTL_DEL_PROFILE,
ptr, WLAN_DEL_PROFILE_PARAMS_LEN);
/* Wait for command complete event */
SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_DEL_PROFILE, &ret);
cc3000_lib_unlock();
return ret;
}
/*****************************************************************************
* Name: wlan_ioctl_get_scan_results
*
* Input Parameters:
* scan_timeout parameter not supported
* ucResults scan results (_wlan_full_scan_results_args_t)
*
* Returned Value:
* On success, zero is returned. On error, -1 is returned
*
* Description:
* Gets entry from scan result table.
* The scan results are returned one by one, and each entry
* represents a single AP found in the area. The following is a
* format of the scan result:
* - 4 Bytes: number of networks found
* - 4 Bytes: The status of the scan: 0 - aged results,
* 1 - results valid, 2 - no results
* - 42 bytes: Result entry, where the bytes are arranged as follows:
* - 1 bit isValid - is result valid or not
* - 7 bits rssi - RSSI value;
* - 2 bits: securityMode - security mode of the AP:
* 0 - Open, 1 - WEP, 2 WPA, 3 WPA2
* - 6 bits: SSID name length
* - 2 bytes: the time at which the entry has entered into
* scans result table
* - 32 bytes: SSID name
* - 6 bytes: BSSID
*
* NOTE: scan_timeout, is not supported on this version.
*
*****************************************************************************/
#ifndef CC3000_TINY_DRIVER
long wlan_ioctl_get_scan_results(unsigned long ulScanTimeout, uint8_t *ucResults)
{
uint8_t *ptr;
uint8_t *args;
cc3000_lib_lock();
ptr = tSLInformation.pucTxCommandBuffer;
args = (ptr + HEADERS_SIZE_CMD);
/* Fill in temporary command buffer */
args = UINT32_TO_STREAM(args, ulScanTimeout);
/* Initiate a HCI command */
hci_command_send(HCI_CMND_WLAN_IOCTL_GET_SCAN_RESULTS,
ptr, WLAN_GET_SCAN_RESULTS_PARAMS_LEN);
/* Wait for command complete event */
SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_GET_SCAN_RESULTS, ucResults);
cc3000_lib_unlock();
return 0;
}
#endif
/*****************************************************************************
* Name: wlan_ioctl_set_scan_params
*
* Input Parameters:
* uiEnable - start/stop application scan:
* 1 = start scan with default interval value of 10 min.
* in order to set a different scan interval value apply the value
* in milliseconds. minimum 1 second. 0=stop). Wlan reset
* (wlan_stop() wlan_start()) is needed when changing scan interval
* value. Saved: No
* uiMinDwellTime minimum dwell time value to be used for each
* channel, in milliseconds. Saved: yes
* Recommended Value: 100 (Default: 20)
* uiMaxDwellTime maximum dwell time value to be used for each
* channel, in milliseconds. Saved: yes
* Recommended Value: 100 (Default: 30)
* uiNumOfProbeRequests max probe request between dwell time.
* Saved: yes. Recommended Value: 5 (Default:2)
* uiChannelMask bitwise, up to 13 channels (0x1fff).
* Saved: yes. Default: 0x7ff
* uiRSSIThreshold RSSI threshold. Saved: yes (Default: -80)
* uiSNRThreshold NSR threshold. Saved: yes (Default: 0)
* uiDefaultTxPower probe Tx power. Saved: yes (Default: 205)
* aiIntervalList pointer to array with 16 entries (16 channels)
* each entry (unsigned long) holds timeout between periodic scan
* (connection scan) - in millisecond. Saved: yes. Default 2000ms.
*
* Returned Value:
* On success, zero is returned. On error, -1 is returned
*
* Description:
* start and stop scan procedure. Set scan parameters.
*
* @Note uiDefaultTxPower, is not supported on this version.
*
*****************************************************************************/
#ifndef CC3000_TINY_DRIVER
long wlan_ioctl_set_scan_params(unsigned long uiEnable,
unsigned long uiMinDwellTime,
unsigned long uiMaxDwellTime,
unsigned long uiNumOfProbeRequests,
unsigned long uiChannelMask,long iRSSIThreshold,
unsigned long uiSNRThreshold,
unsigned long uiDefaultTxPower,
unsigned long *aiIntervalList)
{
unsigned long uiRes;
uint8_t *ptr;
uint8_t *args;
cc3000_lib_lock();
ptr = tSLInformation.pucTxCommandBuffer;
args = (ptr + HEADERS_SIZE_CMD);
/* Fill in temporary command buffer */
args = UINT32_TO_STREAM(args, 36);
args = UINT32_TO_STREAM(args, uiEnable);
args = UINT32_TO_STREAM(args, uiMinDwellTime);
args = UINT32_TO_STREAM(args, uiMaxDwellTime);
args = UINT32_TO_STREAM(args, uiNumOfProbeRequests);
args = UINT32_TO_STREAM(args, uiChannelMask);
args = UINT32_TO_STREAM(args, iRSSIThreshold);
args = UINT32_TO_STREAM(args, uiSNRThreshold);
args = UINT32_TO_STREAM(args, uiDefaultTxPower);
ARRAY_TO_STREAM(args, aiIntervalList, sizeof(unsigned long) *
SL_SET_SCAN_PARAMS_INTERVAL_LIST_SIZE);
/* Initiate a HCI command */
hci_command_send(HCI_CMND_WLAN_IOCTL_SET_SCANPARAM,
ptr, WLAN_SET_SCAN_PARAMS_LEN);
/* Wait for command complete event */
SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_SET_SCANPARAM, &uiRes);
cc3000_lib_unlock();
return uiRes;
}
#endif
/*****************************************************************************
* Name: wlan_set_event_mask
*
* Input Parameters:
* mask mask option:
* HCI_EVNT_WLAN_UNSOL_CONNECT connect event
* HCI_EVNT_WLAN_UNSOL_DISCONNECT disconnect event
* HCI_EVNT_WLAN_ASYNC_SIMPLE_CONFIG_DONE smart config done
* HCI_EVNT_WLAN_UNSOL_INIT init done
* HCI_EVNT_WLAN_UNSOL_DHCP dhcp event report
* HCI_EVNT_WLAN_ASYNC_PING_REPORT ping report
* HCI_EVNT_WLAN_KEEPALIVE keepalive
* HCI_EVNT_WLAN_TX_COMPLETE - disable information on end of transmission
* Saved: no.
*
* Returned Value:
* On success, zero is returned. On error, -1 is returned
*
* Description:
* Mask event according to bit mask. In case that event is
* masked (1), the device will not send the masked event to host.
*
*****************************************************************************/
long wlan_set_event_mask(unsigned long ulMask)
{
long ret;
uint8_t *ptr;
uint8_t *args;
cc3000_lib_lock();
if ((ulMask & HCI_EVNT_WLAN_TX_COMPLETE) == HCI_EVNT_WLAN_TX_COMPLETE)
{
tSLInformation.InformHostOnTxComplete = 0;
/* Since an event is a virtual event - i.e. it is not coming from CC3000
* there is no need to send anything to the device if it was an only event
*/
if (ulMask == HCI_EVNT_WLAN_TX_COMPLETE)
{
return 0;
}
ulMask &= ~HCI_EVNT_WLAN_TX_COMPLETE;
ulMask |= HCI_EVNT_WLAN_UNSOL_BASE;
}
else
{
tSLInformation.InformHostOnTxComplete = 1;
}
ret = EFAIL;
ptr = tSLInformation.pucTxCommandBuffer;
args = (uint8_t *)(ptr + HEADERS_SIZE_CMD);
/* Fill in HCI packet structure */
args = UINT32_TO_STREAM(args, ulMask);
/* Initiate a HCI command */
hci_command_send(HCI_CMND_EVENT_MASK,
ptr, WLAN_SET_MASK_PARAMS_LEN);
/* Wait for command complete event */
SimpleLinkWaitEvent(HCI_CMND_EVENT_MASK, &ret);
cc3000_lib_unlock();
return ret;
}
/*****************************************************************************
* Name: wlan_ioctl_statusget
*
* Input Parameters:
* None
*
* Returned Value:
* WLAN_STATUS_DISCONNECTED, WLAN_STATUS_SCANING,
* STATUS_CONNECTING or WLAN_STATUS_CONNECTED
*
* Description:
* get wlan status: disconnected, scanning, connecting or connected
*
*****************************************************************************/
#ifndef CC3000_TINY_DRIVER
long wlan_ioctl_statusget(void)
{
long ret;
uint8_t *ptr;
cc3000_lib_lock();
ret = EFAIL;
ptr = tSLInformation.pucTxCommandBuffer;
hci_command_send(HCI_CMND_WLAN_IOCTL_STATUSGET,
ptr, 0);
/* Wait for command complete event */
SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_STATUSGET, &ret);
cc3000_lib_unlock();
return ret;
}
#endif
/*****************************************************************************
* Name: wlan_smart_config_start
*
* Input Parameters:
* algoEncryptedFlag indicates whether the information is encrypted
*
* Returned Value:
* On success, zero is returned. On error, -1 is returned
*
* Description:
* Start to acquire device profile. The device acquire its own
* profile, if profile message is found. The acquired AP information
* is stored in CC3000 EEPROM only in case AES128 encryption is used.
* In case AES128 encryption is not used, a profile is created by
* CC3000 internally.
*
* @Note An asynchronous event - Smart Config Done will be generated as soon
* as the process finishes successfully.
*
*****************************************************************************/
long wlan_smart_config_start(unsigned long algoEncryptedFlag)
{
long ret;
uint8_t *ptr;
uint8_t *args;
cc3000_lib_lock();
ret = EFAIL;
ptr = tSLInformation.pucTxCommandBuffer;
args = (uint8_t *)(ptr + HEADERS_SIZE_CMD);
/* Fill in HCI packet structure */
args = UINT32_TO_STREAM(args, algoEncryptedFlag);
hci_command_send(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_START, ptr,
WLAN_SMART_CONFIG_START_PARAMS_LEN);
/* Wait for command complete event */
SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_START, &ret);
cc3000_lib_unlock();
return ret;
}
/*****************************************************************************
* Name: wlan_smart_config_stop
*
* Input Parameters:
* algoEncryptedFlag indicates whether the information is encrypted
*
* Returned Value:
* On success, zero is returned. On error, -1 is returned
*
* Description:
* Stop the acquire profile procedure
*
*****************************************************************************/
long wlan_smart_config_stop(void)
{
long ret;
uint8_t *ptr;
cc3000_lib_lock();
ret = EFAIL;
ptr = tSLInformation.pucTxCommandBuffer;
hci_command_send(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_STOP, ptr, 0);
/* Wait for command complete event */
SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_STOP, &ret);
cc3000_lib_unlock();
return ret;
}
/*****************************************************************************
* Name: wlan_smart_config_set_prefix
*
* Input Parameters:
* newPrefix 3 bytes identify the SSID prefix for the Smart Config.
*
* Returned Value:
* On success, zero is returned. On error, -1 is returned
*
* Description:
* Configure station ssid prefix. The prefix is used internally
* in CC3000. It should always be TTT.
*
* @Note The prefix is stored in CC3000 NVMEM
*
*****************************************************************************/
long wlan_smart_config_set_prefix(char* cNewPrefix)
{
long ret;
uint8_t *ptr;
uint8_t *args;
cc3000_lib_lock();
ret = EFAIL;
ptr = tSLInformation.pucTxCommandBuffer;
args = (ptr + HEADERS_SIZE_CMD);
if (cNewPrefix == NULL)
{
return ret;
}
/* With the new Smart Config, prefix must be TTT */
else
{
*cNewPrefix = 'T';
*(cNewPrefix + 1) = 'T';
*(cNewPrefix + 2) = 'T';
}
ARRAY_TO_STREAM(args, cNewPrefix, SL_SIMPLE_CONFIG_PREFIX_LENGTH);
hci_command_send(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_SET_PREFIX, ptr,
SL_SIMPLE_CONFIG_PREFIX_LENGTH);
/* Wait for command complete event */
SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_SET_PREFIX, &ret);
cc3000_lib_unlock();
return ret;
}
/*****************************************************************************
* Name: wlan_smart_config_process
*
* Input Parameters:
* None
*
* Returned Value:
* On success, zero is returned. On error, -1 is returned
*
* Description:
* process the acquired data and store it as a profile. The acquired
* AP information is stored in CC3000 EEPROM encrypted.
* The encrypted data is decrypted and stored as a profile.
* behavior is as defined by connection policy.
*
*****************************************************************************/
#ifndef CC3000_UNENCRYPTED_SMART_CONFIG
long wlan_smart_config_process()
{
signed long returnValue;
unsigned long ssidLen, keyLen;
uint8_t *decKeyPtr;
uint8_t *ssidPtr;
/* Read the key from EEPROM - fileID 12 */
returnValue = aes_read_key(akey);
if (returnValue != 0)
{
return returnValue;
}
/* Read the received data from fileID #13 and parse it according to the followings:
* 1) SSID LEN - not encrypted
* 2) SSID - not encrypted
* 3) KEY LEN - not encrypted. always 32 bytes long
* 4) Security type - not encrypted
* 5) KEY - encrypted together with true key length as the first byte in KEY
* to elaborate, there are two corner cases:
* 1) the KEY is 32 bytes long. In this case, the first byte does not represent
* KEY length
* 2) the KEY is 31 bytes long. In this case, the first byte represent KEY
* length and equals 31
*/
returnValue = nvmem_read(NVMEM_SHARED_MEM_FILEID, SMART_CONFIG_PROFILE_SIZE,
0, profileArray);
if (returnValue != 0)
{
return returnValue;
}
ssidPtr = &profileArray[1];
ssidLen = profileArray[0];
decKeyPtr = &profileArray[profileArray[0] + 3];
aes_decrypt(decKeyPtr, akey);
if (profileArray[profileArray[0] + 1] > 16)
{
aes_decrypt((uint8_t *)(decKeyPtr + 16), akey);
}
if (*(uint8_t *)(decKeyPtr +31) != 0)
{
if (*decKeyPtr == 31)
{
keyLen = 31;
decKeyPtr++;
}
else
{
keyLen = 32;
}
}
else
{
keyLen = *decKeyPtr;
decKeyPtr++;
}
/* Add a profile */
switch (profileArray[profileArray[0] + 2])
{
case WLAN_SEC_UNSEC: /* None */
{
returnValue = wlan_add_profile(profileArray[profileArray[0] + 2], /* Security type */
ssidPtr, /* SSID */
ssidLen, /* SSID length */
NULL, /* BSSID */
1, /* Priority */
0, 0, 0, 0, 0);
break;
}
case WLAN_SEC_WEP: /* WEP */
{
returnValue = wlan_add_profile(profileArray[profileArray[0] + 2], /* Security type */
ssidPtr, /* SSID */
ssidLen, /* SSID length */
NULL, /* BSSID */
1, /* Priority */
keyLen, /* KEY length */
0, /* KEY index */
0,
decKeyPtr, /* KEY */
0);
break;
}
case WLAN_SEC_WPA: /* WPA */
case WLAN_SEC_WPA2: /* WPA2 */
{
returnValue = wlan_add_profile(WLAN_SEC_WPA2, /* Security type */
ssidPtr,
ssidLen,
NULL, /* BSSID */
1, /* Priority */
0x18, /* PairwiseCipher */
0x1e, /* GroupCipher */
2, /* KEY management */
decKeyPtr, /* KEY */
keyLen); /* KEY length */
break;
}
}
return returnValue;
}
#endif /* CC3000_UNENCRYPTED_SMART_CONFIG */