K2.6 patches and update.
[tomato.git] / release / src-rt / wl / exe / wlu_server_linux.c
blob6bd3823a05ec16ec7f2620bb50e58681ec73309c
1 /*
2 * Wl server for linux
4 * Copyright (C) 2010, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
8 * the contents of this file may not be disclosed to third parties, copied
9 * or duplicated in any form, in whole or in part, without the prior
10 * written permission of Broadcom Corporation.
12 * $Id: wlu_server_linux.c,v 1.6 2010-02-03 13:09:13 Exp $
15 /* Revision History:Linux port of Remote wl server
17 * Date Author Description
19 * 27-Dec-2007 Suganthi Version 0.1
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <ctype.h>
26 #include <malloc.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <netdb.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36 #include <sys/wait.h>
37 #include <signal.h>
39 #include <sys/ioctl.h>
40 #include <net/if.h>
41 #ifndef TARGETENV_android
42 typedef u_int64_t u64;
43 typedef u_int32_t u32;
44 typedef u_int16_t u16;
45 typedef u_int8_t u8;
46 typedef u_int64_t __u64;
47 typedef u_int32_t __u32;
48 typedef u_int16_t __u16;
49 typedef u_int8_t __u8;
50 #endif
52 #include <linux/sockios.h>
53 #include <linux/ethtool.h>
55 #include <typedefs.h>
56 #include <wlioctl.h>
57 #include <dhdioctl.h>
58 #include <proto/ethernet.h>
59 #include <bcmendian.h>
60 #include <bcmutils.h>
61 #include <bcmcdc.h>
62 #include <proto/802.11.h>
63 #include "wlu_remote.h"
66 #define DEV_TYPE_LEN 3 /* length for devtype 'wl'/'et' */
67 #define IOCTL_ERROR -2
68 #define BUF_LENGTH 1000
70 #define dtoh32(i) i
73 #ifdef IL_BIGENDIAN
74 bool swap = FALSE;
75 #endif
76 const char *rwl_server_name;
77 void *g_wl_handle;
78 unsigned short defined_debug = DEBUG_ERR | DEBUG_INFO;
79 extern int remote_server_exec(int argc, char **argv, void *ifr);
81 /* Global to have the PID of the current sync command
82 * This is required in case the sync command fails to respond,
83 * the alarm handler shall kill the PID upon a timeout
85 int g_shellsync_pid;
86 unsigned char g_return_stat = 0;
88 static void
89 syserr(char *s)
91 fprintf(stderr, "%s: ", rwl_server_name);
92 perror(s);
93 exit(errno);
95 /* The handler for DHD commands */
96 int
97 dhd_ioctl(void *dhd, int cmd, void *buf, int len, bool set)
99 struct ifreq *ifr = (struct ifreq *) dhd;
100 dhd_ioctl_t ioc;
101 int ret = 0;
102 int s;
104 /* open socket to kernel */
105 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
106 syserr("socket");
108 /* do it */
109 ioc.cmd = cmd;
110 ioc.buf = buf;
111 ioc.len = len;
112 ioc.set = set;
113 ioc.driver = DHD_IOCTL_MAGIC;
114 ifr->ifr_data = (caddr_t) &ioc;
115 if ((ret = ioctl(s, SIOCDEVPRIVATE, ifr)) < 0) {
116 if (cmd != DHD_GET_MAGIC) {
117 ret = IOCTL_ERROR;
120 /* cleanup */
121 close(s);
122 return ret;
126 wl_ioctl(void *wl, int cmd, void *buf, int len, bool set)
128 struct ifreq *ifr = (struct ifreq *) wl;
129 wl_ioctl_t ioc;
130 int ret = 0;
131 int s;
133 /* open socket to kernel */
134 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
135 syserr("socket");
137 /* do it */
138 ioc.cmd = cmd;
139 ioc.buf = buf;
140 ioc.len = len;
141 ioc.set = set;
142 ifr->ifr_data = (caddr_t) &ioc;
143 if ((ret = ioctl(s, SIOCDEVPRIVATE, ifr)) < 0) {
144 if (cmd != WLC_GET_MAGIC) {
145 ret = IOCTL_ERROR;
148 /* cleanup */
149 close(s);
150 return ret;
153 /* Functions copied from wlu.c to check for the driver adapter in the server machine */
155 wl_check(void *wl)
157 int ret;
158 int val;
160 if ((ret = wl_ioctl(wl, WLC_GET_MAGIC, &val, sizeof(int), FALSE) < 0))
161 return ret;
162 #ifdef IL_BIGENDIAN
163 /* Detect if IOCTL swapping is necessary */
164 if (val == (int)bcmswap32(WLC_IOCTL_MAGIC))
166 val = bcmswap32(val);
167 swap = TRUE;
169 #endif
170 if (val != WLC_IOCTL_MAGIC)
171 return -1;
172 if ((ret = wl_ioctl(wl, WLC_GET_VERSION, &val, sizeof(int), FALSE) < 0))
173 return ret;
174 val = dtoh32(val);
176 if (val > WLC_IOCTL_VERSION) {
177 fprintf(stderr, "Version mismatch, please upgrade\n");
178 return -1;
180 return 0;
183 static int
184 wl_get_dev_type(char *name, void *buf, int len)
186 int s;
187 int ret;
188 struct ifreq ifr;
189 struct ethtool_drvinfo info;
191 /* open socket to kernel */
192 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
193 syserr("socket");
195 /* get device type */
196 memset(&info, 0, sizeof(info));
197 info.cmd = ETHTOOL_GDRVINFO;
198 ifr.ifr_data = (caddr_t)&info;
199 strncpy(ifr.ifr_name, name, IFNAMSIZ);
200 if ((ret = ioctl(s, SIOCETHTOOL, &ifr)) < 0) {
201 /* print a good diagnostic if not superuser */
202 if (errno == EPERM)
203 syserr("wl_get_dev_type");
204 *(char *)buf = '\0';
205 } else {
206 strncpy(buf, info.driver, len);
208 close(s);
209 return ret;
212 static void
213 wl_find_adapter(struct ifreq *ifr)
215 char proc_net_dev[] = "/proc/net/dev";
216 FILE *fp;
217 char buf[BUF_LENGTH], *c, *name;
218 char dev_type[DEV_TYPE_LEN];
220 ifr->ifr_name[0] = '\0';
222 if (!(fp = fopen(proc_net_dev, "r")))
223 return;
225 /* eat first two lines */
226 if (!fgets(buf, sizeof(buf), fp) ||
227 !fgets(buf, sizeof(buf), fp)) {
228 fclose(fp);
229 return;
232 while (fgets(buf, sizeof(buf), fp)) {
233 c = buf;
234 while (isspace(*c))
235 c++;
236 if (!(name = strsep(&c, ":")))
237 continue;
238 strncpy(ifr->ifr_name, name, IFNAMSIZ);
239 if (wl_get_dev_type(name, dev_type, DEV_TYPE_LEN) >= 0 &&
240 !strncmp(dev_type, "wl", 2))
241 if (wl_check((void *) ifr) == 0)
242 break;
243 ifr->ifr_name[0] = '\0';
246 fclose(fp);
250 wl_get(void *wl, int cmd, void *buf, int len)
252 int error;
254 error = wl_ioctl(wl, cmd, buf, len, FALSE);
256 return error;
260 wl_set(void *wl, int cmd, void *buf, int len)
262 int error;
264 error = wl_ioctl(wl, cmd, buf, len, TRUE);
266 return error;
269 extern int set_ctrlc;
270 void handle_ctrlc(int unused)
272 UNUSED_PARAMETER(unused);
273 set_ctrlc = 1;
274 return;
277 volatile sig_atomic_t g_sig_chld = 1;
278 void rwl_chld_handler(int num)
280 int child_status;
282 UNUSED_PARAMETER(num);
283 /* g_return_stat is being set with the return status of sh commands */
284 waitpid(g_shellsync_pid, &child_status, WNOHANG);
285 if (WIFEXITED(child_status))
286 g_return_stat = WEXITSTATUS(child_status);
287 else if (g_rem_ptr->msg.flags == (unsigned)CTRLC_FLAG)
288 g_return_stat = 0;
289 else
290 g_return_stat = 1;
291 g_sig_chld = 0;
294 /* Alarm handler called after SHELL_TIMEOUT value
295 * This handler kills the non-responsive shell process
296 * with the PID value g_shellsync_pid
298 static void
299 sigalrm_handler(int s)
301 UNUSED_PARAMETER(s);
303 if (g_shellsync_pid) {
304 kill(g_shellsync_pid, SIGINT);
306 #ifdef RWL_SOCKET
307 g_sig_chld = 0;
308 #endif
311 static void
312 def_handler(int s)
314 UNUSED_PARAMETER(s);
315 kill(g_shellsync_pid, SIGKILL);
316 exit(0);
319 static void
320 pipe_handler(int s)
322 UNUSED_PARAMETER(s);
323 kill(g_shellsync_pid, SIGKILL);
327 main(int argc, char **argv)
329 int err = 0;
330 struct ifreq *ifr;
332 rwl_server_name = argv[0];
334 if ((ifr = malloc(sizeof(struct ifreq))) == NULL)
336 DPRINT_ERR(ERR, "wl_server: Unable to allocate memory for handle\n");
337 exit(1);
339 memset(ifr, 0, sizeof(ifr));
341 /* use default interface */
342 if (!ifr->ifr_name[0])
343 wl_find_adapter(ifr);
344 /* validate the interface */
345 if (!ifr->ifr_name[0] || wl_check((void *)ifr)) {
346 DPRINT_INFO(OUTPUT, "wl_server: wl driver adapter not found\n");
348 g_wl_handle = ifr;
350 /* Register signal handlers */
351 signal(SIGCHLD, rwl_chld_handler);
352 signal(SIGALRM, sigalrm_handler);
353 signal(SIGTERM, def_handler);
354 signal(SIGPIPE, pipe_handler);
355 signal(SIGABRT, def_handler);
356 #ifdef RWL_DONGLE
357 signal(SIGINT, handle_ctrlc);
358 #endif
359 /* Main server process for all transport types */
360 err = remote_server_exec(argc, argv, ifr);
362 return err;
366 * Funtion to store old interface.
368 void
369 store_old_interface(void *wl, char *old_intf_name)
371 strcpy(old_intf_name, ((struct ifreq *)wl)->ifr_name);
375 * Function to set interface.
378 set_interface(void *wl, char *intf_name)
380 struct ifreq *ifr = (struct ifreq *)wl;
382 if (strlen(intf_name) != 0) {
383 strncpy(ifr->ifr_name, intf_name, strlen(intf_name) + 1);
384 return BCME_OK;
386 else {
387 DPRINT_DBG(OUTPUT, "Default Interface will be used ... \n");
388 return BCME_ERROR;