| /* |
| * Linux port of wl command line utility |
| * |
| * Copyright (C) 2016, Broadcom Corporation |
| * All Rights Reserved. |
| * |
| * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; |
| * the contents of this file may not be disclosed to third parties, copied |
| * or duplicated in any form, in whole or in part, without the prior |
| * written permission of Broadcom Corporation. |
| * |
| * $Id: wlu_linux.c 454792 2014-02-11 20:40:19Z $ |
| */ |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <ctype.h> |
| #include <string.h> |
| #include <errno.h> |
| #ifndef TARGETENV_android |
| #include <error.h> |
| #endif /* TARGETENV_android */ |
| #include <sys/types.h> |
| #include <sys/socket.h> |
| #include <arpa/inet.h> |
| #include <sys/ioctl.h> |
| #include <net/if.h> |
| #include <proto/ethernet.h> |
| #include <proto/bcmip.h> |
| |
| #ifndef TARGETENV_android |
| #include <linux/types.h> |
| #endif /* TARGETENV_android */ |
| |
| #include <linux/sockios.h> |
| #include <linux/ethtool.h> |
| #include <signal.h> |
| #include <typedefs.h> |
| #include <wlioctl.h> |
| #include <bcmutils.h> |
| #include <sys/wait.h> |
| #include <netdb.h> |
| #include <netinet/in.h> |
| #include "wlu.h" |
| #include <bcmcdc.h> |
| #include "wlu_remote.h" |
| #include "wlu_client_shared.h" |
| #include "wlu_pipe.h" |
| #ifdef NL80211 |
| #include "wlu_nl80211.h" |
| #endif /* NL80211 */ |
| #include <miniopt.h> |
| |
| #define DEV_TYPE_LEN 3 /* length for devtype 'wl'/'et' */ |
| #define INTERACTIVE_NUM_ARGS 15 |
| #define INTERACTIVE_MAX_INPUT_LENGTH 512 |
| #define NO_ERROR 0 |
| #define RWL_WIFI_JOIN_DELAY 5 |
| |
| /* Function prototypes */ |
| static cmd_t *wl_find_cmd(char* name); |
| static int do_interactive(struct ifreq *ifr); |
| static int wl_do_cmd(struct ifreq *ifr, char **argv); |
| int process_args(struct ifreq* ifr, char **argv); |
| extern int g_child_pid; |
| /* RemoteWL declarations */ |
| int remote_type = NO_REMOTE; |
| int rwl_os_type = LINUX_OS; |
| static bool rwl_dut_autodetect = TRUE; |
| static bool debug = FALSE; |
| extern char *g_rwl_buf_mac; |
| extern char* g_rwl_device_name_serial; |
| unsigned short g_rwl_servport; |
| char *g_rwl_servIP = NULL; |
| unsigned short defined_debug = DEBUG_ERR | DEBUG_INFO; |
| static uint interactive_flag = 0; |
| extern char *remote_vista_cmds[]; |
| extern char g_rem_ifname[IFNAMSIZ]; |
| extern int rwl_check_port_number(char *s, int len); |
| |
| #ifdef NL80211 |
| static void |
| syserr(char *s) |
| { |
| UNUSED_PARAMETER(s); |
| } |
| |
| static int wl_driver_nl80211(void *wl, wl_ioctl_t *ioc) |
| { |
| struct wl_netlink_info wl_nli; |
| struct ifreq *ifr = (struct ifreq *)wl; |
| int ret = 0; |
| |
| wl_nli.ifidx = if_nametoindex(ifr->ifr_name); |
| if (!wl_nli.ifidx) { |
| fprintf(stderr, "invalid device %s\n", ifr->ifr_name); |
| return BCME_IOCTL_ERROR; |
| } |
| |
| if (wlnl_sock_connect(&wl_nli) < 0) { |
| fprintf(stderr, "%s: ", wlu_av0); |
| perror("socket"); |
| exit(errno); |
| } |
| |
| ret = wlnl_do_testmode(&wl_nli, ioc); |
| wlnl_sock_disconnect(&wl_nli); |
| return ret; |
| } |
| #else |
| static void |
| syserr(char *s) |
| { |
| fprintf(stderr, "%s: ", wlu_av0); |
| perror(s); |
| exit(errno); |
| } |
| |
| static int wl_driver_nl80211(void *wl, wl_ioctl_t *ioc) |
| { |
| UNUSED_PARAMETER(wl); |
| UNUSED_PARAMETER(ioc); |
| return BCME_IOCTL_ERROR; |
| } |
| #endif /* NL80211 */ |
| |
| static int wl_driver_ioctl(void *wl, wl_ioctl_t *ioc) |
| { |
| struct ifreq *ifr = (struct ifreq *) wl; |
| int ret; |
| int s; |
| |
| /* open socket to kernel */ |
| if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) |
| syserr("socket"); |
| |
| /* do it */ |
| ifr->ifr_data = (caddr_t)ioc; |
| ret = ioctl(s, SIOCDEVPRIVATE, ifr); |
| |
| /* cleanup */ |
| close(s); |
| return ret; |
| } |
| |
| static int (*g_driver_io)(void *wl, wl_ioctl_t *ioc) = wl_driver_ioctl; |
| |
| int |
| wl_ioctl(void *wl, int cmd, void *buf, int len, bool set) |
| { |
| wl_ioctl_t ioc; |
| int ret; |
| |
| /* do it */ |
| ioc.cmd = cmd; |
| ioc.buf = buf; |
| ioc.len = len; |
| ioc.set = set; |
| |
| ret = g_driver_io(wl, &ioc); |
| if (ret < 0) { |
| if (g_driver_io == wl_driver_ioctl) { |
| /* try using nl80211 testmode interface */ |
| ret = wl_driver_nl80211(wl, &ioc); |
| if (ret >= 0) { |
| g_driver_io = wl_driver_nl80211; |
| goto exit; |
| } |
| } |
| if (cmd != WLC_GET_MAGIC) |
| ret = BCME_IOCTL_ERROR; |
| } |
| |
| exit: |
| return ret; |
| } |
| |
| static int |
| wl_get_dev_type(char *name, void *buf, int len) |
| { |
| int s; |
| int ret; |
| struct ifreq ifr; |
| struct ethtool_drvinfo info; |
| |
| /* open socket to kernel */ |
| if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) |
| syserr("socket"); |
| |
| /* get device type */ |
| memset(&info, 0, sizeof(info)); |
| info.cmd = ETHTOOL_GDRVINFO; |
| ifr.ifr_data = (caddr_t)&info; |
| strncpy(ifr.ifr_name, name, IFNAMSIZ); |
| if ((ret = ioctl(s, SIOCETHTOOL, &ifr)) < 0) { |
| |
| /* print a good diagnostic if not superuser */ |
| if (errno == EPERM) |
| syserr("wl_get_dev_type"); |
| |
| *(char *)buf = '\0'; |
| } else { |
| strncpy(buf, info.driver, len); |
| } |
| |
| close(s); |
| return ret; |
| } |
| |
| static int |
| wl_find(struct ifreq *ifr) |
| { |
| char proc_net_dev[] = "/proc/net/dev"; |
| FILE *fp; |
| char buf[1000], *c, *name; |
| char dev_type[DEV_TYPE_LEN]; |
| int status; |
| |
| ifr->ifr_name[0] = '\0'; |
| |
| if (!(fp = fopen(proc_net_dev, "r"))) |
| return BCME_ERROR; |
| |
| /* eat first two lines */ |
| if (!fgets(buf, sizeof(buf), fp) || |
| !fgets(buf, sizeof(buf), fp)) { |
| fclose(fp); |
| return BCME_ERROR; |
| } |
| |
| while (fgets(buf, sizeof(buf), fp)) { |
| c = buf; |
| while (isspace(*c)) |
| c++; |
| if (!(name = strsep(&c, ":"))) |
| continue; |
| strncpy(ifr->ifr_name, name, IFNAMSIZ-1); |
| ifr->ifr_name[IFNAMSIZ-1] = 0; |
| if (wl_get_dev_type(name, dev_type, DEV_TYPE_LEN) >= 0 && |
| (!strncmp(dev_type, "wl", 2) || |
| !strncmp(dev_type, "brc", 3))) |
| if (wl_check((void *) ifr) == 0) |
| break; |
| ifr->ifr_name[0] = '\0'; |
| } |
| if (ifr->ifr_name[0] == '\0') |
| status = BCME_ERROR; |
| else |
| status = BCME_OK; |
| |
| fclose(fp); |
| return status; |
| } |
| |
| |
| static int |
| ioctl_queryinformation_fe(void *wl, int cmd, void* input_buf, unsigned long *input_len) |
| { |
| int error = NO_ERROR; |
| |
| if (remote_type == NO_REMOTE) { |
| error = wl_ioctl(wl, cmd, input_buf, *input_len, FALSE); |
| } else { |
| error = rwl_queryinformation_fe(wl, cmd, input_buf, |
| input_len, 0, REMOTE_GET_IOCTL); |
| |
| } |
| return error; |
| } |
| |
| static int |
| ioctl_setinformation_fe(void *wl, int cmd, void* buf, unsigned long *input_len) |
| { |
| int error = 0; |
| |
| if (remote_type == NO_REMOTE) { |
| error = wl_ioctl(wl, cmd, buf, *input_len, TRUE); |
| } else { |
| error = rwl_setinformation_fe(wl, cmd, buf, |
| input_len, 0, REMOTE_SET_IOCTL); |
| } |
| |
| return error; |
| } |
| |
| int |
| wl_get(void *wl, int cmd, void *buf, int len) |
| { |
| int error = 0; |
| unsigned long input_len = len; |
| |
| if ((rwl_os_type == WIN32_OS || rwl_os_type == WINVISTA_OS) && remote_type != NO_REMOTE) |
| cmd += WL_OID_BASE; |
| error = (int)ioctl_queryinformation_fe(wl, cmd, buf, &input_len); |
| |
| if (error == BCME_SERIAL_PORT_ERR) |
| return BCME_SERIAL_PORT_ERR; |
| else if (error == BCME_NODEVICE) |
| return BCME_NODEVICE; |
| else if (error != 0) |
| return BCME_IOCTL_ERROR; |
| |
| return 0; |
| } |
| |
| int |
| wl_set(void *wl, int cmd, void *buf, int len) |
| { |
| int error = 0; |
| unsigned long input_len = len; |
| |
| if ((rwl_os_type == WIN32_OS || rwl_os_type == WINVISTA_OS) && remote_type != NO_REMOTE) |
| cmd += WL_OID_BASE; |
| error = (int)ioctl_setinformation_fe(wl, cmd, buf, &input_len); |
| |
| if (error == BCME_SERIAL_PORT_ERR) |
| return BCME_SERIAL_PORT_ERR; |
| else if (error == BCME_NODEVICE) |
| return BCME_NODEVICE; |
| else if (error != 0) |
| return BCME_IOCTL_ERROR; |
| |
| return 0; |
| } |
| |
| #if defined(WLMSO) |
| int wl_os_type_get_rwl() |
| { |
| return rwl_os_type; |
| } |
| |
| void wl_os_type_set_rwl(int os_type) |
| { |
| rwl_os_type = os_type; |
| } |
| |
| int wl_ir_init_rwl(void **irh) |
| { |
| switch (rwl_get_remote_type()) { |
| case NO_REMOTE: |
| case REMOTE_WIFI: { |
| struct ifreq *ifr; |
| ifr = malloc(sizeof(struct ifreq)); |
| if (ifr) { |
| memset(ifr, 0, sizeof(ifr)); |
| wl_find(ifr); |
| } |
| *irh = ifr; |
| } |
| break; |
| default: |
| break; |
| } |
| |
| return 0; |
| } |
| |
| void wl_close_rwl(int remote_type, void *irh) |
| { |
| switch (remote_type) { |
| case NO_REMOTE: |
| case REMOTE_WIFI: |
| free(irh); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| #define LINUX_NUM_ARGS 16 |
| |
| static int |
| buf_to_args(char *tmp, char *new_args[]) |
| { |
| char line[INTERACTIVE_MAX_INPUT_LENGTH]; |
| char *token; |
| int argc = 0; |
| |
| if (strlen(tmp) >= INTERACTIVE_MAX_INPUT_LENGTH) { |
| printf("wl:error: Input string too long; must be < %d bytes\n", |
| INTERACTIVE_MAX_INPUT_LENGTH); |
| return 0; |
| } |
| |
| strcpy(line, tmp); |
| while (argc < (LINUX_NUM_ARGS - 1) && |
| (token = strtok(argc ? NULL : line, " \t")) != NULL) { |
| new_args[argc] = malloc(strlen(token)+1); |
| strncpy(new_args[argc], token, strlen(token)+1); |
| argc++; |
| } |
| new_args[argc] = NULL; |
| if (argc == (LINUX_NUM_ARGS - 1) && (token = strtok(NULL, " \t")) != NULL) { |
| printf("wl:error: too many args; argc must be < %d\n", |
| (LINUX_NUM_ARGS - 1)); |
| argc = LINUX_NUM_ARGS; |
| } |
| return argc; |
| } |
| |
| int |
| wl_lib(char *input_str) |
| { |
| struct ifreq ifr; |
| char *ifname = NULL; |
| int err = 0; |
| int help = 0; |
| int status = CMD_WL; |
| void* serialHandle = NULL; |
| char *tmp_argv[LINUX_NUM_ARGS]; |
| char **argv = tmp_argv; |
| int argc; |
| |
| /* buf_to_args return 0 if no args or string too long |
| * or return NDIS_NUM_ARGS if too many args |
| */ |
| if (((argc = buf_to_args(input_str, argv)) == 0) || (argc == LINUX_NUM_ARGS)) { |
| printf("wl:error: can't convert input string\n"); |
| return (-1); |
| } |
| #else |
| /* Main client function */ |
| int |
| main(int argc, char **argv) |
| { |
| struct ifreq ifr; |
| char *ifname = NULL; |
| int err = 0; |
| int help = 0; |
| int status = CMD_WL; |
| #if defined(RWL_DONGLE) || RWL_SERIAL |
| void* serialHandle = NULL; |
| #endif |
| |
| #endif /* WLMSO */ |
| wlu_av0 = argv[0]; |
| |
| wlu_init(); |
| memset(&ifr, 0, sizeof(ifr)); |
| (void)*argv++; |
| |
| if ((status = wl_option(&argv, &ifname, &help)) == CMD_OPT) { |
| if (ifname) |
| strncpy(ifr.ifr_name, ifname, IFNAMSIZ); |
| /* Bug fix: If -h is used as an option, the above function call |
| * will notice it and raise the flag but it won't be processed |
| * in this function so we undo the argv increment so that the -h |
| * can be spotted by the next call of wl_option. This will ensure |
| * that wl -h [cmd] will function as desired. |
| */ |
| else if (help) |
| (void)*argv--; |
| } |
| |
| /* Linux client looking for a indongle reflector */ |
| if (*argv && strncmp (*argv, "--indongle", strlen(*argv)) == 0) { |
| rwl_dut_autodetect = FALSE; |
| (void)*argv++; |
| } |
| /* Linux client looking for a WinVista server */ |
| if (*argv && strncmp (*argv, "--vista", strlen(*argv)) == 0) { |
| rwl_os_type = WINVISTA_OS; |
| rwl_dut_autodetect = FALSE; |
| (void)*argv++; |
| } |
| |
| /* Provide option for disabling remote DUT autodetect */ |
| if (*argv && strncmp(*argv, "--nodetect", strlen(*argv)) == 0) { |
| rwl_dut_autodetect = FALSE; |
| argv++; |
| } |
| |
| if (*argv && strncmp (*argv, "--debug", strlen(*argv)) == 0) { |
| debug = TRUE; |
| argv++; |
| } |
| |
| /* RWL socket transport Usage: --socket ipaddr/hostname [port num] */ |
| if (*argv && strncmp (*argv, "--socket", strlen(*argv)) == 0) { |
| (void)*argv++; |
| |
| remote_type = REMOTE_SOCKET; |
| |
| if (!(*argv)) { |
| rwl_usage(remote_type); |
| return err; |
| } |
| /* IP address validation is done in client_shared file */ |
| g_rwl_servIP = *argv; |
| (void)*argv++; |
| |
| /* Port number validation is done in client_shared file */ |
| g_rwl_servport = DEFAULT_SERVER_PORT; |
| if ((*argv) && (rwl_check_port_number(*argv, strlen(*argv)) == SUCCESS)) { |
| g_rwl_servport = atoi(*argv); |
| (void)*argv++; |
| } |
| } |
| |
| /* RWL from system serial port on client to uart serial port on server */ |
| /* Usage: --serial /dev/ttyS0 */ |
| if (*argv && strncmp (*argv, "--serial", strlen(*argv)) == 0) { |
| (void)*argv++; |
| remote_type = REMOTE_SERIAL; |
| } |
| |
| /* RWL from system serial port on client to uart dongle port on server */ |
| /* Usage: --dongle /dev/ttyS0 */ |
| if (*argv && strncmp (*argv, "--dongle", strlen(*argv)) == 0) { |
| (void)*argv++; |
| remote_type = REMOTE_DONGLE; |
| } |
| |
| #if defined(RWL_SERIAL) || defined(RWL_DONGLE) |
| if (remote_type == REMOTE_SERIAL || remote_type == REMOTE_DONGLE) { |
| if (!(*argv)) { |
| rwl_usage(remote_type); |
| return err; |
| } |
| g_rwl_device_name_serial = *argv; |
| (void)*argv++; |
| if ((serialHandle = rwl_open_pipe(remote_type, g_rwl_device_name_serial, 0, 0)) |
| == NULL) { |
| DPRINT_ERR(ERR, "serial device open error\r\n"); |
| return -1; |
| } |
| ifr = (*(struct ifreq *)serialHandle); |
| } |
| #endif /* RWL_SERIAL */ |
| |
| /* RWL over wifi. Usage: --wifi mac_address */ |
| if (*argv && strncmp (*argv, "--wifi", strlen(*argv)) == 0) { |
| (void)*argv++; |
| /* use default interface */ |
| if (!*ifr.ifr_name) |
| wl_find(&ifr); |
| |
| /* validate the interface */ |
| if (!*ifr.ifr_name || (err = wl_check((void *)&ifr)) < 0) { |
| fprintf(stderr, "%s: wl driver adapter not found\n", wlu_av0); |
| exit(1); |
| } |
| |
| remote_type = REMOTE_WIFI; |
| |
| if (argc < 4) { |
| rwl_usage(remote_type); |
| return err; |
| } |
| /* copy server mac address to local buffer for later use by findserver cmd */ |
| if (!wl_ether_atoe(*argv, (struct ether_addr *)g_rwl_buf_mac)) { |
| fprintf(stderr, |
| "could not parse as an ethternet MAC address\n"); |
| return FAIL; |
| } |
| (void)*argv++; |
| } |
| |
| if ((*argv) && (strlen(*argv) > 2) && |
| (strncmp(*argv, "--interactive", strlen(*argv)) == 0)) { |
| interactive_flag = 1; |
| } |
| |
| /* Process for local wl */ |
| if (remote_type == NO_REMOTE) { |
| if (interactive_flag == 1) |
| (void)*argv--; |
| err = process_args(&ifr, argv); |
| return err; |
| } else { |
| /* Autodetect remote DUT */ |
| if (rwl_dut_autodetect == TRUE) |
| rwl_detect((void*)&ifr, debug, &rwl_os_type); |
| } |
| |
| /* RWL client needs to initialize ioctl_version */ |
| if (wl_check((void *)&ifr) != 0) { |
| fprintf(stderr, "%s: wl driver adapter not found\n", wlu_av0); |
| exit(1); |
| } |
| |
| if (interactive_flag == 1) { |
| err = do_interactive(&ifr); |
| return err; |
| } |
| |
| if ((*argv) && (interactive_flag == 0)) { |
| err = process_args(&ifr, argv); |
| if ((err == BCME_SERIAL_PORT_ERR) && (remote_type == REMOTE_DONGLE)) { |
| DPRINT_ERR(ERR, "\n Retry again\n"); |
| err = process_args((struct ifreq*)&ifr, argv); |
| } |
| return err; |
| } |
| rwl_usage(remote_type); |
| #if defined(RWL_DONGLE) || RWL_SERIAL |
| if (remote_type == REMOTE_DONGLE || remote_type == REMOTE_SERIAL) |
| rwl_close_pipe(remote_type, (void*)&ifr); |
| #endif /* RWL_DONGLE || RWL_SERIAL */ |
| return err; |
| } |
| |
| /* |
| * Function called for 'local' execution and for 'remote' non-interactive session |
| * (shell cmd, wl cmd) |
| */ |
| int |
| process_args(struct ifreq* ifr, char **argv) |
| { |
| char *ifname = NULL; |
| int help = 0; |
| int status = 0; |
| int vista_cmd_index; |
| int err = 0; |
| cmd_t *cmd = NULL; |
| #ifdef RWL_WIFI |
| int retry; |
| #endif |
| |
| while (*argv) { |
| if ((strcmp (*argv, "sh") == 0) && (remote_type != NO_REMOTE)) { |
| (void)*argv++; /* Get the shell command */ |
| if (*argv) { |
| /* Register handler in case of shell command only */ |
| err = rwl_shell_cmd_proc((void*)ifr, argv, SHELL_CMD); |
| } else { |
| DPRINT_ERR(ERR, "Enter the shell " |
| "command, e.g. ls(Linux) or dir(Win CE)\n"); |
| err = -1; |
| } |
| return err; |
| } |
| |
| #ifdef RWLASD |
| if ((strcmp (*argv, "asd") == 0) && (remote_type != NO_REMOTE)) { |
| (void)*argv++; /* Get the asd command */ |
| if (*argv) { |
| err = rwl_shell_cmd_proc((void*)ifr, argv, ASD_CMD); |
| } else { |
| DPRINT_ERR(ERR, "Enter the ASD command, e.g. ca_get_version\n"); |
| err = -1; |
| } |
| return err; |
| } |
| #endif |
| if (rwl_os_type == WINVISTA_OS) { |
| for (vista_cmd_index = 0; remote_vista_cmds[vista_cmd_index] && |
| strcmp(remote_vista_cmds[vista_cmd_index], *argv); |
| vista_cmd_index++); |
| if (remote_vista_cmds[vista_cmd_index] != NULL) { |
| err = rwl_shell_cmd_proc((void *)ifr, argv, VISTA_CMD); |
| if ((remote_type == REMOTE_WIFI) && ((!strcmp(*argv, "join")))) { |
| #ifdef RWL_WIFI |
| DPRINT_INFO(OUTPUT, |
| "\nChannel will be synchronized by Findserver\n\n"); |
| sleep(RWL_WIFI_JOIN_DELAY); |
| for (retry = 0; retry < RWL_WIFI_RETRY; retry++) { |
| if ((rwl_find_remote_wifi_server(ifr, |
| &g_rwl_buf_mac[0]) == 0)) { |
| break; |
| } |
| } |
| #endif /* RWL_WIFI */ |
| } |
| return err; |
| } |
| } |
| |
| if ((status = wl_option(&argv, &ifname, &help)) == CMD_OPT) { |
| if (help) |
| break; |
| if (ifname) { |
| if (remote_type == NO_REMOTE) { |
| strncpy((*ifr).ifr_name, ifname, IFNAMSIZ); |
| } |
| else { |
| strncpy(g_rem_ifname, ifname, IFNAMSIZ); |
| } |
| } |
| continue; |
| } |
| /* parse error */ |
| else if (status == CMD_ERR) |
| break; |
| |
| if (remote_type == NO_REMOTE) { |
| /* use default interface */ |
| if (!*(*ifr).ifr_name) |
| wl_find(ifr); |
| |
| /* validate the interface */ |
| if (!*(*ifr).ifr_name || (err = wl_check((void *)ifr)) < 0) { |
| fprintf(stderr, "%s: wl driver adapter not found\n", wlu_av0); |
| exit(1); |
| } |
| |
| if ((strcmp (*argv, "--interactive") == 0) || (interactive_flag == 1)) { |
| err = do_interactive(ifr); |
| return err; |
| } |
| } |
| /* search for command */ |
| cmd = wl_find_cmd(*argv); |
| /* if not found, use default set_var and get_var commands */ |
| if (!cmd) { |
| cmd = &wl_varcmd; |
| } |
| #ifdef RWL_WIFI |
| if (!strcmp(cmd->name, "findserver")) { |
| remote_wifi_ser_init_cmds((void *) ifr); |
| } |
| #endif /* RWL_WIFI */ |
| |
| /* RWL over Wifi supports 'lchannel' command which lets client |
| * (ie *this* machine) change channels since normal 'channel' command |
| * applies to the server (ie target machine) |
| */ |
| if (remote_type == REMOTE_WIFI) { |
| #ifdef RWL_WIFI |
| if (!strcmp(argv[0], "lchannel")) { |
| strcpy(argv[0], "channel"); |
| rwl_wifi_swap_remote_type(remote_type); |
| err = (*cmd->func)((void *) ifr, cmd, argv); |
| rwl_wifi_swap_remote_type(remote_type); |
| } else { |
| err = (*cmd->func)((void *) ifr, cmd, argv); |
| } |
| /* After join cmd's gets exeuted on the server side , client needs to know |
| * the channel on which the server is associated with AP , after delay of |
| * few seconds client will intiate the scan on diffrent channels by calling |
| * rwl_find_remote_wifi_server fucntion |
| */ |
| if ((!strcmp(cmd->name, "join") || ((!strcmp(cmd->name, "ssid") && |
| (*(++argv) != NULL))))) { |
| DPRINT_INFO(OUTPUT, "\n Findserver is called to synchronize the" |
| "channel\n\n"); |
| sleep(RWL_WIFI_JOIN_DELAY); |
| for (retry = 0; retry < RWL_WIFI_RETRY; retry++) { |
| if ((rwl_find_remote_wifi_server(ifr, |
| &g_rwl_buf_mac[0]) == 0)) { |
| break; |
| } |
| } |
| } |
| #endif /* RWL_WIFI */ |
| } else { |
| /* do command */ |
| err = (*cmd->func)((void *) ifr, cmd, argv); |
| } |
| break; |
| } /* while loop end */ |
| |
| /* provide for help on a particular command */ |
| if (help && *argv) { |
| cmd = wl_find_cmd(*argv); |
| if (cmd) { |
| wl_cmd_usage(stdout, cmd); |
| } else { |
| DPRINT_ERR(ERR, "%s: Unrecognized command \"%s\", type -h for help\n", |
| wlu_av0, *argv); |
| } |
| } else if (!cmd) |
| wl_usage(stdout, NULL); |
| else if (err == BCME_USAGE_ERROR) |
| wl_cmd_usage(stderr, cmd); |
| else if (err == BCME_IOCTL_ERROR) |
| wl_printlasterror((void *) ifr); |
| else if (err == BCME_NODEVICE) |
| DPRINT_ERR(ERR, "%s : wl driver adapter not found\n", g_rem_ifname); |
| |
| return err; |
| } |
| |
| /* Function called for 'local' interactive session and for 'remote' interactive session */ |
| static int |
| do_interactive(struct ifreq *ifr) |
| { |
| int err = 0; |
| |
| #ifdef RWL_WIFI |
| int retry; |
| #endif |
| |
| while (1) { |
| char *fgsret; |
| char line[INTERACTIVE_MAX_INPUT_LENGTH]; |
| fprintf(stdout, "> "); |
| fgsret = fgets(line, sizeof(line), stdin); |
| |
| /* end of file */ |
| if (fgsret == NULL) |
| break; |
| if (line[0] == '\n') |
| continue; |
| |
| if (strlen (line) > 0) { |
| /* skip past first arg if it's "wl" and parse up arguments */ |
| char *argv[INTERACTIVE_NUM_ARGS]; |
| int argc; |
| char *token; |
| argc = 0; |
| |
| while (argc < (INTERACTIVE_NUM_ARGS - 1) && |
| (token = strtok(argc ? NULL : line, " \t\n")) != NULL) { |
| |
| /* Specifically make sure empty arguments (like SSID) are empty */ |
| if (token[0] == '"' && token[1] == '"') { |
| token[0] = '\0'; |
| } |
| |
| argv[argc++] = token; |
| } |
| argv[argc] = NULL; |
| if (argc == (INTERACTIVE_NUM_ARGS - 1) && |
| (token = strtok(NULL, " \t")) != NULL) { |
| printf("wl:error: too many args; argc must be < %d\n", |
| (INTERACTIVE_NUM_ARGS - 1)); |
| continue; |
| } |
| #ifdef RWL_WIFI |
| if (!strcmp(argv[0], "findserver")) { |
| remote_wifi_ser_init_cmds((void *) ifr); |
| } |
| #endif /* RWL_WIFI */ |
| |
| if (strcmp(argv[0], "q") == 0 || strcmp(argv[0], "exit") == 0) { |
| break; |
| } |
| |
| if ((strcmp(argv[0], "sh") == 0) && (remote_type != NO_REMOTE)) { |
| if (argv[1]) { |
| process_args(ifr, argv); |
| } else { |
| DPRINT_ERR(ERR, "Give shell command"); |
| continue; |
| } |
| } else { /* end shell */ |
| /* check for lchannel support,applicable only for wifi transport. |
| * when lchannel is called remote type is swapped by calling swap_ |
| * remote_type.This is done to change, the remote type to local, |
| * so that local machine's channel can be executed and |
| * returned to the user. |
| * To get back the original remote type, swap is recalled. |
| */ |
| if (remote_type == REMOTE_WIFI) { |
| #ifdef RWL_WIFI |
| if (!strcmp(argv[0], "lchannel")) { |
| strcpy(argv[0], "channel"); |
| rwl_wifi_swap_remote_type(remote_type); |
| err = wl_do_cmd(ifr, argv); |
| rwl_wifi_swap_remote_type(remote_type); |
| } else { |
| err = wl_do_cmd(ifr, argv); |
| } |
| /* After join cmd's gets exeuted on the server side, client |
| * needs to know the channel on which the server is associated |
| * with AP , after delay of few seconds client will intiate the |
| * scan on diffrent channels by calling |
| * rwl_find_remote_wifi_server function |
| */ |
| if ((!strcmp(argv[0], "join")) || |
| (!strcmp(argv[0], "ssid"))) { |
| DPRINT_INFO(OUTPUT, "\n Findserver is called" |
| "after the join issued to remote \n \n"); |
| sleep(RWL_WIFI_JOIN_DELAY); |
| for (retry = 0; retry < RWL_WIFI_RETRY; retry++) { |
| if ((rwl_find_remote_wifi_server(ifr, |
| &g_rwl_buf_mac[0]) == 0)) { |
| break; |
| } |
| } |
| } |
| #endif /* RWL_WIFI */ |
| } else { |
| err = wl_do_cmd(ifr, argv); |
| } |
| } /* end of wl */ |
| } /* end of strlen (line) > 0 */ |
| } /* while (1) */ |
| |
| return err; |
| } |
| |
| /* |
| * find command in argv and execute it |
| * Won't handle changing ifname yet, expects that to happen with the --interactive |
| * Return an error if unable to find/execute command |
| */ |
| static int |
| wl_do_cmd(struct ifreq *ifr, char **argv) |
| { |
| cmd_t *cmd = NULL; |
| int err = 0; |
| int help = 0; |
| char *ifname = NULL; |
| int status = CMD_WL; |
| |
| /* skip over 'wl' if it's there */ |
| if (*argv && strcmp (*argv, "wl") == 0) { |
| argv++; |
| } |
| |
| /* handle help or interface name changes */ |
| if (*argv && (status = wl_option (&argv, &ifname, &help)) == CMD_OPT) { |
| if (ifname) { |
| fprintf(stderr, |
| "Interface name change not allowed within --interactive\n"); |
| } |
| } |
| |
| /* in case wl_option eats all the args */ |
| if (!*argv) { |
| return err; |
| } |
| |
| if (status != CMD_ERR) { |
| /* search for command */ |
| cmd = wl_find_cmd(*argv); |
| |
| /* defaults to using the set_var and get_var commands */ |
| if (!cmd) { |
| cmd = &wl_varcmd; |
| } |
| /* do command */ |
| err = (*cmd->func)((void *)ifr, cmd, argv); |
| } |
| /* provide for help on a particular command */ |
| if (help && *argv) { |
| cmd = wl_find_cmd(*argv); |
| if (cmd) { |
| wl_cmd_usage(stdout, cmd); |
| } else { |
| DPRINT_ERR(ERR, "%s: Unrecognized command \"%s\", type -h for help\n", |
| wlu_av0, *argv); |
| } |
| } else if (!cmd) |
| wl_usage(stdout, NULL); |
| else if (err == BCME_USAGE_ERROR) |
| wl_cmd_usage(stderr, cmd); |
| else if (err == BCME_IOCTL_ERROR) |
| wl_printlasterror((void *)ifr); |
| else if (err == BCME_NODEVICE) |
| DPRINT_ERR(ERR, "%s : wl driver adapter not found\n", g_rem_ifname); |
| |
| return err; |
| } |
| |
| /* Search the wl_cmds table for a matching command name. |
| * Return the matching command or NULL if no match found. |
| */ |
| static cmd_t * |
| wl_find_cmd(char* name) |
| { |
| cmd_t *cmd = NULL; |
| |
| /* search the wl_cmds for a matching name */ |
| for (cmd = wl_cmds; cmd->name && strcmp(cmd->name, name); cmd++); |
| |
| if (cmd->name == NULL) |
| cmd = NULL; |
| |
| return cmd; |
| } |
| |
| void def_handler(int signum) |
| { |
| UNUSED_PARAMETER(signum); |
| kill(g_child_pid, SIGINT); |
| kill(getpid(), SIGINT); |
| exit(0); |
| } |
| /* Create a child that waits for Ctrl-C at the client side |
| */ |
| int rwl_shell_createproc(void *wl) |
| { |
| UNUSED_PARAMETER(wl); |
| signal(SIGINT, ctrlc_handler); |
| signal(SIGTERM, def_handler); |
| signal(SIGABRT, def_handler); |
| return fork(); |
| } |
| |
| /* In case if the server shell command exits normally |
| * then kill the thread that was waiting for Ctr-C to happen |
| * at the client side |
| */ |
| void rwl_shell_killproc(int pid) |
| { |
| kill(pid, SIGKILL); |
| signal(SIGINT, SIG_DFL); |
| wait(NULL); |
| } |
| #ifdef RWL_SOCKET |
| /* to validate hostname/ip given by the client */ |
| int validate_server_address() |
| { |
| struct hostent *he; |
| struct ipv4_addr temp; |
| if (!wl_atoip(g_rwl_servIP, &temp)) { |
| /* Wrong IP address format check for hostname */ |
| if ((he = gethostbyname(g_rwl_servIP)) != NULL) { |
| if (!wl_atoip(*he->h_addr_list, &temp)) { |
| g_rwl_servIP = |
| inet_ntoa(*(struct in_addr *)*he->h_addr_list); |
| if (g_rwl_servIP == NULL) { |
| DPRINT_ERR(ERR, "Error at inet_ntoa \n"); |
| return FAIL; |
| } |
| } else { |
| DPRINT_ERR(ERR, "Error in IP address \n"); |
| return FAIL; |
| } |
| } else { |
| DPRINT_ERR(ERR, "Enter correct IP address/hostname format\n"); |
| return FAIL; |
| } |
| } |
| return SUCCESS; |
| } |
| #endif /* RWL_SOCKET */ |