#include <string.h>
#include "wlan.h"
#include "hci.h"
#include "ccspi.h"
#include "socket.h"
#include "nvmem.h"
#include "security.h"
#include "evnt_handler.h"
volatile sSimplLinkInformation tSLInformation;
#define SMART_CONFIG_PROFILE_SIZE 67
#ifndef CC3000_UNENCRYPTED_SMART_CONFIG
UINT8 key[AES128_KEY_SIZE];
UINT8 profileArray[SMART_CONFIG_PROFILE_SIZE];
#endif
#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)
static void SimpleLink_Init_Start(UINT16 usPatchesAvailableAtHost)
{
UINT8 *ptr;
UINT8 *args;
ptr = tSLInformation.pucTxCommandBuffer;
args = (UINT8 *)(ptr + HEADERS_SIZE_CMD);
UINT8_TO_STREAM(args, ((usPatchesAvailableAtHost) ? SL_PATCHES_REQUEST_FORCE_NONE : SL_PATCHES_REQUEST_DEFAULT));
hci_command_send(HCI_CMND_SIMPLE_LINK_START, ptr, WLAN_SL_INIT_START_PARAMS_LEN);
SimpleLinkWaitEvent(HCI_CMND_SIMPLE_LINK_START, 0);
}
void wlan_init( tWlanCB sWlanCB,
tFWPatches sFWPatches,
tDriverPatches sDriverPatches,
tBootLoaderPatches sBootLoaderPatches,
tWlanReadInteruptPin sReadWlanInterruptPin,
tWlanInterruptEnable sWlanInterruptEnable,
tWlanInterruptDisable sWlanInterruptDisable,
tWriteWlanPin sWriteWlanPin)
{
tSLInformation.sFWPatches = sFWPatches;
tSLInformation.sDriverPatches = sDriverPatches;
tSLInformation.sBootLoaderPatches = sBootLoaderPatches;
tSLInformation.ReadWlanInterruptPin = sReadWlanInterruptPin;
tSLInformation.WlanInterruptEnable = sWlanInterruptEnable;
tSLInformation.WlanInterruptDisable = sWlanInterruptDisable;
tSLInformation.WriteWlanPin = sWriteWlanPin;
tSLInformation.sWlanCB= sWlanCB;
tSLInformation.InformHostOnTxComplete = 1;
}
void SpiReceiveHandler(void *pvBuffer)
{
tSLInformation.usEventOrDataReceived = 1;
tSLInformation.pucReceivedData = (UINT8 *)pvBuffer;
hci_unsolicited_event_handler();
}
#define TIMEOUT (500000)
int wlan_start(UINT16 usPatchesAvailableAtHost)
{
UINT32 ulSpiIRQState;
UINT32 wlan_timeout;
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;
tSLInformation.pucTxCommandBuffer = (UINT8 *)wlan_tx_buffer;
SpiOpen(SpiReceiveHandler);
ulSpiIRQState = tSLInformation.ReadWlanInterruptPin();
tSLInformation.WriteWlanPin( WLAN_ENABLE );
wlan_timeout = TIMEOUT;
if (ulSpiIRQState) {
while(tSLInformation.ReadWlanInterruptPin() != 0 && --wlan_timeout)
{
}
}
else
{
while(tSLInformation.ReadWlanInterruptPin() == 0 && --wlan_timeout)
{
}
if (wlan_timeout == 0) {
return -1;
}
wlan_timeout = TIMEOUT;
while(tSLInformation.ReadWlanInterruptPin() != 0 && --wlan_timeout)
{
}
}
if (wlan_timeout ==0) {
return -1;
}
SimpleLink_Init_Start(usPatchesAvailableAtHost);
hci_command_send(HCI_CMND_READ_BUFFER_SIZE, tSLInformation.pucTxCommandBuffer, 0);
SimpleLinkWaitEvent(HCI_CMND_READ_BUFFER_SIZE, 0);
return 0;
}
void wlan_stop(void)
{
tSLInformation.WriteWlanPin( WLAN_DISABLE );
while(tSLInformation.ReadWlanInterruptPin() == 0)
{
}
if (tSLInformation.pucTxCommandBuffer)
{
tSLInformation.pucTxCommandBuffer = 0;
}
SpiClose();
}
#ifndef CC3000_TINY_DRIVER
INT32 wlan_connect(UINT32 ulSecType, CHAR *ssid, INT32 ssid_len,
UINT8 *bssid, UINT8 *key, INT32 key_len)
{
INT32 ret;
UINT8 *ptr;
UINT8 *args;
UINT8 bssid_zero[] = {0, 0, 0, 0, 0, 0};
ret = EFAIL;
ptr = tSLInformation.pucTxCommandBuffer;
args = (ptr + HEADERS_SIZE_CMD);
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);
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);
}
hci_command_send(HCI_CMND_WLAN_CONNECT, ptr, WLAN_CONNECT_PARAM_LEN +
ssid_len + key_len - 1);
SimpleLinkWaitEvent(HCI_CMND_WLAN_CONNECT, &ret);
CC3000_EXPORT(errno) = ret;
return(ret);
}
#else
INT32 wlan_connect(CHAR *ssid, INT32 ssid_len)
{
INT32 ret;
UINT8 *ptr;
UINT8 *args;
UINT8 bssid_zero[] = {0, 0, 0, 0, 0, 0};
ret = EFAIL;
ptr = tSLInformation.pucTxCommandBuffer;
args = (ptr + HEADERS_SIZE_CMD);
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);
ARRAY_TO_STREAM(args, bssid_zero, ETH_ALEN);
ARRAY_TO_STREAM(args, ssid, ssid_len);
hci_command_send(HCI_CMND_WLAN_CONNECT, ptr, WLAN_CONNECT_PARAM_LEN +
ssid_len - 1);
SimpleLinkWaitEvent(HCI_CMND_WLAN_CONNECT, &ret);
CC3000_EXPORT(errno) = ret;
return(ret);
}
#endif
INT32 wlan_disconnect()
{
INT32 ret;
UINT8 *ptr;
ret = EFAIL;
ptr = tSLInformation.pucTxCommandBuffer;
hci_command_send(HCI_CMND_WLAN_DISCONNECT, ptr, 0);
SimpleLinkWaitEvent(HCI_CMND_WLAN_DISCONNECT, &ret);
CC3000_EXPORT(errno) = ret;
return(ret);
}
INT32 wlan_ioctl_set_connection_policy(UINT32 should_connect_to_open_ap,
UINT32 ulShouldUseFastConnect,
UINT32 ulUseProfiles)
{
INT32 ret;
UINT8 *ptr;
UINT8 *args;
ret = EFAIL;
ptr = tSLInformation.pucTxCommandBuffer;
args = (UINT8 *)(ptr + HEADERS_SIZE_CMD);
args = UINT32_TO_STREAM(args, should_connect_to_open_ap);
args = UINT32_TO_STREAM(args, ulShouldUseFastConnect);
args = UINT32_TO_STREAM(args, ulUseProfiles);
hci_command_send(HCI_CMND_WLAN_IOCTL_SET_CONNECTION_POLICY,
ptr, WLAN_SET_CONNECTION_POLICY_PARAMS_LEN);
SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_SET_CONNECTION_POLICY, &ret);
return(ret);
}
#ifndef CC3000_TINY_DRIVER
INT32 wlan_add_profile(UINT32 ulSecType,
UINT8* ucSsid,
UINT32 ulSsidLen,
UINT8 *ucBssid,
UINT32 ulPriority,
UINT32 ulPairwiseCipher_Or_TxKeyLen,
UINT32 ulGroupCipher_TxKeyIndex,
UINT32 ulKeyMgmt,
UINT8* ucPf_OrKey,
UINT32 ulPassPhraseLen)
{
UINT16 arg_len=0;
INT32 ret;
UINT8 *ptr;
INT32 i = 0;
UINT8 *args;
UINT8 bssid_zero[] = {0, 0, 0, 0, 0, 0};
ptr = tSLInformation.pucTxCommandBuffer;
args = (ptr + HEADERS_SIZE_CMD);
args = UINT32_TO_STREAM(args, ulSecType);
switch (ulSecType)
{
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;
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 *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;
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;
}
hci_command_send(HCI_CMND_WLAN_IOCTL_ADD_PROFILE,
ptr, arg_len);
SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_ADD_PROFILE, &ret);
return(ret);
}
#else
INT32 wlan_add_profile(UINT32 ulSecType,
UINT8* ucSsid,
UINT32 ulSsidLen,
UINT8 *ucBssid,
UINT32 ulPriority,
UINT32 ulPairwiseCipher_Or_TxKeyLen,
UINT32 ulGroupCipher_TxKeyIndex,
UINT32 ulKeyMgmt,
UINT8* ucPf_OrKey,
UINT32 ulPassPhraseLen)
{
return -1;
}
#endif
INT32 wlan_ioctl_del_profile(UINT32 ulIndex)
{
INT32 ret;
UINT8 *ptr;
UINT8 *args;
ptr = tSLInformation.pucTxCommandBuffer;
args = (UINT8 *)(ptr + HEADERS_SIZE_CMD);
args = UINT32_TO_STREAM(args, ulIndex);
ret = EFAIL;
hci_command_send(HCI_CMND_WLAN_IOCTL_DEL_PROFILE,
ptr, WLAN_DEL_PROFILE_PARAMS_LEN);
SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_DEL_PROFILE, &ret);
return(ret);
}
#ifndef CC3000_TINY_DRIVER
INT32 wlan_ioctl_get_scan_results(UINT32 ulScanTimeout,
UINT8 *ucResults)
{
UINT8 *ptr;
UINT8 *args;
ptr = tSLInformation.pucTxCommandBuffer;
args = (ptr + HEADERS_SIZE_CMD);
args = UINT32_TO_STREAM(args, ulScanTimeout);
hci_command_send(HCI_CMND_WLAN_IOCTL_GET_SCAN_RESULTS,
ptr, WLAN_GET_SCAN_RESULTS_PARAMS_LEN);
SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_GET_SCAN_RESULTS, ucResults);
return(0);
}
#endif
#ifndef CC3000_TINY_DRIVER
INT32 wlan_ioctl_set_scan_params(UINT32 uiEnable, UINT32 uiMinDwellTime,
UINT32 uiMaxDwellTime,
UINT32 uiNumOfProbeRequests,
UINT32 uiChannelMask,INT32 iRSSIThreshold,
UINT32 uiSNRThreshold,
UINT32 uiDefaultTxPower,
UINT32 *aiIntervalList)
{
UINT32 uiRes;
UINT8 *ptr;
UINT8 *args;
ptr = tSLInformation.pucTxCommandBuffer;
args = (ptr + HEADERS_SIZE_CMD);
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(UINT32) *
SL_SET_SCAN_PARAMS_INTERVAL_LIST_SIZE);
hci_command_send(HCI_CMND_WLAN_IOCTL_SET_SCANPARAM,
ptr, WLAN_SET_SCAN_PARAMS_LEN);
SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_SET_SCANPARAM, &uiRes);
return(uiRes);
}
#endif
INT32 wlan_set_event_mask(UINT32 ulMask)
{
INT32 ret;
UINT8 *ptr;
UINT8 *args;
if ((ulMask & HCI_EVNT_WLAN_TX_COMPLETE) == HCI_EVNT_WLAN_TX_COMPLETE)
{
tSLInformation.InformHostOnTxComplete = 0;
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 *)(ptr + HEADERS_SIZE_CMD);
args = UINT32_TO_STREAM(args, ulMask);
hci_command_send(HCI_CMND_EVENT_MASK,
ptr, WLAN_SET_MASK_PARAMS_LEN);
SimpleLinkWaitEvent(HCI_CMND_EVENT_MASK, &ret);
return(ret);
}
#ifndef CC3000_TINY_DRIVER
INT32 wlan_ioctl_statusget(void)
{
INT32 ret;
UINT8 *ptr;
ret = EFAIL;
ptr = tSLInformation.pucTxCommandBuffer;
hci_command_send(HCI_CMND_WLAN_IOCTL_STATUSGET,
ptr, 0);
SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_STATUSGET, &ret);
return(ret);
}
#endif
INT32 wlan_smart_config_start(UINT32 algoEncryptedFlag)
{
INT32 ret;
UINT8 *ptr;
UINT8 *args;
ret = EFAIL;
ptr = tSLInformation.pucTxCommandBuffer;
args = (UINT8 *)(ptr + HEADERS_SIZE_CMD);
args = UINT32_TO_STREAM(args, algoEncryptedFlag);
ret = EFAIL;
hci_command_send(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_START, ptr,
WLAN_SMART_CONFIG_START_PARAMS_LEN);
SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_START, &ret);
return(ret);
}
INT32 wlan_smart_config_stop(void)
{
INT32 ret;
UINT8 *ptr;
ret = EFAIL;
ptr = tSLInformation.pucTxCommandBuffer;
hci_command_send(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_STOP, ptr, 0);
SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_STOP, &ret);
return(ret);
}
INT32 wlan_smart_config_set_prefix(CHAR* cNewPrefix)
{
INT32 ret;
UINT8 *ptr;
UINT8 *args;
ret = EFAIL;
ptr = tSLInformation.pucTxCommandBuffer;
args = (ptr + HEADERS_SIZE_CMD);
if (cNewPrefix == NULL)
return ret;
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);
SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_SET_PREFIX, &ret);
return(ret);
}
#ifndef CC3000_UNENCRYPTED_SMART_CONFIG
INT32 wlan_smart_config_process()
{
INT32 returnValue;
UINT32 ssidLen, keyLen;
UINT8 *decKeyPtr;
UINT8 *ssidPtr;
returnValue = aes_read_key(key);
if (returnValue != 0)
return returnValue;
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, key);
if (profileArray[profileArray[0] + 1] > 16)
aes_decrypt((UINT8 *)(decKeyPtr + 16), key);
if (*(UINT8 *)(decKeyPtr +31) != 0)
{
if (*decKeyPtr == 31)
{
keyLen = 31;
decKeyPtr++;
}
else
{
keyLen = 32;
}
}
else
{
keyLen = *decKeyPtr;
decKeyPtr++;
}
switch (profileArray[profileArray[0] + 2])
{
case WLAN_SEC_UNSEC: {
returnValue = wlan_add_profile(profileArray[profileArray[0] + 2], ssidPtr, ssidLen, NULL, 1, 0, 0, 0, 0, 0);
break;
}
case WLAN_SEC_WEP: {
returnValue = wlan_add_profile(profileArray[profileArray[0] + 2], ssidPtr, ssidLen, NULL, 1, keyLen, 0, 0,
decKeyPtr, 0);
break;
}
case WLAN_SEC_WPA: case WLAN_SEC_WPA2: {
returnValue = wlan_add_profile(WLAN_SEC_WPA2, ssidPtr,
ssidLen,
NULL, 1, 0x18, 0x1e, 2, decKeyPtr, keyLen);
break;
}
}
return returnValue;
}
#endif