/**************************************************************************** * apps/wireless/wapi/src/wapi.c * * Copyright (C) 2011, 2017Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Largely and original work, but highly influenced by sampled code provided * with WAPI: * * Copyright (c) 2010, Volkan YAZICI * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include "wireless/wapi.h" #include "util.h" /**************************************************************************** * Private Types ****************************************************************************/ /* Describes one command */ struct wapi_command_s { FAR const char *name; uint8_t noptions; CODE void *handler; }; /* Generic form of a commnd handler */ typedef void (*cmd1_t)(int sock, FAR const char *arg1); typedef void (*cmd2_t)(int sock, FAR const char *arg1, FAR const char *arg2); typedef void (*cmd3_t)(int sock, FAR const char *arg1, FAR const char *arg2, FAR const char *arg3); /**************************************************************************** * Private Function Prototypes ****************************************************************************/ static int wapi_str2int(FAR const char *str); static double wapi_str2double(FAR const char *str); static unsigned int wapi_str2ndx(FAR const char *name, FAR const char **list, unsigned int listlen); static void wapi_show_cmd(int sock, FAR const char *ifname); static void wapi_ip_cmd(int sock, FAR const char *ifname, FAR const char *addrstr); static void wapi_mask_cmd(int sock, FAR const char *ifname, FAR const char *maskstr); static void wapi_freq_cmd(int sock, FAR const char *ifname, FAR const char *freqstr, FAR const char *flagstr); static void wapi_essid_cmd(int sock, FAR const char *ifname, FAR const char *essid, FAR const char *flagstr); static void wapi_mode_cmd(int sock, FAR const char *ifname, FAR const char *modestr); static void wapi_ap_cmd(int sock, FAR const char *ifname, FAR const char *macstr); static void wapi_bitrate_cmd(int sock, FAR const char *ifname, FAR const char *ratestr, FAR const char *flagstr); static void wapi_txpower_cmd(int sock, FAR const char *ifname, FAR const char *pwrstr, FAR const char *flagstr); static void wapi_scan_cmd(int sock, FAR const char *ifname); static void wapi_showusage(FAR const char *progname, int exitcode); /**************************************************************************** * Private Data ****************************************************************************/ static const struct wapi_command_s g_wapi_commands[] = { {"help", 0, (CODE void *)NULL}, {"show", 1, (CODE void *)wapi_show_cmd}, {"scan", 1, (CODE void *)wapi_scan_cmd}, {"ip", 2, (CODE void *)wapi_ip_cmd}, {"mask", 2, (CODE void *)wapi_mask_cmd}, {"freq", 3, (CODE void *)wapi_freq_cmd}, {"essid", 3, (CODE void *)wapi_essid_cmd}, {"mode", 2, (CODE void *)wapi_mode_cmd}, {"ap", 2, (CODE void *)wapi_ap_cmd}, {"bitrate", 3, (CODE void *)wapi_bitrate_cmd}, {"txpower", 3, (CODE void *)wapi_txpower_cmd}, }; #define NCOMMANDS (sizeof(g_wapi_commands) / sizeof(struct wapi_command_s)) /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: wapi_str2int * * Description: * Convert a string to an integer value * ****************************************************************************/ static int wapi_str2int(FAR const char *str) { FAR char *endptr; long value; value = strtol(str, &endptr, 0); if (*endptr != '\0') { WAPI_ERROR("ERROR: Garbage after numeric argument\n"); exit(EXIT_FAILURE); } if (value > INT_MAX || value < INT_MIN) { WAPI_ERROR("ERROR: Integer value out of range\n"); exit(EXIT_FAILURE); } return (int)value; } /**************************************************************************** * Name: wapi_str2double * * Description: * Convert a string to a double value * ****************************************************************************/ static double wapi_str2double(FAR const char *str) { FAR char *endptr; double value; value = strtod(str, &endptr); if (*endptr != '\0') { WAPI_ERROR("ERROR: Garbage after numeric argument\n"); exit(EXIT_FAILURE); } return value; } /**************************************************************************** * Name: wapi_str2ndx * * Description: * Return the index of a string in a list of strings * ****************************************************************************/ static unsigned int wapi_str2ndx(FAR const char *name, FAR const char **list, unsigned int listlen) { unsigned int ndx; for (ndx = 0; ndx < listlen; ndx++) { if (strcmp(name, list[ndx]) == 0) { return ndx; } } WAPI_ERROR("ERROR: Invalid option string: %s\n", name); WAPI_ERROR(" Valid options include:\n"); for (ndx = 0; ndx < listlen; ndx++) { WAPI_ERROR(" - %s\n", list[ndx]); } exit(EXIT_FAILURE); } /**************************************************************************** * Name: wapi_show_cmd * * Description: * Gets current configuration of the ifname using WAPI accessors and prints * them in a pretty fashion with their corresponding return values. If a * getter succeeds, we try to set that property with the same value to test * the setters as well. * * Returned Value: * None * ****************************************************************************/ static void wapi_show_cmd(int sock, FAR const char *ifname) { struct in_addr addr; double freq; wapi_freq_flag_t freq_flag; char essid[WAPI_ESSID_MAX_SIZE + 1]; wapi_essid_flag_t essid_flag; wapi_mode_t mode; struct ether_addr ap; int bitrate; wapi_bitrate_flag_t bitrate_flag; int txpower; wapi_txpower_flag_t txpower_flag; int ret; printf("%s Configuration:\n", ifname); /* Get ip */ bzero(&addr, sizeof(struct in_addr)); ret = wapi_get_ip(sock, ifname, &addr); if (ret < 0) { WAPI_ERROR("ERROR: wapi_get_ip() failed: %d\n", ret); } else { printf(" IP: %s\n", inet_ntoa(addr)); } /* Get netmask */ bzero(&addr, sizeof(struct in_addr)); ret = wapi_get_netmask(sock, ifname, &addr); if (ret < 0) { WAPI_ERROR("ERROR: wapi_get_netmask() failed: %d\n", ret); } else { printf(" NetMask: %s\n", inet_ntoa(addr)); } /* Get frequency */ ret = wapi_get_freq(sock, ifname, &freq, &freq_flag); if (ret < 0) { WAPI_ERROR("ERROR: wapi_get_freq() failed: %d\n", ret); } else { double tmpfreq; int chan; printf("Frequency: %g\n", freq); printf(" Flag: %s\n", g_wapi_freq_flags[freq_flag]); ret = wapi_freq2chan(sock, ifname, freq, &chan); if (ret < 0) { WAPI_ERROR("ERROR: wapi_freq2chan() failed: %d\n", ret); } else { printf(" Channel: %d\n", chan); } ret = wapi_chan2freq(sock, ifname, chan, &tmpfreq); if (ret < 0) { WAPI_ERROR("ERROR: wapi_chan2freq() failed: %d\n", ret); } else { printf("Frequency: %g\n", tmpfreq); } } /* Get the ESSID */ ret = wapi_get_essid(sock, ifname, essid, &essid_flag); if (ret < 0) { WAPI_ERROR("ERROR: wapi_get_essid() failed: %d\n", ret); } else { printf(" ESSID: %s\n", essid); printf(" Flag: %s\n", g_wapi_essid_flags[essid_flag]); } /* Get operating mode */ ret = wapi_get_mode(sock, ifname, &mode); if (ret < 0) { WAPI_ERROR("ERROR: wapi_get_mode() failed: %d\n", ret); } else { printf(" Mode: %s", g_wapi_modes[mode]); } /* Get AP */ ret = wapi_get_ap(sock, ifname, &ap); if (ret < 0) { WAPI_ERROR("ERROR: wapi_get_ap() failed: %d\n", ret); } else { printf(" AP: %02x:%02x:%02x:%02x:%02x:%02x\n", ap.ether_addr_octet[0], ap.ether_addr_octet[1], ap.ether_addr_octet[2], ap.ether_addr_octet[3], ap.ether_addr_octet[4], ap.ether_addr_octet[5]); } /* Get bitrate */ ret = wapi_get_bitrate(sock, ifname, &bitrate, &bitrate_flag); if (ret < 0) { WAPI_ERROR("ERROR: wapi_get_bitrate() failed: %d\n", ret); } else { printf(" BitRate: %d\n", bitrate); printf(" Flag: %s\n", g_wapi_bitrate_flags[bitrate_flag]); } /* Get txpower */ ret = wapi_get_txpower(sock, ifname, &txpower, &txpower_flag); if (ret < 0) { WAPI_ERROR("ERROR: wapi_get_txpower() failed: %d\n", ret); } else { printf(" TxPower: %d\n", txpower); printf(" Flag: %s\n", g_wapi_txpower_flags[txpower_flag]); } } /**************************************************************************** * Name: wapi_ip_cmd * * Description: * Set the IP address. * * Returned Value: * None * ****************************************************************************/ static void wapi_ip_cmd(int sock, FAR const char *ifname, FAR const char *addrstr) { struct in_addr addr; int ret; /* Format the request */ addr.s_addr = inet_addr(addrstr); /* Set the IP address */ ret = wapi_set_ip(sock, ifname, &addr); if (ret < 0) { WAPI_ERROR("ERROR: wapi_set_ip() failed: %d\n", ret); } } /**************************************************************************** * Name: wapi_mask_cmd * * Description: * Set the network mask * * Returned Value: * None * ****************************************************************************/ static void wapi_mask_cmd(int sock, FAR const char *ifname, FAR const char *maskstr) { struct in_addr addr; int ret; /* Format the request */ addr.s_addr = inet_addr(maskstr); /* Set the network mask */ ret = wapi_set_netmask(sock, ifname, &addr); if (ret < 0) { WAPI_ERROR("ERROR: wapi_set_netmask() failed: %d\n", ret); } } /**************************************************************************** * Name: wapi_freq_cmd * * Description: * Set the frequency * * Returned Value: * None * ****************************************************************************/ static void wapi_freq_cmd(int sock, FAR const char *ifname, FAR const char *freqstr, FAR const char *flagstr) { double frequency; wapi_freq_flag_t freq_flag; int ret; /* Convert input strings to values */ frequency = wapi_str2double(freqstr); freq_flag = (wapi_freq_flag_t)wapi_str2ndx(flagstr, g_wapi_freq_flags, IW_FREQ_NFLAGS); /* Set the frequency */ ret = wapi_set_freq(sock, ifname, frequency, freq_flag); if (ret < 0) { WAPI_ERROR("ERROR: \nwapi_set_freq() failed: %d\n", ret); } } /**************************************************************************** * Name: wapi_essid_cmd * * Description: * Set the ESSID * * Returned Value: * None * ****************************************************************************/ static void wapi_essid_cmd(int sock, FAR const char *ifname, FAR const char *essid, FAR const char *flagstr) { wapi_essid_flag_t essid_flag; int ret; /* Convert input strings to values */ essid_flag = (wapi_essid_flag_t)wapi_str2ndx(flagstr, g_wapi_essid_flags, 2); /* Set the ESSID */ ret = wapi_set_essid(sock, ifname, essid, essid_flag); if (ret < 0) { WAPI_ERROR("ERROR: wapi_set_essid() failed: %d\n", ret); } } /**************************************************************************** * Name: wapi_mode_cmd * * Description: * Set the operating mode * * Returned Value: * None * ****************************************************************************/ static void wapi_mode_cmd(int sock, FAR const char *ifname, FAR const char *modestr) { wapi_mode_t mode; int ret; /* Convert input strings to values */ mode = (wapi_mode_t)wapi_str2ndx(modestr, g_wapi_modes, IW_MODE_NFLAGS); /* Set operating mode */ ret = wapi_set_mode(sock, ifname, mode); if (ret < 0) { WAPI_ERROR("ERROR: \nwapi_set_mode() failed: %d\n", ret); } } /**************************************************************************** * Name: wapi_ap_cmd * * Description: * Set the AP * * Returned Value: * None * ****************************************************************************/ static void wapi_ap_cmd(int sock, FAR const char *ifname, FAR const char *macstr) { struct ether_addr ap; int ret; /* Convert input strings to values */ sscanf(macstr, "%02x:%02x:%02x:%02x:%02x:%02x", &ap.ether_addr_octet[0], &ap.ether_addr_octet[1], &ap.ether_addr_octet[2], &ap.ether_addr_octet[3], &ap.ether_addr_octet[4], &ap.ether_addr_octet[5]); /* Set ap */ ret = wapi_set_ap(sock, ifname, &ap); if (ret < 0) { WAPI_ERROR("ERROR: \nwapi_set_ap() failed: %d\n", ret); } } /**************************************************************************** * Name: wapi_bitrate_cmd * * Description: * Set the bit rate * * Returned Value: * None * ****************************************************************************/ static void wapi_bitrate_cmd(int sock, FAR const char *ifname, FAR const char *ratestr, FAR const char *flagstr) { wapi_bitrate_flag_t bitrate_flag; int bitrate; int ret; /* Convert input strings to values */ bitrate = wapi_str2int(ratestr); bitrate_flag = (wapi_bitrate_flag_t) wapi_str2ndx(flagstr, g_wapi_bitrate_flags, 2); /* Set bitrate */ ret = wapi_set_bitrate(sock, ifname, bitrate, bitrate_flag); if (ret < 0) { WAPI_ERROR("ERROR: \nwapi_set_bitrate() failed: %d\n", ret); } } /**************************************************************************** * Name: wapi_txpower_cmd * * Description: * Set the TX power * * Returned Value: * None * ****************************************************************************/ static void wapi_txpower_cmd(int sock, FAR const char *ifname, FAR const char *pwrstr, FAR const char *flagstr) { wapi_txpower_flag_t txpower_flag; int txpower; int ret; /* Convert input strings to values */ txpower = wapi_str2int(pwrstr); txpower_flag = (wapi_txpower_flag_t) wapi_str2ndx(flagstr, g_wapi_txpower_flags, IW_TXPOW_NFLAGS); /* Set txpower */ ret = wapi_set_txpower(sock, ifname, txpower, txpower_flag); if (ret < 0) { WAPI_ERROR("ERROR: \nwapi_set_txpower() failed: %d\n", ret); } } /**************************************************************************** * Name: wapi_scan_cmd * * Description: * Scans available APs in the range using given ifname interface. * * Returned Value: * None * ****************************************************************************/ static void wapi_scan_cmd(int sock, FAR const char *ifname) { int sleepdur = 1; int sleeptries = 5; wapi_list_t list; FAR wapi_scan_info_t *info; int ret; /* Start scan */ ret = wapi_scan_init(sock, ifname); WAPI_ERROR("ERROR: wapi_scan_init() failed: %d\n", ret); /* Wait for completion */ do { sleep(sleepdur); ret = wapi_scan_stat(sock, ifname); WAPI_ERROR("ERROR: wapi_scan_stat() failed: %d, sleeptries: %d\n", ret, sleeptries); } while (--sleeptries > 0 && ret > 0); if (ret < 0) { return; } /* Collect results */ bzero(&list, sizeof(wapi_list_t)); ret = wapi_scan_coll(sock, ifname, &list); if (ret < 0) { WAPI_ERROR("ERROR: wapi_scan_coll() failed: %d\n", ret); } /* Print found aps */ for (info = list.head.scan; info; info = info->next) { printf(" %02x:%02x:%02x:%02x:%02x:%02x %s\n", info->ap.ether_addr_octet[0], info->ap.ether_addr_octet[1], info->ap.ether_addr_octet[2], info->ap.ether_addr_octet[3], info->ap.ether_addr_octet[4], info->ap.ether_addr_octet[5], (info->has_essid ? info->essid : "")); } /* Free ap list */ info = list.head.scan; while (info) { FAR wapi_scan_info_t *temp; temp = info->next; free(info); info = temp; } } /**************************************************************************** * Name: wapi_showusage * * Description: * Show program usage. * * Returned Value: * None * ****************************************************************************/ static void wapi_showusage(FAR const char *progname, int exitcode) { int i; fprintf(stderr, "Usage: %s show \n", progname); fprintf(stderr, " %s scan \n", progname); fprintf(stderr, " %s ip \n", progname); fprintf(stderr, " %s mask \n", progname); fprintf(stderr, " %s freq \n", progname); fprintf(stderr, " %s essid \n", progname); fprintf(stderr, " %s mode \n", progname); fprintf(stderr, " %s ap \n", progname); fprintf(stderr, " %s bitrate \n", progname); fprintf(stderr, " %s txpower \n", progname); fprintf(stderr, " %s help\n", progname); fprintf(stderr, "\nFrequency Flags:\n"); for (i = 0; i < IW_FREQ_NFLAGS; i++) { fprintf(stderr, " %s\n", g_wapi_freq_flags[i]); } fprintf(stderr, "\nESSID Flags:\n"); for (i = 0; i < 2; i++) { fprintf(stderr, " %s\n", g_wapi_essid_flags[i]); } fprintf(stderr, "\nOperating Modes:\n"); for (i = 0; i < IW_MODE_NFLAGS; i++) { fprintf(stderr, " %s\n", g_wapi_modes[i]); } fprintf(stderr, "\nBitrate Flags:\n"); for (i = 0; i < 2; i++) { fprintf(stderr, " %s\n", g_wapi_bitrate_flags[i]); } fprintf(stderr, "\nTX power Flags:\n"); for (i = 0; i < IW_TXPOW_NFLAGS; i++) { fprintf(stderr, " %s\n", g_wapi_txpower_flags[i]); } exit(exitcode); } /**************************************************************************** * Public Functions ****************************************************************************/ #ifdef CONFIG_BUILD_KERNEL int main(int argc, FAR char *argv[]) #else int wapi_main(int argc, char *argv[]) #endif { FAR const char *cmdname; FAR const struct wapi_command_s *wapicmd; int sock; int i; /* Get the command */ if (argc < 2) { WAPI_ERROR("ERROR: Missing command\n"); wapi_showusage(argv[0], EXIT_FAILURE); } cmdname = argv[1]; /* Find the command in the g_wapi_command[] list */ wapicmd = NULL; for (i = 0; i < NCOMMANDS; i++) { FAR const struct wapi_command_s *cmd = &g_wapi_commands[i]; if (strcmp(cmdname, cmd->name) == 0) { wapicmd = cmd; break; } } if (wapicmd == NULL) { WAPI_ERROR("ERROR: Unsupported command: %s\n", cmdname); wapi_showusage(argv[0], EXIT_FAILURE); } if (wapicmd->noptions + 2 < argc) { WAPI_ERROR("ERROR: Garbage at end of command ignored\n"); } else if (wapicmd->noptions + 2 > argc) { WAPI_ERROR("ERROR: Missing required command options: %s\n", cmdname); wapi_showusage(argv[0], EXIT_FAILURE); } /* Special case the help command which has no arguments, no handler, * and does not need a socket. */ if (wapicmd->handler == NULL) { wapi_showusage(argv[0], EXIT_SUCCESS); } /* Create a communication socket */ sock = wapi_make_socket(); if (sock < 0) { WAPI_ERROR("ERROR: wapi_make_socket() failed: %d\n", sock); return EXIT_FAILURE; } /* Dispatch the command handling */ switch (wapicmd->noptions) { default: case 0: WAPI_ERROR("ERROR: Internal craziness\n"); wapi_showusage(argv[0], EXIT_FAILURE); case 1: ((cmd1_t)wapicmd->handler)(sock, argv[2]); break; case 2: ((cmd2_t)wapicmd->handler)(sock, argv[2], argv[3]); break; case 3: ((cmd3_t)wapicmd->handler)(sock, argv[2], argv[3], argv[4]); break; } /* Close communication socket */ close(sock); return EXIT_SUCCESS; }