1/*
2 * ipc_sta.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:  IPC_STA.c
22*
23*   PURPOSE:
24*
25*   DESCRIPTION:
26*   ============
27*
28*
29****************************************************************************/
30
31/* includes */
32/************/
33#include <sys/types.h>
34#include <sys/socket.h>
35#include <net/if.h>
36#include <linux/rtnetlink.h>
37#include <errno.h>
38#include <sys/ioctl.h>
39#include <unistd.h>
40#include <linux/wireless.h>
41#include "cu_osapi.h"
42#include "oserr.h"
43#include "STADExternalIf.h"
44#include "ipc_sta.h"
45
46/* defines */
47/***********/
48
49/* local types */
50/***************/
51/* Module control block */
52typedef struct IpcSta_t
53{
54    struct iwreq    wext_req;
55    ti_private_cmd_t private_cmd;
56    S32 STA_socket;
57
58} IpcSta_t;
59
60/* local variables */
61/*******************/
62
63/* local fucntions */
64/*******************/
65
66/*
67 * IpcSta_Sockets_Open - Open a socket.
68 * Depending on the protocol present, open the right socket. The socket
69 * will allow us to talk to the driver.
70 */
71static S32 IpcSta_Sockets_Open(VOID)
72{
73    static const S32 families[] = {
74        AF_INET, AF_IPX, AF_APPLETALK
75    };
76    U32    i;
77    S32    sock;
78
79    /*
80    * Now pick any (exisiting) useful socket family for generic queries
81    * Note : don't open all the socket, only returns when one matches,
82    * all protocols might not be valid.
83    * Workaround by Jim Kaba <jkaba@sarnoff.com>
84    * Note : in 2001% of the case, we will just open the inet_sock.
85    * The remaining 2002% case are not fully correct...
86    */
87
88    /* Try all families we support */
89    for(i = 0; i < sizeof(families)/sizeof(int); ++i)
90    {
91        /* Try to open the socket, if success returns it */
92        sock = socket(families[i], SOCK_DGRAM, 0);
93        if(sock >= 0)
94            return sock;
95    }
96
97    return -1;
98}
99
100/*
101 * IpcSta_Sockets_Close - Close the socket used for ioctl.
102 */
103static inline VOID IpcSta_Sockets_Close(S32 skfd)
104{
105    close(skfd);
106}
107
108
109/* functions */
110/*************/
111THandle IpcSta_Create(const PS8 device_name)
112{
113    IpcSta_t* pIpcSta = (IpcSta_t*)os_MemoryCAlloc(sizeof(IpcSta_t), sizeof(U8));
114    if(pIpcSta == NULL)
115    {
116        os_error_printf(CU_MSG_ERROR, (PS8)"ERROR - IpcSta_Create - cant allocate control block\n");
117        return NULL;
118    }
119
120    /* open the socket to the driver */
121    pIpcSta->STA_socket = IpcSta_Sockets_Open();
122    if(pIpcSta->STA_socket == -1)
123    {
124        os_error_printf(CU_MSG_ERROR, (PS8)"ERROR - IpcSta_Create - cant open socket for communication with the driver\n");
125        return NULL;
126    }
127
128    /* set the driver name */
129    os_strcpy((PS8)pIpcSta->wext_req.ifr_ifrn.ifrn_name, device_name);
130
131    return pIpcSta;
132}
133
134VOID IpcSta_Destroy(THandle hIpcSta)
135{
136    IpcSta_t* pIpcSta = (IpcSta_t*)hIpcSta;
137
138    /* close the socket to the driver */
139    IpcSta_Sockets_Close(pIpcSta->STA_socket);
140
141    os_MemoryFree(pIpcSta);
142}
143
144S32 IPC_STA_Private_Send(THandle hIpcSta, U32 ioctl_cmd, PVOID bufIn, U32 sizeIn,
145                                                PVOID bufOut, U32 sizeOut)
146
147{
148    IpcSta_t* pIpcSta = (IpcSta_t*)hIpcSta;
149    S32 res;
150
151    pIpcSta ->private_cmd.cmd = ioctl_cmd;
152    if(bufOut == NULL)
153        pIpcSta ->private_cmd.flags = PRIVATE_CMD_SET_FLAG;
154    else
155        pIpcSta ->private_cmd.flags = PRIVATE_CMD_GET_FLAG;
156
157    pIpcSta ->private_cmd.in_buffer = bufIn;
158    pIpcSta ->private_cmd.in_buffer_len = sizeIn;
159    pIpcSta ->private_cmd.out_buffer = bufOut;
160    pIpcSta ->private_cmd.out_buffer_len = sizeOut;
161
162
163    pIpcSta->wext_req.u.data.pointer = &pIpcSta->private_cmd;
164    pIpcSta->wext_req.u.data.length = sizeof(ti_private_cmd_t);
165    pIpcSta->wext_req.u.data.flags = 0;
166
167    res = ioctl(pIpcSta->STA_socket, SIOCIWFIRSTPRIV, &pIpcSta->wext_req);
168    if(res != OK)
169    {
170        os_error_printf(CU_MSG_ERROR, (PS8)"ERROR - IPC_STA_Private_Send - error sending Wext private IOCTL to STA driver (ioctl_cmd = %x,  res = %d, errno = %d)\n", ioctl_cmd,res,errno);
171        return EOALERR_IPC_STA_ERROR_SENDING_WEXT;
172    }
173
174    return OK;
175}
176
177S32 IPC_STA_Wext_Send(THandle hIpcSta, U32 wext_request_id, PVOID p_iwreq_data, U32 len)
178{
179    IpcSta_t* pIpcSta = (IpcSta_t*)hIpcSta;
180    S32 res;
181
182    os_memcpy(&pIpcSta->wext_req.u.data, p_iwreq_data, len);
183
184    res = ioctl(pIpcSta->STA_socket, wext_request_id, &pIpcSta->wext_req);
185    if(res != OK)
186    {
187        os_error_printf(CU_MSG_ERROR, (PS8)"ERROR - IPC_STA_Wext_Send - error sending Wext IOCTL to STA driver (wext_request_id = 0x%x, res = %d, errno = %d)\n",wext_request_id,res,errno);
188        return EOALERR_IPC_STA_ERROR_SENDING_WEXT;
189    }
190
191    os_memcpy(p_iwreq_data, &pIpcSta->wext_req.u.data, len);
192
193    return OK;
194}
195
196