2 * Linux port of wl command line utility
4 * Copyright (C) 2010, Broadcom Corporation
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_linux.c,v 1.53 2010-02-03 06:58:43 Exp $
20 #ifndef TARGETENV_android
22 #endif /* TARGETENV_android */
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <arpa/inet.h>
26 #include <sys/ioctl.h>
28 #include <proto/ethernet.h>
29 #include <proto/bcmip.h>
31 #ifndef TARGETENV_android
32 typedef u_int64_t u64
;
33 typedef u_int32_t u32
;
34 typedef u_int16_t u16
;
36 typedef u_int64_t __u64
;
37 typedef u_int32_t __u32
;
38 typedef u_int16_t __u16
;
39 typedef u_int8_t __u8
;
40 #endif /* TARGETENV_android */
42 #include <linux/sockios.h>
43 #include <linux/ethtool.h>
50 #include <netinet/in.h>
53 #include "wlu_remote.h"
54 #include "wlu_client_shared.h"
58 #define DEV_TYPE_LEN 3 /* length for devtype 'wl'/'et' */
59 #define INTERACTIVE_NUM_ARGS 15
60 #define INTERACTIVE_MAX_INPUT_LENGTH 256
62 #define RWL_WIFI_JOIN_DELAY 5
64 /* Function prototypes */
65 static cmd_t
*wl_find_cmd(char* name
);
66 static int do_interactive(struct ifreq
*ifr
);
67 static int wl_do_cmd(struct ifreq
*ifr
, char **argv
);
68 int process_args(struct ifreq
* ifr
, char **argv
);
69 extern int g_child_pid
;
70 /* RemoteWL declarations */
71 int remote_type
= NO_REMOTE
;
72 int rwl_os_type
= LINUX_OS
;
73 extern char *g_rwl_buf_mac
;
74 extern char* g_rwl_device_name_serial
;
75 unsigned short g_rwl_servport
;
76 char *g_rwl_servIP
= NULL
;
77 unsigned short defined_debug
= DEBUG_ERR
| DEBUG_INFO
;
78 static uint interactive_flag
= 0;
79 extern char *remote_vista_cmds
[];
80 extern char g_rem_ifname
[IFNAMSIZ
];
84 fprintf(stderr
, "%s: ", wlu_av0
);
90 wl_ioctl(void *wl
, int cmd
, void *buf
, int len
, bool set
)
92 struct ifreq
*ifr
= (struct ifreq
*) wl
;
97 /* open socket to kernel */
98 if ((s
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0)
106 ifr
->ifr_data
= (caddr_t
) &ioc
;
107 if ((ret
= ioctl(s
, SIOCDEVPRIVATE
, ifr
)) < 0) {
108 if (cmd
!= WLC_GET_MAGIC
) {
119 wl_get_dev_type(char *name
, void *buf
, int len
)
124 struct ethtool_drvinfo info
;
126 /* open socket to kernel */
127 if ((s
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0)
130 /* get device type */
131 memset(&info
, 0, sizeof(info
));
132 info
.cmd
= ETHTOOL_GDRVINFO
;
133 ifr
.ifr_data
= (caddr_t
)&info
;
134 strncpy(ifr
.ifr_name
, name
, IFNAMSIZ
);
135 if ((ret
= ioctl(s
, SIOCETHTOOL
, &ifr
)) < 0) {
137 /* print a good diagnostic if not superuser */
139 syserr("wl_get_dev_type");
143 strncpy(buf
, info
.driver
, len
);
151 wl_find(struct ifreq
*ifr
)
153 char proc_net_dev
[] = "/proc/net/dev";
155 char buf
[1000], *c
, *name
;
156 char dev_type
[DEV_TYPE_LEN
];
159 ifr
->ifr_name
[0] = '\0';
161 if (!(fp
= fopen(proc_net_dev
, "r")))
164 /* eat first two lines */
165 if (!fgets(buf
, sizeof(buf
), fp
) ||
166 !fgets(buf
, sizeof(buf
), fp
)) {
171 while (fgets(buf
, sizeof(buf
), fp
)) {
175 if (!(name
= strsep(&c
, ":")))
177 strncpy(ifr
->ifr_name
, name
, IFNAMSIZ
);
178 if (wl_get_dev_type(name
, dev_type
, DEV_TYPE_LEN
) >= 0 &&
179 !strncmp(dev_type
, "wl", 2))
180 if (wl_check((void *) ifr
) == 0)
182 ifr
->ifr_name
[0] = '\0';
184 if (ifr
->ifr_name
[0] == '\0')
195 ioctl_queryinformation_fe(void *wl
, int cmd
, void* input_buf
, int *input_len
)
197 int error
= NO_ERROR
;
199 if (remote_type
== NO_REMOTE
) {
200 error
= wl_ioctl(wl
, cmd
, input_buf
, *input_len
, FALSE
);
202 error
= rwl_queryinformation_fe(wl
, cmd
, input_buf
,
203 (unsigned long*)input_len
, 0, REMOTE_GET_IOCTL
);
210 ioctl_setinformation_fe(void *wl
, int cmd
, void* buf
, int *len
)
214 if (remote_type
== NO_REMOTE
) {
215 error
= wl_ioctl(wl
, cmd
, buf
, *len
, TRUE
);
217 error
= rwl_setinformation_fe(wl
, cmd
, buf
,
218 (unsigned long*)len
, 0, REMOTE_SET_IOCTL
);
225 wl_get(void *wl
, int cmd
, void *buf
, int len
)
228 /* For RWL: When interfacing to a Windows client, need t add in OID_BASE */
229 error
= (int)ioctl_queryinformation_fe(wl
, cmd
, buf
, &len
);
231 if (error
== SERIAL_PORT_ERR
)
232 return SERIAL_PORT_ERR
;
233 else if (error
== BCME_NODEVICE
)
234 return BCME_NODEVICE
;
242 wl_set(void *wl
, int cmd
, void *buf
, int len
)
246 /* For RWL: When interfacing to a Windows client, need t add in OID_BASE */
247 error
= (int)ioctl_setinformation_fe(wl
, cmd
, buf
, &len
);
249 if (error
== SERIAL_PORT_ERR
)
250 return SERIAL_PORT_ERR
;
251 else if (error
== BCME_NODEVICE
)
252 return BCME_NODEVICE
;
260 int wl_os_type_get_rwl()
265 void wl_os_type_set_rwl(int os_type
)
267 rwl_os_type
= os_type
;
270 int wl_ir_init_rwl(void **irh
)
272 switch (rwl_get_remote_type()) {
276 ifr
= malloc(sizeof(struct ifreq
));
278 memset(ifr
, 0, sizeof(ifr
));
291 void wl_close_rwl(int remote_type
, void *irh
)
293 switch (remote_type
) {
303 #define LINUX_NUM_ARGS 16
306 buf_to_args(char *tmp
, char *new_args
[])
313 while ((argc
< (LINUX_NUM_ARGS
- 1)) &&
314 ((token
= strtok(argc
? NULL
: line
, " \t")) != NULL
)) {
315 new_args
[argc
] = malloc(strlen(token
)+1);
316 strncpy(new_args
[argc
], token
, strlen(token
)+1);
319 new_args
[argc
] = NULL
;
324 wl_lib(char *input_str
)
331 void* serialHandle
= NULL
;
332 char *tmp_argv
[LINUX_NUM_ARGS
];
333 char **argv
= tmp_argv
;
336 if ((argc
= buf_to_args(input_str
, argv
)) <= 0) {
337 printf("wl: can't convert input string\n");
341 /* Main client function */
343 main(int argc
, char **argv
)
350 #if defined(RWL_DONGLE) || RWL_SERIAL
351 void* serialHandle
= NULL
;
358 memset(&ifr
, 0, sizeof(ifr
));
361 if ((status
= wl_option(&argv
, &ifname
, &help
)) == CMD_OPT
) {
363 strncpy(ifr
.ifr_name
, ifname
, IFNAMSIZ
);
366 /* Linux client looking for a indongle/Win Vista server */
368 /* Linux client looking for a indongle reflector */
369 if (*argv
&& strncmp (*argv
, "--indongle", strlen(*argv
)) == 0) {
372 /* Linux client looking for a WinVista server */
373 if (*argv
&& strncmp (*argv
, "--vista", strlen(*argv
)) == 0) {
374 rwl_os_type
= WINVISTA_OS
;
378 /* RWL socket transport Usage: --socket ipaddr/hostname [port num] */
379 if (*argv
&& strncmp (*argv
, "--socket", strlen(*argv
)) == 0) {
382 remote_type
= REMOTE_SOCKET
;
385 rwl_usage(remote_type
);
388 /* IP address validation is done in client_shared file */
389 g_rwl_servIP
= *argv
;
392 g_rwl_servport
= DEFAULT_SERVER_PORT
;
393 if ((*argv
) && isdigit(**argv
)) {
394 g_rwl_servport
= atoi(*argv
);
399 /* RWL from system serial port on client to uart serial port on server */
400 /* Usage: --serial /dev/ttyS0 */
401 if (*argv
&& strncmp (*argv
, "--serial", strlen(*argv
)) == 0) {
403 remote_type
= REMOTE_SERIAL
;
406 /* RWL from system serial port on client to uart dongle port on server */
407 /* Usage: --dongle /dev/ttyS0 */
408 if (*argv
&& strncmp (*argv
, "--dongle", strlen(*argv
)) == 0) {
410 remote_type
= REMOTE_DONGLE
;
413 #if defined(RWL_SERIAL) || defined(RWL_DONGLE)
414 if (remote_type
== REMOTE_SERIAL
|| remote_type
== REMOTE_DONGLE
) {
416 rwl_usage(remote_type
);
419 g_rwl_device_name_serial
= *argv
;
421 if ((serialHandle
= rwl_open_pipe(remote_type
, g_rwl_device_name_serial
, 0, 0))
423 DPRINT_ERR(ERR
, "serial device open error\r\n");
426 ifr
= (*(struct ifreq
*)serialHandle
);
428 #endif /* RWL_SERIAL */
430 /* RWL over wifi. Usage: --wifi mac_address */
431 if (*argv
&& strncmp (*argv
, "--wifi", strlen(*argv
)) == 0) {
433 /* use default interface */
436 /* validate the interface */
437 if (!*ifr
.ifr_name
|| wl_check((void*)&ifr
)) {
438 fprintf(stderr
, "%s: wl driver adapter not found\n", wlu_av0
);
441 remote_type
= REMOTE_WIFI
;
444 rwl_usage(remote_type
);
447 /* copy server mac address to local buffer for later use by findserver cmd */
448 if (!wl_ether_atoe(*argv
, (struct ether_addr
*)g_rwl_buf_mac
)) {
450 "could not parse as an ethternet MAC address\n");
456 if ((*argv
) && (strlen(*argv
) > 2) &&
457 (strncmp(*argv
, "--interactive", strlen(*argv
)) == 0)) {
458 interactive_flag
= 1;
461 /* Process for local wl */
462 if (remote_type
== NO_REMOTE
) {
463 if (interactive_flag
== 1)
465 err
= process_args(&ifr
, argv
);
469 if (interactive_flag
== 1) {
470 err
= do_interactive(&ifr
);
474 if ((*argv
) && (interactive_flag
== 0)) {
475 err
= process_args(&ifr
, argv
);
476 if ((err
== SERIAL_PORT_ERR
) && (remote_type
== REMOTE_DONGLE
)) {
477 DPRINT_ERR(ERR
, "\n Retry again\n");
478 err
= process_args((struct ifreq
*)&ifr
, argv
);
482 rwl_usage(remote_type
);
483 #if defined(RWL_DONGLE) || RWL_SERIAL
484 if (remote_type
== REMOTE_DONGLE
|| remote_type
== REMOTE_SERIAL
)
485 rwl_close_pipe(remote_type
, (void*)&ifr
);
486 #endif /* RWL_DONGLE || RWL_SERIAL */
491 * Function called for 'local' execution and for 'remote' non-interactive session
492 * (shell cmd, wl cmd)
495 process_args(struct ifreq
* ifr
, char **argv
)
508 if ((strcmp (*argv
, "sh") == 0) && (remote_type
!= NO_REMOTE
)) {
509 (void)*argv
++; /* Get the shell command */
511 /* Register handler in case of shell command only */
512 err
= rwl_shell_cmd_proc((void*)ifr
, argv
, SHELL_CMD
);
514 DPRINT_ERR(ERR
, "Enter the shell "
515 "command, e.g. ls(Linux) or dir(Win CE)\n");
522 if ((strcmp (*argv
, "asd") == 0) && (remote_type
!= NO_REMOTE
)) {
523 (void)*argv
++; /* Get the asd command */
525 err
= rwl_shell_cmd_proc((void*)ifr
, argv
, ASD_CMD
);
527 DPRINT_ERR(ERR
, "Enter the ASD command, e.g. ca_get_version\n");
533 if (rwl_os_type
== WINVISTA_OS
) {
534 for (vista_cmd_index
= 0; remote_vista_cmds
[vista_cmd_index
] &&
535 strcmp(remote_vista_cmds
[vista_cmd_index
], *argv
);
537 if (remote_vista_cmds
[vista_cmd_index
] != NULL
) {
538 err
= rwl_shell_cmd_proc((void *)ifr
, argv
, VISTA_CMD
);
539 if ((remote_type
== REMOTE_WIFI
) && ((!strcmp(*argv
, "join")))) {
542 "\nChannel will be synchronized by Findserver\n\n");
543 sleep(RWL_WIFI_JOIN_DELAY
);
544 for (retry
= 0; retry
< RWL_WIFI_RETRY
; retry
++) {
545 if ((rwl_find_remote_wifi_server(ifr
,
546 &g_rwl_buf_mac
[0]) == 0)) {
550 #endif /* RWL_WIFI */
556 if ((status
= wl_option(&argv
, &ifname
, &help
)) == CMD_OPT
) {
560 if (remote_type
== NO_REMOTE
) {
561 strncpy((*ifr
).ifr_name
, ifname
, IFNAMSIZ
);
564 strncpy(g_rem_ifname
, ifname
, IFNAMSIZ
);
570 else if (status
== CMD_ERR
)
573 if (remote_type
== NO_REMOTE
) {
574 /* use default interface */
575 if (!*(*ifr
).ifr_name
)
577 /* validate the interface */
578 if (!*(*ifr
).ifr_name
|| wl_check((void *)ifr
)) {
579 fprintf(stderr
, "%s: wl driver adapter not found\n", wlu_av0
);
583 if ((strcmp (*argv
, "--interactive") == 0) || (interactive_flag
== 1)) {
584 err
= do_interactive(ifr
);
588 /* search for command */
589 cmd
= wl_find_cmd(*argv
);
590 /* if not found, use default set_var and get_var commands */
595 if (!strcmp(cmd
->name
, "findserver")) {
596 remote_wifi_ser_init_cmds((void *) ifr
);
598 #endif /* RWL_WIFI */
600 /* RWL over Wifi supports 'lchannel' command which lets client
601 * (ie *this* machine) change channels since normal 'channel' command
602 * applies to the server (ie target machine)
604 if (remote_type
== REMOTE_WIFI
) {
606 if (!strcmp(argv
[0], "lchannel")) {
607 strcpy(argv
[0], "channel");
608 rwl_wifi_swap_remote_type(remote_type
);
609 err
= (*cmd
->func
)((void *) ifr
, cmd
, argv
);
610 rwl_wifi_swap_remote_type(remote_type
);
612 err
= (*cmd
->func
)((void *) ifr
, cmd
, argv
);
614 /* After join cmd's gets exeuted on the server side , client needs to know
615 * the channel on which the server is associated with AP , after delay of
616 * few seconds client will intiate the scan on diffrent channels by calling
617 * rwl_find_remote_wifi_server fucntion
619 if ((!strcmp(cmd
->name
, "join") || ((!strcmp(cmd
->name
, "ssid") &&
620 (*(++argv
) != NULL
))))) {
621 DPRINT_INFO(OUTPUT
, "\n Findserver is called to synchronize the"
623 sleep(RWL_WIFI_JOIN_DELAY
);
624 for (retry
= 0; retry
< RWL_WIFI_RETRY
; retry
++) {
625 if ((rwl_find_remote_wifi_server(ifr
,
626 &g_rwl_buf_mac
[0]) == 0)) {
631 #endif /* RWL_WIFI */
634 err
= (*cmd
->func
)((void *) ifr
, cmd
, argv
);
637 } /* while loop end */
639 /* provide for help on a particular command */
641 cmd
= wl_find_cmd(*argv
);
643 wl_cmd_usage(stdout
, cmd
);
645 DPRINT_ERR(ERR
, "%s: Unrecognized command \"%s\", type -h for help\n",
649 wl_usage(stdout
, NULL
);
650 else if (err
== USAGE_ERROR
)
651 wl_cmd_usage(stderr
, cmd
);
652 else if (err
== IOCTL_ERROR
)
653 wl_printlasterror((void *) ifr
);
654 else if (err
== BCME_NODEVICE
)
655 DPRINT_ERR(ERR
, "%s : wl driver adapter not found\n", g_rem_ifname
);
660 /* Function called for 'local' interactive session and for 'remote' interactive session */
662 do_interactive(struct ifreq
*ifr
)
672 char line
[INTERACTIVE_MAX_INPUT_LENGTH
];
673 fprintf(stdout
, "> ");
674 fgsret
= fgets(line
, sizeof(line
), stdin
);
682 if (strlen (line
) > 0) {
683 /* skip past first arg if it's "wl" and parse up arguments */
684 char *argv
[INTERACTIVE_NUM_ARGS
];
689 while ((argc
< (INTERACTIVE_NUM_ARGS
- 1)) &&
690 ((token
= strtok(argc
? NULL
: line
, " \t\n")) != NULL
)) {
692 /* Specifically make sure empty arguments (like SSID) are empty */
693 if (token
[0] == '"' && token
[1] == '"') {
697 argv
[argc
++] = token
;
701 if (!strcmp(argv
[0], "findserver")) {
702 remote_wifi_ser_init_cmds((void *) ifr
);
704 #endif /* RWL_WIFI */
706 if (strcmp(argv
[0], "q") == 0 || strcmp(argv
[0], "exit") == 0) {
710 if ((strcmp(argv
[0], "sh") == 0) && (remote_type
!= NO_REMOTE
)) {
712 process_args(ifr
, argv
);
714 DPRINT_ERR(ERR
, "Give shell command");
717 } else { /* end shell */
718 /* check for lchannel support,applicable only for wifi transport.
719 * when lchannel is called remote type is swapped by calling swap_
720 * remote_type.This is done to change, the remote type to local,
721 * so that local machine's channel can be executed and
722 * returned to the user.
723 * To get back the original remote type, swap is recalled.
725 if (remote_type
== REMOTE_WIFI
) {
727 if (!strcmp(argv
[0], "lchannel")) {
728 strcpy(argv
[0], "channel");
729 rwl_wifi_swap_remote_type(remote_type
);
730 err
= wl_do_cmd(ifr
, argv
);
731 rwl_wifi_swap_remote_type(remote_type
);
733 err
= wl_do_cmd(ifr
, argv
);
735 /* After join cmd's gets exeuted on the server side, client
736 * needs to know the channel on which the server is associated
737 * with AP , after delay of few seconds client will intiate the
738 * scan on diffrent channels by calling
739 * rwl_find_remote_wifi_server function
741 if ((!strcmp(argv
[0], "join")) ||
742 (!strcmp(argv
[0], "ssid"))) {
743 DPRINT_INFO(OUTPUT
, "\n Findserver is called"
744 "after the join issued to remote \n \n");
745 sleep(RWL_WIFI_JOIN_DELAY
);
746 for (retry
= 0; retry
< RWL_WIFI_RETRY
; retry
++) {
747 if ((rwl_find_remote_wifi_server(ifr
,
748 &g_rwl_buf_mac
[0]) == 0)) {
753 #endif /* RWL_WIFI */
755 err
= wl_do_cmd(ifr
, argv
);
758 } /* end of strlen (line) > 0 */
765 * find command in argv and execute it
766 * Won't handle changing ifname yet, expects that to happen with the --interactive
767 * Return an error if unable to find/execute command
770 wl_do_cmd(struct ifreq
*ifr
, char **argv
)
778 /* skip over 'wl' if it's there */
779 if (*argv
&& strcmp (*argv
, "wl") == 0) {
783 /* handle help or interface name changes */
784 if (*argv
&& (status
= wl_option (&argv
, &ifname
, &help
)) == CMD_OPT
) {
787 "Interface name change not allowed within --interactive\n");
791 /* in case wl_option eats all the args */
796 if (status
!= CMD_ERR
) {
797 /* search for command */
798 cmd
= wl_find_cmd(*argv
);
800 /* defaults to using the set_var and get_var commands */
805 err
= (*cmd
->func
)((void *)ifr
, cmd
, argv
);
807 /* provide for help on a particular command */
809 cmd
= wl_find_cmd(*argv
);
811 wl_cmd_usage(stdout
, cmd
);
813 DPRINT_ERR(ERR
, "%s: Unrecognized command \"%s\", type -h for help\n",
817 wl_usage(stdout
, NULL
);
818 else if (err
== USAGE_ERROR
)
819 wl_cmd_usage(stderr
, cmd
);
820 else if (err
== IOCTL_ERROR
)
821 wl_printlasterror((void *)ifr
);
822 else if (err
== BCME_NODEVICE
)
823 DPRINT_ERR(ERR
, "%s : wl driver adapter not found\n", g_rem_ifname
);
828 /* Search the wl_cmds table for a matching command name.
829 * Return the matching command or NULL if no match found.
832 wl_find_cmd(char* name
)
836 /* search the wl_cmds for a matching name */
837 for (cmd
= wl_cmds
; cmd
->name
&& strcmp(cmd
->name
, name
); cmd
++);
839 if (cmd
->name
== NULL
)
845 void def_handler(int signum
)
847 UNUSED_PARAMETER(signum
);
848 kill(g_child_pid
, SIGINT
);
849 kill(getpid(), SIGINT
);
852 /* Create a child that waits for Ctrl-C at the client side
854 int rwl_shell_createproc(void *wl
)
856 UNUSED_PARAMETER(wl
);
857 signal(SIGINT
, ctrlc_handler
);
858 signal(SIGTERM
, def_handler
);
859 signal(SIGABRT
, def_handler
);
863 /* In case if the server shell command exits normally
864 * then kill the thread that was waiting for Ctr-C to happen
867 void rwl_shell_killproc(int pid
)
870 signal(SIGINT
, SIG_DFL
);
874 /* to validate hostname/ip given by the client */
875 int validate_server_address()
878 struct ipv4_addr temp
;
879 if (!wl_atoip(g_rwl_servIP
, &temp
)) {
880 /* Wrong IP address format check for hostname */
881 if ((he
= gethostbyname(g_rwl_servIP
)) != NULL
) {
882 if (!wl_atoip(*he
->h_addr_list
, &temp
)) {
884 inet_ntoa(*(struct in_addr
*)*he
->h_addr_list
);
885 if (g_rwl_servIP
== NULL
) {
886 DPRINT_ERR(ERR
, "Error at inet_ntoa \n");
890 DPRINT_ERR(ERR
, "Error in IP address \n");
894 DPRINT_ERR(ERR
, "Enter correct IP address/hostname format\n");
900 #endif /* RWL_SOCKET */