CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
orangepi-xunlong

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.

GitHub Repository: orangepi-xunlong/orangepi-build
Path: blob/next/external/cache/sources/wl/dhd/dhdu_linux.c
Views: 3960
1
/*
2
* Linux port of dhd command line utility, hacked from wl utility.
3
*
4
* $Copyright Open Broadcom Corporation$
5
*
6
* $Id: dhdu_linux.c 281524 2011-09-02 17:09:25Z $
7
*/
8
9
#include <stdio.h>
10
#include <stdlib.h>
11
#include <unistd.h>
12
#include <ctype.h>
13
#include <string.h>
14
#include <errno.h>
15
#include <sys/types.h>
16
#include <sys/wait.h>
17
#include <sys/socket.h>
18
#include <proto/ethernet.h>
19
#include <proto/bcmip.h>
20
#include <arpa/inet.h>
21
#include <sys/ioctl.h>
22
#include <net/if.h>
23
#include <fcntl.h>
24
#include <sys/ioctl.h>
25
#include <unistd.h>
26
27
#ifndef TARGETENV_android
28
#include <error.h>
29
typedef u_int64_t u64;
30
typedef u_int32_t u32;
31
typedef u_int16_t u16;
32
typedef u_int8_t u8;
33
#endif /* TARGETENV_android */
34
#include <linux/sockios.h>
35
#include <linux/types.h>
36
#include <linux/ethtool.h>
37
38
#include <typedefs.h>
39
#include <signal.h>
40
#include <dhdioctl.h>
41
#include <wlioctl.h>
42
#include <bcmcdc.h>
43
#include <bcmutils.h>
44
#include "dhdu.h"
45
#include "wlu_remote.h"
46
#include "wlu_client_shared.h"
47
#include "wlu_pipe.h"
48
#include <netdb.h>
49
#include <netinet/in.h>
50
#include <dhdioctl.h>
51
#include "dhdu_common.h"
52
53
char *av0;
54
static int rwl_os_type = LINUX_OS;
55
/* Search the dhd_cmds table for a matching command name.
56
* Return the matching command or NULL if no match found.
57
*/
58
static cmd_t *
59
dhd_find_cmd(char* name)
60
{
61
cmd_t *cmd = NULL;
62
/* search the dhd_cmds for a matching name */
63
for (cmd = dhd_cmds; cmd->name && strcmp(cmd->name, name); cmd++);
64
if (cmd->name == NULL)
65
cmd = NULL;
66
return cmd;
67
}
68
69
static void
70
syserr(char *s)
71
{
72
fprintf(stderr, "%s: ", dhdu_av0);
73
perror(s);
74
exit(errno);
75
}
76
77
/* This function is called by ioctl_setinformation_fe or ioctl_queryinformation_fe
78
* for executing remote commands or local commands
79
*/
80
static int
81
dhd_ioctl(void *dhd, int cmd, void *buf, int len, bool set)
82
{
83
struct ifreq *ifr = (struct ifreq *)dhd;
84
dhd_ioctl_t ioc;
85
int ret = 0;
86
int s;
87
/* By default try to execute wl commands */
88
int driver_magic = WLC_IOCTL_MAGIC;
89
int get_magic = WLC_GET_MAGIC;
90
91
/* For local dhd commands execute dhd. For wifi transport we still
92
* execute wl commands.
93
*/
94
if (remote_type == NO_REMOTE && strncmp (buf, RWL_WIFI_ACTION_CMD,
95
strlen(RWL_WIFI_ACTION_CMD)) && strncmp(buf, RWL_WIFI_GET_ACTION_CMD,
96
strlen(RWL_WIFI_GET_ACTION_CMD))) {
97
driver_magic = DHD_IOCTL_MAGIC;
98
get_magic = DHD_GET_MAGIC;
99
}
100
101
/* open socket to kernel */
102
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
103
syserr("socket");
104
105
/* do it */
106
ioc.cmd = cmd;
107
ioc.buf = buf;
108
ioc.len = len;
109
ioc.set = set;
110
ioc.driver = driver_magic;
111
ifr->ifr_data = (caddr_t) &ioc;
112
113
if ((ret = ioctl(s, SIOCDEVPRIVATE, ifr)) < 0) {
114
if (cmd != get_magic) {
115
ret = IOCTL_ERROR;
116
}
117
}
118
119
/* cleanup */
120
close(s);
121
return ret;
122
}
123
124
/* This function is called in wlu_pipe.c remote_wifi_ser_init() to execute
125
* the initial set of wl commands for wifi transport (e.g slow_timer, fast_timer etc)
126
*/
127
int wl_ioctl(void *wl, int cmd, void *buf, int len, bool set)
128
{
129
return dhd_ioctl(wl, cmd, buf, len, set); /* Call actual wl_ioctl here: Shubhro */
130
}
131
132
/* Search if dhd adapter or wl adapter is present
133
* This is called by dhd_find to check if it supports wl or dhd
134
* The reason for checking wl adapter is that we can still send remote dhd commands over
135
* wifi transport.
136
*/
137
static int
138
dhd_get_dev_type(char *name, void *buf, char *type)
139
{
140
int s;
141
int ret;
142
struct ifreq ifr;
143
struct ethtool_drvinfo info;
144
145
/* open socket to kernel */
146
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
147
syserr("socket");
148
149
/* get device type */
150
memset(&info, 0, sizeof(info));
151
info.cmd = ETHTOOL_GDRVINFO;
152
strcpy(info.driver, "?");
153
strcat(info.driver, type);
154
ifr.ifr_data = (caddr_t)&info;
155
strncpy(ifr.ifr_name, name, IFNAMSIZ);
156
if ((ret = ioctl(s, SIOCETHTOOL, &ifr)) < 0) {
157
158
/* print a good diagnostic if not superuser */
159
if (errno == EPERM)
160
syserr("dhd_get_dev_type");
161
162
*(char *)buf = '\0';
163
}
164
else
165
strcpy(buf, info.driver);
166
167
close(s);
168
return ret;
169
}
170
171
/* dhd_get/dhd_set is called by several functions in dhdu.c. This used to call dhd_ioctl
172
* directly. However now we need to execute the dhd commands remotely.
173
* So we make use of wl pipes to execute this.
174
* wl_get or wl_set functions also check if it is a local command hence they in turn
175
* call dhd_ioctl if required. Name wl_get/wl_set is retained because these functions are
176
* also called by wlu_pipe.c wlu_client_shared.c
177
*/
178
int
179
dhd_get(void *dhd, int cmd, void *buf, int len)
180
{
181
return wl_get(dhd, cmd, buf, len);
182
}
183
184
/*
185
* To use /dev/node interface:
186
* 1. mknod /dev/hnd0 c 248 0
187
* 2. chmod 777 /dev/hnd0
188
*/
189
#define NODE "/dev/hnd0"
190
191
int
192
dhd_set(void *dhd, int cmd, void *buf, int len)
193
{
194
static int dnode = -1;
195
196
switch (cmd) {
197
case DHD_DLDN_ST:
198
if (dnode == -1)
199
dnode = open(NODE, O_RDWR);
200
else
201
fprintf(stderr, "devnode already opened!\n");
202
203
return dnode;
204
break;
205
case DHD_DLDN_WRITE:
206
if (dnode > 0)
207
return write(dnode, buf, len);
208
break;
209
case DHD_DLDN_END:
210
if (dnode > 0)
211
return close(dnode);
212
break;
213
default:
214
return wl_set(dhd, cmd, buf, len);
215
216
}
217
218
return -1;
219
}
220
221
/* Verify the wl adapter found.
222
* This is called by dhd_find to check if it supports wl
223
* The reason for checking wl adapter is that we can still send remote dhd commands over
224
* wifi transport. The function is copied from wlu.c.
225
*/
226
int
227
wl_check(void *wl)
228
{
229
int ret;
230
int val = 0;
231
232
if (!dhd_check (wl))
233
return 0;
234
235
/*
236
* If dhd_check() fails then go for a regular wl driver verification
237
*/
238
if ((ret = wl_get(wl, WLC_GET_MAGIC, &val, sizeof(int))) < 0)
239
return ret;
240
if (val != WLC_IOCTL_MAGIC)
241
return BCME_ERROR;
242
if ((ret = wl_get(wl, WLC_GET_VERSION, &val, sizeof(int))) < 0)
243
return ret;
244
if (val > WLC_IOCTL_VERSION) {
245
fprintf(stderr, "Version mismatch, please upgrade\n");
246
return BCME_ERROR;
247
}
248
return 0;
249
}
250
/* Search and verify the request type of adapter (wl or dhd)
251
* This is called by main before executing local dhd commands
252
* or sending remote dhd commands over wifi transport
253
*/
254
void
255
dhd_find(struct ifreq *ifr, char *type)
256
{
257
char proc_net_dev[] = "/proc/net/dev";
258
FILE *fp;
259
static char buf[400];
260
char *c, *name;
261
char dev_type[32];
262
263
ifr->ifr_name[0] = '\0';
264
/* eat first two lines */
265
if (!(fp = fopen(proc_net_dev, "r")) ||
266
!fgets(buf, sizeof(buf), fp) ||
267
!fgets(buf, sizeof(buf), fp))
268
return;
269
270
while (fgets(buf, sizeof(buf), fp)) {
271
c = buf;
272
while (isspace(*c))
273
c++;
274
if (!(name = strsep(&c, ":")))
275
continue;
276
strncpy(ifr->ifr_name, name, IFNAMSIZ);
277
if (dhd_get_dev_type(name, dev_type, type) >= 0 &&
278
!strncmp(dev_type, type, strlen(dev_type) - 1))
279
{
280
if (!wl_check((void*)ifr))
281
break;
282
}
283
ifr->ifr_name[0] = '\0';
284
}
285
286
fclose(fp);
287
}
288
/* This function is called by wl_get to execute either local dhd command
289
* or send a dhd command over wl transport
290
*/
291
static int
292
ioctl_queryinformation_fe(void *wl, int cmd, void* input_buf, int *input_len)
293
{
294
if (remote_type == NO_REMOTE) {
295
return dhd_ioctl(wl, cmd, input_buf, *input_len, FALSE);
296
} else {
297
return rwl_queryinformation_fe(wl, cmd, input_buf,
298
(unsigned long*)input_len, 0, RDHD_GET_IOCTL);
299
}
300
}
301
302
/* This function is called by wl_set to execute either local dhd command
303
* or send a dhd command over wl transport
304
*/
305
static int
306
ioctl_setinformation_fe(void *wl, int cmd, void* buf, int *len)
307
{
308
if (remote_type == NO_REMOTE) {
309
return dhd_ioctl(wl, cmd, buf, *len, TRUE);
310
} else {
311
return rwl_setinformation_fe(wl, cmd, buf, (unsigned long*)len, 0, RDHD_SET_IOCTL);
312
313
}
314
}
315
316
/* The function is replica of wl_get in wlu_linux.c. Optimize when we have some
317
* common code between wlu_linux.c and dhdu_linux.c
318
*/
319
int
320
wl_get(void *wl, int cmd, void *buf, int len)
321
{
322
int error = BCME_OK;
323
/* For RWL: When interfacing to a Windows client, need t add in OID_BASE */
324
if ((rwl_os_type == WIN32_OS) && (remote_type != NO_REMOTE)) {
325
error = (int)ioctl_queryinformation_fe(wl, WL_OID_BASE + cmd, buf, &len);
326
} else {
327
error = (int)ioctl_queryinformation_fe(wl, cmd, buf, &len);
328
}
329
if (error == SERIAL_PORT_ERR)
330
return SERIAL_PORT_ERR;
331
332
if (error != 0)
333
return IOCTL_ERROR;
334
335
return error;
336
}
337
338
/* The function is replica of wl_set in wlu_linux.c. Optimize when we have some
339
* common code between wlu_linux.c and dhdu_linux.c
340
*/
341
int
342
wl_set(void *wl, int cmd, void *buf, int len)
343
{
344
int error = BCME_OK;
345
346
/* For RWL: When interfacing to a Windows client, need t add in OID_BASE */
347
if ((rwl_os_type == WIN32_OS) && (remote_type != NO_REMOTE)) {
348
error = (int)ioctl_setinformation_fe(wl, WL_OID_BASE + cmd, buf, &len);
349
} else {
350
error = (int)ioctl_setinformation_fe(wl, cmd, buf, &len);
351
}
352
353
if (error == SERIAL_PORT_ERR)
354
return SERIAL_PORT_ERR;
355
356
if (error != 0) {
357
return IOCTL_ERROR;
358
}
359
return error;
360
}
361
362
int
363
wl_validatedev(void *dev_handle)
364
{
365
int retval = 1;
366
struct ifreq *ifr = (struct ifreq *)dev_handle;
367
/* validate the interface */
368
if (!ifr->ifr_name || wl_check((void *)ifr)) {
369
retval = 0;
370
}
371
return retval;
372
}
373
374
/* Main client function
375
* The code is mostly from wlu_linux.c. This function takes care of executing remote dhd commands
376
* along with the local dhd commands now.
377
*/
378
int
379
#if defined(LIB)
380
dhd_main(int argc, char **argv)
381
#else
382
main(int argc, char **argv)
383
#endif
384
{
385
struct ifreq ifr;
386
char *ifname = NULL;
387
int err = 0;
388
int help = 0;
389
int status = CMD_DHD;
390
void* serialHandle = NULL;
391
392
UNUSED_PARAMETER(argc);
393
394
av0 = argv[0];
395
memset(&ifr, 0, sizeof(ifr));
396
argv++;
397
398
if ((status = dhd_option(&argv, &ifname, &help)) == CMD_OPT) {
399
if (ifname)
400
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
401
}
402
/* Linux client looking for a Win32 server */
403
if (*argv && strncmp (*argv, "--wince", strlen(*argv)) == 0) {
404
rwl_os_type = WIN32_OS;
405
argv++;
406
}
407
408
/* RWL socket transport Usage: --socket ipaddr [port num] */
409
if (*argv && strncmp (*argv, "--socket", strlen(*argv)) == 0) {
410
argv++;
411
412
remote_type = REMOTE_SOCKET;
413
414
if (!(*argv)) {
415
rwl_usage(remote_type);
416
return err;
417
}
418
g_rwl_servIP = *argv;
419
argv++;
420
421
g_rwl_servport = DEFAULT_SERVER_PORT;
422
if ((*argv) && isdigit(**argv)) {
423
g_rwl_servport = atoi(*argv);
424
argv++;
425
}
426
}
427
428
/* RWL from system serial port on client to uart dongle port on server */
429
/* Usage: --dongle /dev/ttyS0 */
430
if (*argv && strncmp (*argv, "--dongle", strlen(*argv)) == 0) {
431
argv++;
432
remote_type = REMOTE_DONGLE;
433
434
if (!(*argv)) {
435
rwl_usage(remote_type);
436
return err;
437
}
438
g_rwl_device_name_serial = *argv;
439
argv++;
440
if ((serialHandle = rwl_open_pipe(remote_type, "\0", 0, 0)) == NULL) {
441
DPRINT_ERR(ERR, "serial device open error\r\n");
442
return BCME_ERROR;
443
}
444
ifr = (*(struct ifreq *)serialHandle);
445
}
446
447
/* RWL over wifi. Usage: --wifi mac_address */
448
if (*argv && strncmp (*argv, "--wifi", strlen(*argv)) == 0) {
449
argv++;
450
remote_type = NO_REMOTE;
451
if (!ifr.ifr_name[0])
452
{
453
dhd_find(&ifr, "wl");
454
}
455
/* validate the interface */
456
if (!ifr.ifr_name[0] || wl_check((void*)&ifr)) {
457
fprintf(stderr, "%s: wl driver adapter not found\n", av0);
458
exit(1);
459
}
460
remote_type = REMOTE_WIFI;
461
462
if (argc < 4) {
463
rwl_usage(remote_type);
464
return err;
465
}
466
/* copy server mac address to local buffer for later use by findserver cmd */
467
if (!dhd_ether_atoe(*argv, (struct ether_addr *)g_rwl_buf_mac)) {
468
fprintf(stderr,
469
"could not parse as an ethernet MAC address\n");
470
return FAIL;
471
}
472
argv++;
473
}
474
475
/* Process for local dhd */
476
if (remote_type == NO_REMOTE) {
477
err = process_args(&ifr, argv);
478
return err;
479
}
480
481
if (*argv) {
482
err = process_args(&ifr, argv);
483
if ((err == SERIAL_PORT_ERR) && (remote_type == REMOTE_DONGLE)) {
484
DPRINT_ERR(ERR, "\n Retry again\n");
485
err = process_args((struct ifreq*)&ifr, argv);
486
}
487
return err;
488
}
489
rwl_usage(remote_type);
490
491
if (remote_type == REMOTE_DONGLE)
492
rwl_close_pipe(remote_type, (void*)&ifr);
493
494
return err;
495
}
496
/*
497
* Function called for 'local' execution and for 'remote' non-interactive session
498
* (shell cmd, wl cmd) .The code is mostly from wlu_linux.c. This code can be
499
* common to wlu_linux.c and dhdu_linux.c
500
*/
501
static int
502
process_args(struct ifreq* ifr, char **argv)
503
{
504
char *ifname = NULL;
505
int help = 0;
506
int status = 0;
507
int err = BCME_OK;
508
cmd_t *cmd = NULL;
509
while (*argv) {
510
if ((strcmp (*argv, "sh") == 0) && (remote_type != NO_REMOTE)) {
511
argv++; /* Get the shell command */
512
if (*argv) {
513
/* Register handler in case of shell command only */
514
signal(SIGINT, ctrlc_handler);
515
err = rwl_shell_cmd_proc((void*)ifr, argv, SHELL_CMD);
516
} else {
517
DPRINT_ERR(ERR,
518
"Enter the shell command (e.g ls(Linux) or dir(Win CE) \n");
519
err = BCME_ERROR;
520
}
521
return err;
522
}
523
524
if ((status = dhd_option(&argv, &ifname, &help)) == CMD_OPT) {
525
if (help)
526
break;
527
if (ifname)
528
strncpy(ifr->ifr_name, ifname, IFNAMSIZ);
529
continue;
530
}
531
/* parse error */
532
else if (status == CMD_ERR)
533
break;
534
535
if (remote_type == NO_REMOTE) {
536
/* use default interface */
537
if (!ifr->ifr_name[0])
538
dhd_find(ifr, "dhd");
539
/* validate the interface */
540
if (!ifr->ifr_name[0] || dhd_check((void *)ifr)) {
541
if (strcmp("dldn", *argv) != 0) {
542
fprintf(stderr, "%s: dhd driver adapter not found\n", av0);
543
exit(BCME_ERROR);
544
}
545
}
546
547
}
548
/* search for command */
549
cmd = dhd_find_cmd(*argv);
550
/* if not found, use default set_var and get_var commands */
551
if (!cmd) {
552
cmd = &dhd_varcmd;
553
}
554
555
/* do command */
556
err = (*cmd->func)((void *) ifr, cmd, argv);
557
break;
558
} /* while loop end */
559
560
/* provide for help on a particular command */
561
if (help && *argv) {
562
cmd = dhd_find_cmd(*argv);
563
if (cmd) {
564
dhd_cmd_usage(cmd);
565
} else {
566
DPRINT_ERR(ERR, "%s: Unrecognized command \"%s\", type -h for help\n",
567
av0, *argv);
568
}
569
} else if (!cmd)
570
dhd_usage(NULL);
571
else if (err == USAGE_ERROR)
572
dhd_cmd_usage(cmd);
573
else if (err == IOCTL_ERROR)
574
dhd_printlasterror((void *) ifr);
575
576
return err;
577
}
578
579
int
580
rwl_shell_createproc(void *wl)
581
{
582
UNUSED_PARAMETER(wl);
583
return fork();
584
}
585
586
void
587
rwl_shell_killproc(int pid)
588
{
589
kill(pid, SIGKILL);
590
}
591
592
#ifdef RWL_SOCKET
593
/* to validate hostname/ip given by the client */
594
int validate_server_address()
595
{
596
struct hostent *he;
597
struct ipv4_addr temp;
598
if (!dhd_atoip(g_rwl_servIP, &temp)) {
599
/* Wrong IP address format check for hostname */
600
if ((he = gethostbyname(g_rwl_servIP)) != NULL) {
601
if (!dhd_atoip(*he->h_addr_list, &temp)) {
602
g_rwl_servIP =
603
inet_ntoa(*(struct in_addr *)*he->h_addr_list);
604
if (g_rwl_servIP == NULL) {
605
DPRINT_ERR(ERR, "Error at inet_ntoa \n");
606
return FAIL;
607
}
608
} else {
609
DPRINT_ERR(ERR, "Error in IP address \n");
610
return FAIL;
611
}
612
} else {
613
DPRINT_ERR(ERR, "Enter correct IP address/hostname format\n");
614
return FAIL;
615
}
616
}
617
return SUCCESS;
618
}
619
#endif /* RWL_SOCKET */
620
621