1/*
2 * cu_wext.c
3 *
4 * Copyright 2001-2009 Texas Instruments, Inc. - http://www.ti.com/
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19/****************************************************************************
20*
21*   MODULE:  CU_Wext.c
22*
23*   PURPOSE:
24*
25*   DESCRIPTION:
26*   ============
27*
28*
29****************************************************************************/
30
31/* includes */
32/************/
33#include "cu_osapi.h"
34#include "oserr.h"
35#include <net/if.h>
36#include <linux/rtnetlink.h>
37#include <linux/wireless.h>
38#include <string.h>
39#include <stdlib.h>
40
41#include "TWDriver.h"
42#include "STADExternalIf.h"
43#include "ParsEvent.h"
44#include "ipc_sta.h"
45#include "cu_os.h"
46
47/* defines */
48/***********/
49
50/* local types */
51/***************/
52/* Module control block */
53typedef struct
54{
55    THandle hIpcSta;
56    union iwreq_data req_data;
57
58    struct iw_scan_req *scan_req;
59    U16 scan_flag;
60} TCuWext;
61
62/* local variables */
63/*******************/
64
65/* local fucntions */
66/*******************/
67static S32 CuWext_FillBssidList(struct iw_event *iwe, OS_802_11_BSSID_EX* bssidList, S32 index)
68{
69    S32 res = 0;
70    switch(iwe->cmd)
71    {
72        case SIOCGIWAP:
73            os_memcpy(bssidList[index].MacAddress, iwe->u.ap_addr.sa_data, MAC_ADDR_LEN);
74            bssidList[index].Configuration.BeaconPeriod = 0; /* default configuration */
75            res = 1;
76            break;
77        case SIOCGIWESSID:
78            bssidList[index-1].Ssid.SsidLength = iwe->u.data.length;
79            os_memcpy(bssidList[index-1].Ssid.Ssid, iwe->u.data.pointer, bssidList[index-1].Ssid.SsidLength);
80            if(iwe->u.data.length != MAX_SSID_LEN)
81                bssidList[index-1].Ssid.Ssid[bssidList[index-1].Ssid.SsidLength] = 0;
82            break;
83        case SIOCGIWNAME:
84            {
85                unsigned i;
86                S8 buffer[IFNAMSIZ];
87                static const char *ieee80211_modes[] = {
88                    "?",
89                    "IEEE 802.11 B",
90                    "IEEE 802.11 A",
91                    "IEEE 802.11 BG",
92                    "IEEE 802.11 ABG" };
93
94                os_memset(buffer, 0, IFNAMSIZ);
95                os_memcpy(buffer, iwe->u.name, IFNAMSIZ);
96                for(i=0;i<SIZE_ARR(ieee80211_modes); i++)
97                    if (0 == os_strcmp((PS8)ieee80211_modes[i], buffer))
98                        break;
99                bssidList[index-1].NetworkTypeInUse = i;
100            }
101            break;
102        case SIOCGIWMODE:
103            if(iwe->u.mode == IW_MODE_ADHOC)
104                bssidList[index-1].InfrastructureMode = os802_11IBSS;
105            else if (iwe->u.mode == IW_MODE_INFRA)
106                bssidList[index-1].InfrastructureMode = os802_11Infrastructure;
107            else if (iwe->u.mode == IW_MODE_AUTO)
108                bssidList[index-1].InfrastructureMode = os802_11AutoUnknown;
109            else
110                bssidList[index-1].InfrastructureMode = os802_11InfrastructureMax;
111
112            break;
113        case SIOCGIWFREQ:
114            bssidList[index-1].Configuration.Union.channel = iwe->u.freq.m;
115            break;
116        case IWEVQUAL:
117            bssidList[index-1].Rssi = (S8)iwe->u.qual.level;
118            break;
119        case SIOCGIWENCODE:
120            if(iwe->u.data.flags == (IW_ENCODE_ENABLED | IW_ENCODE_NOKEY))
121            {
122                bssidList[index-1].Privacy = TRUE;
123                bssidList[index-1].Capabilities |= CAP_PRIVACY_MASK<<CAP_PRIVACY_SHIFT;
124            }
125            else
126            {
127                bssidList[index-1].Privacy = FALSE;
128                bssidList[index-1].Capabilities &= ~(CAP_PRIVACY_MASK<<CAP_PRIVACY_SHIFT);
129            }
130            break;
131        case SIOCGIWRATE:
132            break;
133        case IWEVCUSTOM:
134            {
135                S8 buffer[100];
136
137                os_memset(buffer, 0, 100);
138                os_memcpy(buffer, iwe->u.data.pointer, iwe->u.data.length);
139
140                if(!os_strncmp(buffer, (PS8)"Bcn", 3))
141                {
142                    char *p1;
143                    p1 = strtok(&buffer[10], " ");
144                    bssidList[index-1].Configuration.BeaconPeriod = atoi(p1);
145                }
146            }
147            break;
148    }
149
150    return res;
151}
152
153
154/* functions */
155/*************/
156
157THandle CuOs_Create(THandle hIpcSta)
158{
159    TCuWext* pCuWext = (TCuWext*)os_MemoryCAlloc(sizeof(TCuWext), sizeof(U8));
160    if(pCuWext == NULL)
161    {
162        os_error_printf(CU_MSG_ERROR, (PS8)"ERROR - CuOs_Create - cant allocate control block\n");
163        return NULL;
164    }
165
166    pCuWext->hIpcSta = hIpcSta;
167
168    return pCuWext;
169}
170
171VOID CuOs_Destroy(THandle hCuWext)
172{
173    TCuWext* pCuWext = (TCuWext*)hCuWext;
174
175    os_MemoryFree(pCuWext);
176}
177
178S32 CuOs_Get_SSID(THandle hCuWext, OS_802_11_SSID* ssid)
179{
180    TCuWext* pCuWext = (TCuWext*)hCuWext;
181    S32 res;
182
183    os_memset(ssid->Ssid, 0, sizeof(OS_802_11_SSID) - sizeof(U32));
184
185    pCuWext->req_data.essid.pointer = (PVOID)ssid->Ssid;
186    pCuWext->req_data.essid.length = sizeof(OS_802_11_SSID) - sizeof(U32);
187    pCuWext->req_data.essid.flags = 0;
188
189    res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCGIWESSID, &pCuWext->req_data, sizeof(struct iw_point));
190    if(res != OK)
191        return res;
192
193    ssid->SsidLength = pCuWext->req_data.essid.length;
194
195    return OK;
196}
197
198S32 CuOs_Get_BSSID(THandle hCuWext, TMacAddr bssid)
199{
200    TCuWext* pCuWext = (TCuWext*)hCuWext;
201    S32 res,i;
202
203    os_memset(&pCuWext->req_data.ap_addr, 0x00, sizeof(struct sockaddr));
204
205    res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCGIWAP, &pCuWext->req_data, sizeof(struct sockaddr));
206    if(res != OK)
207        return res;
208
209    for(i=0;i<MAC_ADDR_LEN;i++)
210        bssid[i] = pCuWext->req_data.ap_addr.sa_data[i];
211
212    return OK;
213}
214
215S32 CuOs_GetCurrentChannel(THandle hCuWext, U32* channel)
216{
217    TCuWext* pCuWext = (TCuWext*)hCuWext;
218    S32 res;
219
220    pCuWext->req_data.freq.m = 0;
221
222    res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCGIWFREQ, &pCuWext->req_data, sizeof(struct iw_freq    ));
223    if(res != OK)
224        return res;
225
226    *channel = pCuWext->req_data.freq.m;
227
228    return OK;
229}
230
231/*Usage example of SIOCGIWSTATS. This WEXT is used by wireless tools such as iwconfig, iwlib etc.*/
232S32 CuOs_GetCurrentStats(THandle hCuWext, S32* rssi)
233{
234    TCuWext* pCuWext = (TCuWext*)hCuWext;
235    S32 res;
236	struct	iw_statistics stat;
237	*rssi = 0;
238
239	pCuWext->req_data.data.pointer = &stat;
240
241	res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCGIWSTATS, &pCuWext->req_data, sizeof(struct iw_statistics));
242    if(res != OK)
243        return res;
244
245    *rssi = stat.qual.level;
246
247    return OK;
248}
249
250S32 CuOs_Start_Scan(THandle hCuWext, OS_802_11_SSID* ssid, U8 scanType)
251{
252    TCuWext* pCuWext = (TCuWext*)hCuWext;
253    struct iw_scan_req tReq;
254    S32 res;
255
256    if (ssid->SsidLength > IW_ESSID_MAX_SIZE)
257    {
258        os_error_printf(CU_MSG_ERROR, (PS8)"ERROR - CuOs_Start_Scan - too long SSID (%lu)\n",ssid->SsidLength);
259        return OSAL_ERROR;
260    }
261
262    if (ssid->Ssid[0] && ssid->SsidLength)
263    {
264        os_memset(&tReq, 0, sizeof(tReq));
265        tReq.essid_len = ssid->SsidLength;
266        /*
267         * tReq.bssid.sa_family = ARPHRD_ETHER;
268         * os_memset(tReq.bssid.sa_data, 0xff, ETH_ALEN);
269         */
270        os_memcpy(tReq.essid, ssid->Ssid, ssid->SsidLength);
271        pCuWext->scan_req = &tReq;
272        pCuWext->req_data.data.flags = IW_SCAN_THIS_ESSID;
273    }
274    else
275    {
276        pCuWext->req_data.data.flags = 0;
277    }
278
279	tReq.scan_type = scanType;
280    pCuWext->req_data.data.pointer = &tReq;
281    pCuWext->req_data.data.length = sizeof(struct iw_scan_req);
282
283    res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCSIWSCAN, &pCuWext->req_data, sizeof(struct iw_point));
284    if(res != OK)
285        return res;
286
287    return OK;
288}
289
290S32 CuOs_GetBssidList(THandle hCuWext, OS_802_11_BSSID_LIST_EX *bssidList)
291{
292    TCuWext* pCuWext = (TCuWext*)hCuWext;
293    S32 res, NumberOfItems;
294
295    /* allocate the scan result buffer */
296    U8* buffer = os_MemoryCAlloc(IW_SCAN_MAX_DATA, sizeof(U8));
297    if(buffer == NULL)
298    {
299        os_error_printf(CU_MSG_ERROR, (PS8)"ERROR - CuOs_Get_BssidList - cant allocate scan result buffer\n");
300        return EOALERR_CU_WEXT_ERROR_CANT_ALLOCATE;
301    }
302
303    NumberOfItems = 0;
304    pCuWext->req_data.data.pointer = buffer;
305    pCuWext->req_data.data.flags = 0;
306    do
307    {
308        pCuWext->req_data.data.length = IW_SCAN_MAX_DATA;
309
310        res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCGIWSCAN, &pCuWext->req_data, sizeof(struct iw_point));
311        if(res != OK)
312        {
313            os_MemoryFree(buffer);
314            return res;
315        }
316
317        /* parse the scan results */
318        if(pCuWext->req_data.data.length)
319        {
320            struct iw_event     iwe;
321            struct stream_descr stream;
322            S32                 ret;
323
324            /* init the event stream */
325            os_memset((char *)&stream, '\0', sizeof(struct stream_descr));
326            stream.current = (char *)buffer;
327            stream.end = (char *)(buffer + pCuWext->req_data.data.length);
328
329            do
330            {
331                /* Extract an event and print it */
332                ret = ParsEvent_GetEvent(&stream, &iwe);
333                if(ret > 0)
334                    NumberOfItems += CuWext_FillBssidList(&iwe, bssidList->Bssid, NumberOfItems);
335            }
336            while(ret > 0);
337        }
338
339    } while(pCuWext->req_data.data.flags);
340
341    bssidList->NumberOfItems = NumberOfItems;
342
343    /* free the scan result buffer */
344    os_MemoryFree(buffer);
345
346    return OK;
347}
348
349
350S32 CuOs_Set_BSSID(THandle hCuWext, TMacAddr bssid)
351{
352    TCuWext* pCuWext = (TCuWext*)hCuWext;
353    S32 res;
354
355    os_memcpy(pCuWext->req_data.ap_addr.sa_data, bssid, MAC_ADDR_LEN);
356
357    res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCSIWAP, &pCuWext->req_data, sizeof(struct sockaddr));
358
359    if(res != OK)
360        return res;
361
362    return OK;
363}
364
365S32 CuOs_Set_ESSID(THandle hCuWext, OS_802_11_SSID* ssid)
366{
367    TCuWext* pCuWext = (TCuWext*)hCuWext;
368    S32 res;
369
370    pCuWext->req_data.essid.pointer = (PVOID)ssid->Ssid;
371    pCuWext->req_data.essid.length = ssid->SsidLength;
372    if(ssid->SsidLength)
373        pCuWext->req_data.essid.flags = 1;
374    else
375        pCuWext->req_data.essid.flags = 0;
376    pCuWext->req_data.essid.flags |= SET_SSID_WITHOUT_SUPPL;
377
378    res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCSIWESSID, &pCuWext->req_data, sizeof(struct sockaddr));
379
380    if(res != OK)
381        return res;
382
383    return OK;
384}
385
386S32 CuOs_GetTxPowerLevel(THandle hCuWext, S32* pTxPowerLevel)
387{
388    TCuWext* pCuWext = (TCuWext*)hCuWext;
389    S32 res;
390
391    os_memset(&pCuWext->req_data.txpower, 0, sizeof(struct iw_param));
392
393    res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCGIWTXPOW, &pCuWext->req_data, sizeof(struct iw_param));
394
395    if(res != OK)
396        return res;
397
398    *pTxPowerLevel = pCuWext->req_data.txpower.value;
399
400    return OK;
401}
402
403S32 CuOs_SetTxPowerLevel(THandle hCuWext, S32 txPowerLevel)
404{
405    TCuWext* pCuWext = (TCuWext*)hCuWext;
406    S32 res;
407
408    os_memset(&pCuWext->req_data.txpower, 0, sizeof(struct iw_param));
409
410    pCuWext->req_data.txpower.value = txPowerLevel;
411
412    res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCSIWTXPOW, &pCuWext->req_data, sizeof(struct iw_param));
413
414    if(res != OK)
415        return res;
416
417    return OK;
418}
419
420S32 CuOs_GetRtsTh(THandle hCuWext, PS32 pRtsTh)
421{
422    TCuWext* pCuWext = (TCuWext*)hCuWext;
423    S32 res;
424
425    os_memset(&pCuWext->req_data.rts, 0, sizeof(struct iw_param));
426
427    res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCGIWRTS, &pCuWext->req_data, sizeof(struct iw_param));
428    if(res != OK)
429        return res;
430
431    *pRtsTh = pCuWext->req_data.rts.value;
432
433    return OK;
434}
435
436
437S32 CuOs_SetRtsTh(THandle hCuWext, S32 RtsTh)
438{
439    TCuWext* pCuWext = (TCuWext*)hCuWext;
440    S32 res;
441
442    os_memset(&pCuWext->req_data.rts, 0, sizeof(struct iw_param));
443    pCuWext->req_data.rts.value = RtsTh;
444
445    res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCSIWRTS, &pCuWext->req_data, sizeof(struct iw_param));
446    if(res != OK)
447        return res;
448
449
450
451    return OK;
452}
453
454S32 CuOs_GetFragTh(THandle hCuWext, PS32 pFragTh)
455{
456    TCuWext* pCuWext = (TCuWext*)hCuWext;
457    S32 res;
458
459    os_memset(&pCuWext->req_data.frag, 0, sizeof(struct iw_param));
460
461    res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCGIWFRAG, &pCuWext->req_data, sizeof(struct iw_param));
462    if(res != OK)
463        return res;
464
465    *pFragTh = pCuWext->req_data.frag.value;
466
467    return OK;
468}
469
470S32 CuOs_SetFragTh(THandle hCuWext, S32 FragTh)
471{
472    TCuWext* pCuWext = (TCuWext*)hCuWext;
473    S32 res;
474
475    os_memset(&pCuWext->req_data.frag, 0, sizeof(struct iw_param));
476    pCuWext->req_data.frag.value = FragTh;
477
478    res = IPC_STA_Wext_Send(pCuWext->hIpcSta, SIOCSIWFRAG, &pCuWext->req_data, sizeof(struct iw_param));
479    if(res != OK)
480        return res;
481
482    return OK;
483}
484/*stab function (should be filled later on for Linux to get ThreadID of the WLAN driver*/
485S32 CuOs_GetDriverThreadId(THandle hCuWext, U32* threadid)
486{
487	return OK;
488}
489