blob: 39189ad0427e4e9f9d3a5568d54967f4daccc03f [file] [log] [blame]
/*
* cu_wext.c
*
* Copyright 2001-2009 Texas Instruments, Inc. - http://www.ti.com/
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/****************************************************************************
*
* MODULE: CU_Wext.c
*
* PURPOSE:
*
* DESCRIPTION:
* ============
*
*
****************************************************************************/
/* includes */
/************/
#include "cu_osapi.h"
#include "oserr.h"
#include <net/if.h>
#include <linux/rtnetlink.h>
#include <linux/wireless.h>
#include <string.h>
#include <stdlib.h>
#include "TWDriver.h"
#include "STADExternalIf.h"
#include "ParsEvent.h"
#include "ipc_sta.h"
#include "cu_os.h"
/* defines */
/***********/
/* local types */
/***************/
/* Module control block */
typedef struct
{
THandle hIpcSta;
union iwreq_data req_data;
struct iw_scan_req *scan_req;
U16 scan_flag;
} TCuWext;
/* local variables */
/*******************/
/* local fucntions */
/*******************/
static S32 CuWext_FillBssidList(struct iw_event *iwe, OS_802_11_BSSID_EX* bssidList, S32 index)
{
S32 res = 0;
switch(iwe->cmd)
{
case SIOCGIWAP:
os_memcpy(bssidList[index].MacAddress, iwe->u.ap_addr.sa_data, MAC_ADDR_LEN);
bssidList[index].Configuration.BeaconPeriod = 0; /* default configuration */
res = 1;
break;
case SIOCGIWESSID:
bssidList[index-1].Ssid.SsidLength = iwe->u.data.length;
os_memcpy(bssidList[index-1].Ssid.Ssid, iwe->u.data.pointer, bssidList[index-1].Ssid.SsidLength);
if(iwe->u.data.length != MAX_SSID_LEN)
bssidList[index-1].Ssid.Ssid[bssidList[index-1].Ssid.SsidLength] = 0;
break;
case SIOCGIWNAME:
{
unsigned i;
S8 buffer[IFNAMSIZ];
static const char *ieee80211_modes[] = {
"?",
"IEEE 802.11 B",
"IEEE 802.11 A",
"IEEE 802.11 BG",
"IEEE 802.11 ABG" };
os_memset(buffer, 0, IFNAMSIZ);
os_memcpy(buffer, iwe->u.name, IFNAMSIZ);
for(i=0;i<SIZE_ARR(ieee80211_modes); i++)
if (0 == os_strcmp((PS8)ieee80211_modes[i], buffer))
break;
bssidList[index-1].NetworkTypeInUse = i;
}
break;
case SIOCGIWMODE:
if(iwe->u.mode == IW_MODE_ADHOC)
bssidList[index-1].InfrastructureMode = os802_11IBSS;
else if (iwe->u.mode == IW_MODE_INFRA)
bssidList[index-1].InfrastructureMode = os802_11Infrastructure;
else if (iwe->u.mode == IW_MODE_AUTO)
bssidList[index-1].InfrastructureMode = os802_11AutoUnknown;
else
bssidList[index-1].InfrastructureMode = os802_11InfrastructureMax;
break;
case SIOCGIWFREQ:
bssidList[index-1].Configuration.Union.channel = iwe->u.freq.m;
break;
case IWEVQUAL:
bssidList[index-1].Rssi = (S8)iwe->u.qual.level;
break;
case SIOCGIWENCODE:
if(iwe->u.data.flags == (IW_ENCODE_ENABLED | IW_ENCODE_NOKEY))
{
bssidList[index-1].Privacy = TRUE;
bssidList[index-1].Capabilities |= CAP_PRIVACY_MASK<<CAP_PRIVACY_SHIFT;
}
else
{
bssidList[index-1].Privacy = FALSE;
bssidList[index-1].Capabilities &= ~(CAP_PRIVACY_MASK<<CAP_PRIVACY_SHIFT);
}
break;
case SIOCGIWRATE:
break;
case IWEVCUSTOM:
{
S8 buffer[100];
os_memset(buffer, 0, 100);
os_memcpy(buffer, iwe->u.data.pointer, iwe->u.data.length);
if(!os_strncmp(buffer, (PS8)"Bcn", 3))
{
char *p1;
p1 = strtok(&buffer[10], " ");
bssidList[index-1].Configuration.BeaconPeriod = atoi(p1);
}
}
break;
}
return res;
}
/* functions */
/*************/
THandle CuOs_Create(THandle hIpcSta)
{
TCuWext* pCuWext = (TCuWext*)os_MemoryCAlloc(sizeof(TCuWext), sizeof(U8));
if(pCuWext == NULL)
{
os_error_printf(CU_MSG_ERROR, (PS8)"ERROR - CuOs_Create - cant allocate control block\n");
return NULL;
}
pCuWext->hIpcSta = hIpcSta;
return pCuWext;
}
VOID CuOs_Destroy(THandle hCuWext)
{
TCuWext* pCuWext = (TCuWext*)hCuWext;
os_MemoryFree(pCuWext);
}
S32 CuOs_Get_SSID(THandle hCuWext, OS_802_11_SSID* ssid)
{
TCuWext* pCuWext = (TCuWext*)hCuWext;
S32 res;
os_memset(ssid->Ssid, 0, sizeof(OS_802_11_SSID) - sizeof(U32));
pCuWext->req_data.essid.pointer = (PVOID)ssid->Ssid;
pCuWext->req_data.essid.length = sizeof(OS_802_11_SSID) - sizeof(U32);
pCuWext->req_data.essid.flags = 0;
res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCGIWESSID, &pCuWext->req_data, sizeof(struct iw_point));
if(res != OK)
return res;
ssid->SsidLength = pCuWext->req_data.essid.length;
return OK;
}
S32 CuOs_Get_BSSID(THandle hCuWext, TMacAddr bssid)
{
TCuWext* pCuWext = (TCuWext*)hCuWext;
S32 res,i;
os_memset(&pCuWext->req_data.ap_addr, 0x00, sizeof(struct sockaddr));
res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCGIWAP, &pCuWext->req_data, sizeof(struct sockaddr));
if(res != OK)
return res;
for(i=0;i<MAC_ADDR_LEN;i++)
bssid[i] = pCuWext->req_data.ap_addr.sa_data[i];
return OK;
}
S32 CuOs_GetCurrentChannel(THandle hCuWext, U32* channel)
{
TCuWext* pCuWext = (TCuWext*)hCuWext;
S32 res;
pCuWext->req_data.freq.m = 0;
res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCGIWFREQ, &pCuWext->req_data, sizeof(struct iw_freq ));
if(res != OK)
return res;
*channel = pCuWext->req_data.freq.m;
return OK;
}
/*Usage example of SIOCGIWSTATS. This WEXT is used by wireless tools such as iwconfig, iwlib etc.*/
S32 CuOs_GetCurrentStats(THandle hCuWext, S32* rssi)
{
TCuWext* pCuWext = (TCuWext*)hCuWext;
S32 res;
struct iw_statistics stat;
*rssi = 0;
pCuWext->req_data.data.pointer = &stat;
res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCGIWSTATS, &pCuWext->req_data, sizeof(struct iw_statistics));
if(res != OK)
return res;
*rssi = stat.qual.level;
return OK;
}
S32 CuOs_Start_Scan(THandle hCuWext, OS_802_11_SSID* ssid, U8 scanType)
{
TCuWext* pCuWext = (TCuWext*)hCuWext;
struct iw_scan_req tReq;
S32 res;
if (ssid->SsidLength > IW_ESSID_MAX_SIZE)
{
os_error_printf(CU_MSG_ERROR, (PS8)"ERROR - CuOs_Start_Scan - too long SSID (%lu)\n",ssid->SsidLength);
return OSAL_ERROR;
}
if (ssid->Ssid[0] && ssid->SsidLength)
{
os_memset(&tReq, 0, sizeof(tReq));
tReq.essid_len = ssid->SsidLength;
/*
* tReq.bssid.sa_family = ARPHRD_ETHER;
* os_memset(tReq.bssid.sa_data, 0xff, ETH_ALEN);
*/
os_memcpy(tReq.essid, ssid->Ssid, ssid->SsidLength);
pCuWext->scan_req = &tReq;
pCuWext->req_data.data.flags = IW_SCAN_THIS_ESSID;
}
else
{
pCuWext->req_data.data.flags = 0;
}
tReq.scan_type = scanType;
pCuWext->req_data.data.pointer = &tReq;
pCuWext->req_data.data.length = sizeof(struct iw_scan_req);
res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCSIWSCAN, &pCuWext->req_data, sizeof(struct iw_point));
if(res != OK)
return res;
return OK;
}
S32 CuOs_GetBssidList(THandle hCuWext, OS_802_11_BSSID_LIST_EX *bssidList)
{
TCuWext* pCuWext = (TCuWext*)hCuWext;
S32 res, NumberOfItems;
/* allocate the scan result buffer */
U8* buffer = os_MemoryCAlloc(IW_SCAN_MAX_DATA, sizeof(U8));
if(buffer == NULL)
{
os_error_printf(CU_MSG_ERROR, (PS8)"ERROR - CuOs_Get_BssidList - cant allocate scan result buffer\n");
return EOALERR_CU_WEXT_ERROR_CANT_ALLOCATE;
}
NumberOfItems = 0;
pCuWext->req_data.data.pointer = buffer;
pCuWext->req_data.data.flags = 0;
do
{
pCuWext->req_data.data.length = IW_SCAN_MAX_DATA;
res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCGIWSCAN, &pCuWext->req_data, sizeof(struct iw_point));
if(res != OK)
{
os_MemoryFree(buffer);
return res;
}
/* parse the scan results */
if(pCuWext->req_data.data.length)
{
struct iw_event iwe;
struct stream_descr stream;
S32 ret;
/* init the event stream */
os_memset((char *)&stream, '\0', sizeof(struct stream_descr));
stream.current = (char *)buffer;
stream.end = (char *)(buffer + pCuWext->req_data.data.length);
do
{
/* Extract an event and print it */
ret = ParsEvent_GetEvent(&stream, &iwe);
if(ret > 0)
NumberOfItems += CuWext_FillBssidList(&iwe, bssidList->Bssid, NumberOfItems);
}
while(ret > 0);
}
} while(pCuWext->req_data.data.flags);
bssidList->NumberOfItems = NumberOfItems;
/* free the scan result buffer */
os_MemoryFree(buffer);
return OK;
}
S32 CuOs_Set_BSSID(THandle hCuWext, TMacAddr bssid)
{
TCuWext* pCuWext = (TCuWext*)hCuWext;
S32 res;
os_memcpy(pCuWext->req_data.ap_addr.sa_data, bssid, MAC_ADDR_LEN);
res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCSIWAP, &pCuWext->req_data, sizeof(struct sockaddr));
if(res != OK)
return res;
return OK;
}
S32 CuOs_Set_ESSID(THandle hCuWext, OS_802_11_SSID* ssid)
{
TCuWext* pCuWext = (TCuWext*)hCuWext;
S32 res;
pCuWext->req_data.essid.pointer = (PVOID)ssid->Ssid;
pCuWext->req_data.essid.length = ssid->SsidLength;
if(ssid->SsidLength)
pCuWext->req_data.essid.flags = 1;
else
pCuWext->req_data.essid.flags = 0;
pCuWext->req_data.essid.flags |= SET_SSID_WITHOUT_SUPPL;
res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCSIWESSID, &pCuWext->req_data, sizeof(struct sockaddr));
if(res != OK)
return res;
return OK;
}
S32 CuOs_GetTxPowerLevel(THandle hCuWext, S32* pTxPowerLevel)
{
TCuWext* pCuWext = (TCuWext*)hCuWext;
S32 res;
os_memset(&pCuWext->req_data.txpower, 0, sizeof(struct iw_param));
res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCGIWTXPOW, &pCuWext->req_data, sizeof(struct iw_param));
if(res != OK)
return res;
*pTxPowerLevel = pCuWext->req_data.txpower.value;
return OK;
}
S32 CuOs_SetTxPowerLevel(THandle hCuWext, S32 txPowerLevel)
{
TCuWext* pCuWext = (TCuWext*)hCuWext;
S32 res;
os_memset(&pCuWext->req_data.txpower, 0, sizeof(struct iw_param));
pCuWext->req_data.txpower.value = txPowerLevel;
res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCSIWTXPOW, &pCuWext->req_data, sizeof(struct iw_param));
if(res != OK)
return res;
return OK;
}
S32 CuOs_GetRtsTh(THandle hCuWext, PS32 pRtsTh)
{
TCuWext* pCuWext = (TCuWext*)hCuWext;
S32 res;
os_memset(&pCuWext->req_data.rts, 0, sizeof(struct iw_param));
res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCGIWRTS, &pCuWext->req_data, sizeof(struct iw_param));
if(res != OK)
return res;
*pRtsTh = pCuWext->req_data.rts.value;
return OK;
}
S32 CuOs_SetRtsTh(THandle hCuWext, S32 RtsTh)
{
TCuWext* pCuWext = (TCuWext*)hCuWext;
S32 res;
os_memset(&pCuWext->req_data.rts, 0, sizeof(struct iw_param));
pCuWext->req_data.rts.value = RtsTh;
res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCSIWRTS, &pCuWext->req_data, sizeof(struct iw_param));
if(res != OK)
return res;
return OK;
}
S32 CuOs_GetFragTh(THandle hCuWext, PS32 pFragTh)
{
TCuWext* pCuWext = (TCuWext*)hCuWext;
S32 res;
os_memset(&pCuWext->req_data.frag, 0, sizeof(struct iw_param));
res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCGIWFRAG, &pCuWext->req_data, sizeof(struct iw_param));
if(res != OK)
return res;
*pFragTh = pCuWext->req_data.frag.value;
return OK;
}
S32 CuOs_SetFragTh(THandle hCuWext, S32 FragTh)
{
TCuWext* pCuWext = (TCuWext*)hCuWext;
S32 res;
os_memset(&pCuWext->req_data.frag, 0, sizeof(struct iw_param));
pCuWext->req_data.frag.value = FragTh;
res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCSIWFRAG, &pCuWext->req_data, sizeof(struct iw_param));
if(res != OK)
return res;
return OK;
}
/*stab function (should be filled later on for Linux to get ThreadID of the WLAN driver*/
S32 CuOs_GetDriverThreadId(THandle hCuWext, U32* threadid)
{
return OK;
}