Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/next/external/cache/sources/wl/dhd/dhdu_linux.c
Views: 3960
/*1* Linux port of dhd command line utility, hacked from wl utility.2*3* $Copyright Open Broadcom Corporation$4*5* $Id: dhdu_linux.c 281524 2011-09-02 17:09:25Z $6*/78#include <stdio.h>9#include <stdlib.h>10#include <unistd.h>11#include <ctype.h>12#include <string.h>13#include <errno.h>14#include <sys/types.h>15#include <sys/wait.h>16#include <sys/socket.h>17#include <proto/ethernet.h>18#include <proto/bcmip.h>19#include <arpa/inet.h>20#include <sys/ioctl.h>21#include <net/if.h>22#include <fcntl.h>23#include <sys/ioctl.h>24#include <unistd.h>2526#ifndef TARGETENV_android27#include <error.h>28typedef u_int64_t u64;29typedef u_int32_t u32;30typedef u_int16_t u16;31typedef u_int8_t u8;32#endif /* TARGETENV_android */33#include <linux/sockios.h>34#include <linux/types.h>35#include <linux/ethtool.h>3637#include <typedefs.h>38#include <signal.h>39#include <dhdioctl.h>40#include <wlioctl.h>41#include <bcmcdc.h>42#include <bcmutils.h>43#include "dhdu.h"44#include "wlu_remote.h"45#include "wlu_client_shared.h"46#include "wlu_pipe.h"47#include <netdb.h>48#include <netinet/in.h>49#include <dhdioctl.h>50#include "dhdu_common.h"5152char *av0;53static int rwl_os_type = LINUX_OS;54/* Search the dhd_cmds table for a matching command name.55* Return the matching command or NULL if no match found.56*/57static cmd_t *58dhd_find_cmd(char* name)59{60cmd_t *cmd = NULL;61/* search the dhd_cmds for a matching name */62for (cmd = dhd_cmds; cmd->name && strcmp(cmd->name, name); cmd++);63if (cmd->name == NULL)64cmd = NULL;65return cmd;66}6768static void69syserr(char *s)70{71fprintf(stderr, "%s: ", dhdu_av0);72perror(s);73exit(errno);74}7576/* This function is called by ioctl_setinformation_fe or ioctl_queryinformation_fe77* for executing remote commands or local commands78*/79static int80dhd_ioctl(void *dhd, int cmd, void *buf, int len, bool set)81{82struct ifreq *ifr = (struct ifreq *)dhd;83dhd_ioctl_t ioc;84int ret = 0;85int s;86/* By default try to execute wl commands */87int driver_magic = WLC_IOCTL_MAGIC;88int get_magic = WLC_GET_MAGIC;8990/* For local dhd commands execute dhd. For wifi transport we still91* execute wl commands.92*/93if (remote_type == NO_REMOTE && strncmp (buf, RWL_WIFI_ACTION_CMD,94strlen(RWL_WIFI_ACTION_CMD)) && strncmp(buf, RWL_WIFI_GET_ACTION_CMD,95strlen(RWL_WIFI_GET_ACTION_CMD))) {96driver_magic = DHD_IOCTL_MAGIC;97get_magic = DHD_GET_MAGIC;98}99100/* open socket to kernel */101if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)102syserr("socket");103104/* do it */105ioc.cmd = cmd;106ioc.buf = buf;107ioc.len = len;108ioc.set = set;109ioc.driver = driver_magic;110ifr->ifr_data = (caddr_t) &ioc;111112if ((ret = ioctl(s, SIOCDEVPRIVATE, ifr)) < 0) {113if (cmd != get_magic) {114ret = IOCTL_ERROR;115}116}117118/* cleanup */119close(s);120return ret;121}122123/* This function is called in wlu_pipe.c remote_wifi_ser_init() to execute124* the initial set of wl commands for wifi transport (e.g slow_timer, fast_timer etc)125*/126int wl_ioctl(void *wl, int cmd, void *buf, int len, bool set)127{128return dhd_ioctl(wl, cmd, buf, len, set); /* Call actual wl_ioctl here: Shubhro */129}130131/* Search if dhd adapter or wl adapter is present132* This is called by dhd_find to check if it supports wl or dhd133* The reason for checking wl adapter is that we can still send remote dhd commands over134* wifi transport.135*/136static int137dhd_get_dev_type(char *name, void *buf, char *type)138{139int s;140int ret;141struct ifreq ifr;142struct ethtool_drvinfo info;143144/* open socket to kernel */145if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)146syserr("socket");147148/* get device type */149memset(&info, 0, sizeof(info));150info.cmd = ETHTOOL_GDRVINFO;151strcpy(info.driver, "?");152strcat(info.driver, type);153ifr.ifr_data = (caddr_t)&info;154strncpy(ifr.ifr_name, name, IFNAMSIZ);155if ((ret = ioctl(s, SIOCETHTOOL, &ifr)) < 0) {156157/* print a good diagnostic if not superuser */158if (errno == EPERM)159syserr("dhd_get_dev_type");160161*(char *)buf = '\0';162}163else164strcpy(buf, info.driver);165166close(s);167return ret;168}169170/* dhd_get/dhd_set is called by several functions in dhdu.c. This used to call dhd_ioctl171* directly. However now we need to execute the dhd commands remotely.172* So we make use of wl pipes to execute this.173* wl_get or wl_set functions also check if it is a local command hence they in turn174* call dhd_ioctl if required. Name wl_get/wl_set is retained because these functions are175* also called by wlu_pipe.c wlu_client_shared.c176*/177int178dhd_get(void *dhd, int cmd, void *buf, int len)179{180return wl_get(dhd, cmd, buf, len);181}182183/*184* To use /dev/node interface:185* 1. mknod /dev/hnd0 c 248 0186* 2. chmod 777 /dev/hnd0187*/188#define NODE "/dev/hnd0"189190int191dhd_set(void *dhd, int cmd, void *buf, int len)192{193static int dnode = -1;194195switch (cmd) {196case DHD_DLDN_ST:197if (dnode == -1)198dnode = open(NODE, O_RDWR);199else200fprintf(stderr, "devnode already opened!\n");201202return dnode;203break;204case DHD_DLDN_WRITE:205if (dnode > 0)206return write(dnode, buf, len);207break;208case DHD_DLDN_END:209if (dnode > 0)210return close(dnode);211break;212default:213return wl_set(dhd, cmd, buf, len);214215}216217return -1;218}219220/* Verify the wl adapter found.221* This is called by dhd_find to check if it supports wl222* The reason for checking wl adapter is that we can still send remote dhd commands over223* wifi transport. The function is copied from wlu.c.224*/225int226wl_check(void *wl)227{228int ret;229int val = 0;230231if (!dhd_check (wl))232return 0;233234/*235* If dhd_check() fails then go for a regular wl driver verification236*/237if ((ret = wl_get(wl, WLC_GET_MAGIC, &val, sizeof(int))) < 0)238return ret;239if (val != WLC_IOCTL_MAGIC)240return BCME_ERROR;241if ((ret = wl_get(wl, WLC_GET_VERSION, &val, sizeof(int))) < 0)242return ret;243if (val > WLC_IOCTL_VERSION) {244fprintf(stderr, "Version mismatch, please upgrade\n");245return BCME_ERROR;246}247return 0;248}249/* Search and verify the request type of adapter (wl or dhd)250* This is called by main before executing local dhd commands251* or sending remote dhd commands over wifi transport252*/253void254dhd_find(struct ifreq *ifr, char *type)255{256char proc_net_dev[] = "/proc/net/dev";257FILE *fp;258static char buf[400];259char *c, *name;260char dev_type[32];261262ifr->ifr_name[0] = '\0';263/* eat first two lines */264if (!(fp = fopen(proc_net_dev, "r")) ||265!fgets(buf, sizeof(buf), fp) ||266!fgets(buf, sizeof(buf), fp))267return;268269while (fgets(buf, sizeof(buf), fp)) {270c = buf;271while (isspace(*c))272c++;273if (!(name = strsep(&c, ":")))274continue;275strncpy(ifr->ifr_name, name, IFNAMSIZ);276if (dhd_get_dev_type(name, dev_type, type) >= 0 &&277!strncmp(dev_type, type, strlen(dev_type) - 1))278{279if (!wl_check((void*)ifr))280break;281}282ifr->ifr_name[0] = '\0';283}284285fclose(fp);286}287/* This function is called by wl_get to execute either local dhd command288* or send a dhd command over wl transport289*/290static int291ioctl_queryinformation_fe(void *wl, int cmd, void* input_buf, int *input_len)292{293if (remote_type == NO_REMOTE) {294return dhd_ioctl(wl, cmd, input_buf, *input_len, FALSE);295} else {296return rwl_queryinformation_fe(wl, cmd, input_buf,297(unsigned long*)input_len, 0, RDHD_GET_IOCTL);298}299}300301/* This function is called by wl_set to execute either local dhd command302* or send a dhd command over wl transport303*/304static int305ioctl_setinformation_fe(void *wl, int cmd, void* buf, int *len)306{307if (remote_type == NO_REMOTE) {308return dhd_ioctl(wl, cmd, buf, *len, TRUE);309} else {310return rwl_setinformation_fe(wl, cmd, buf, (unsigned long*)len, 0, RDHD_SET_IOCTL);311312}313}314315/* The function is replica of wl_get in wlu_linux.c. Optimize when we have some316* common code between wlu_linux.c and dhdu_linux.c317*/318int319wl_get(void *wl, int cmd, void *buf, int len)320{321int error = BCME_OK;322/* For RWL: When interfacing to a Windows client, need t add in OID_BASE */323if ((rwl_os_type == WIN32_OS) && (remote_type != NO_REMOTE)) {324error = (int)ioctl_queryinformation_fe(wl, WL_OID_BASE + cmd, buf, &len);325} else {326error = (int)ioctl_queryinformation_fe(wl, cmd, buf, &len);327}328if (error == SERIAL_PORT_ERR)329return SERIAL_PORT_ERR;330331if (error != 0)332return IOCTL_ERROR;333334return error;335}336337/* The function is replica of wl_set in wlu_linux.c. Optimize when we have some338* common code between wlu_linux.c and dhdu_linux.c339*/340int341wl_set(void *wl, int cmd, void *buf, int len)342{343int error = BCME_OK;344345/* For RWL: When interfacing to a Windows client, need t add in OID_BASE */346if ((rwl_os_type == WIN32_OS) && (remote_type != NO_REMOTE)) {347error = (int)ioctl_setinformation_fe(wl, WL_OID_BASE + cmd, buf, &len);348} else {349error = (int)ioctl_setinformation_fe(wl, cmd, buf, &len);350}351352if (error == SERIAL_PORT_ERR)353return SERIAL_PORT_ERR;354355if (error != 0) {356return IOCTL_ERROR;357}358return error;359}360361int362wl_validatedev(void *dev_handle)363{364int retval = 1;365struct ifreq *ifr = (struct ifreq *)dev_handle;366/* validate the interface */367if (!ifr->ifr_name || wl_check((void *)ifr)) {368retval = 0;369}370return retval;371}372373/* Main client function374* The code is mostly from wlu_linux.c. This function takes care of executing remote dhd commands375* along with the local dhd commands now.376*/377int378#if defined(LIB)379dhd_main(int argc, char **argv)380#else381main(int argc, char **argv)382#endif383{384struct ifreq ifr;385char *ifname = NULL;386int err = 0;387int help = 0;388int status = CMD_DHD;389void* serialHandle = NULL;390391UNUSED_PARAMETER(argc);392393av0 = argv[0];394memset(&ifr, 0, sizeof(ifr));395argv++;396397if ((status = dhd_option(&argv, &ifname, &help)) == CMD_OPT) {398if (ifname)399strncpy(ifr.ifr_name, ifname, IFNAMSIZ);400}401/* Linux client looking for a Win32 server */402if (*argv && strncmp (*argv, "--wince", strlen(*argv)) == 0) {403rwl_os_type = WIN32_OS;404argv++;405}406407/* RWL socket transport Usage: --socket ipaddr [port num] */408if (*argv && strncmp (*argv, "--socket", strlen(*argv)) == 0) {409argv++;410411remote_type = REMOTE_SOCKET;412413if (!(*argv)) {414rwl_usage(remote_type);415return err;416}417g_rwl_servIP = *argv;418argv++;419420g_rwl_servport = DEFAULT_SERVER_PORT;421if ((*argv) && isdigit(**argv)) {422g_rwl_servport = atoi(*argv);423argv++;424}425}426427/* RWL from system serial port on client to uart dongle port on server */428/* Usage: --dongle /dev/ttyS0 */429if (*argv && strncmp (*argv, "--dongle", strlen(*argv)) == 0) {430argv++;431remote_type = REMOTE_DONGLE;432433if (!(*argv)) {434rwl_usage(remote_type);435return err;436}437g_rwl_device_name_serial = *argv;438argv++;439if ((serialHandle = rwl_open_pipe(remote_type, "\0", 0, 0)) == NULL) {440DPRINT_ERR(ERR, "serial device open error\r\n");441return BCME_ERROR;442}443ifr = (*(struct ifreq *)serialHandle);444}445446/* RWL over wifi. Usage: --wifi mac_address */447if (*argv && strncmp (*argv, "--wifi", strlen(*argv)) == 0) {448argv++;449remote_type = NO_REMOTE;450if (!ifr.ifr_name[0])451{452dhd_find(&ifr, "wl");453}454/* validate the interface */455if (!ifr.ifr_name[0] || wl_check((void*)&ifr)) {456fprintf(stderr, "%s: wl driver adapter not found\n", av0);457exit(1);458}459remote_type = REMOTE_WIFI;460461if (argc < 4) {462rwl_usage(remote_type);463return err;464}465/* copy server mac address to local buffer for later use by findserver cmd */466if (!dhd_ether_atoe(*argv, (struct ether_addr *)g_rwl_buf_mac)) {467fprintf(stderr,468"could not parse as an ethernet MAC address\n");469return FAIL;470}471argv++;472}473474/* Process for local dhd */475if (remote_type == NO_REMOTE) {476err = process_args(&ifr, argv);477return err;478}479480if (*argv) {481err = process_args(&ifr, argv);482if ((err == SERIAL_PORT_ERR) && (remote_type == REMOTE_DONGLE)) {483DPRINT_ERR(ERR, "\n Retry again\n");484err = process_args((struct ifreq*)&ifr, argv);485}486return err;487}488rwl_usage(remote_type);489490if (remote_type == REMOTE_DONGLE)491rwl_close_pipe(remote_type, (void*)&ifr);492493return err;494}495/*496* Function called for 'local' execution and for 'remote' non-interactive session497* (shell cmd, wl cmd) .The code is mostly from wlu_linux.c. This code can be498* common to wlu_linux.c and dhdu_linux.c499*/500static int501process_args(struct ifreq* ifr, char **argv)502{503char *ifname = NULL;504int help = 0;505int status = 0;506int err = BCME_OK;507cmd_t *cmd = NULL;508while (*argv) {509if ((strcmp (*argv, "sh") == 0) && (remote_type != NO_REMOTE)) {510argv++; /* Get the shell command */511if (*argv) {512/* Register handler in case of shell command only */513signal(SIGINT, ctrlc_handler);514err = rwl_shell_cmd_proc((void*)ifr, argv, SHELL_CMD);515} else {516DPRINT_ERR(ERR,517"Enter the shell command (e.g ls(Linux) or dir(Win CE) \n");518err = BCME_ERROR;519}520return err;521}522523if ((status = dhd_option(&argv, &ifname, &help)) == CMD_OPT) {524if (help)525break;526if (ifname)527strncpy(ifr->ifr_name, ifname, IFNAMSIZ);528continue;529}530/* parse error */531else if (status == CMD_ERR)532break;533534if (remote_type == NO_REMOTE) {535/* use default interface */536if (!ifr->ifr_name[0])537dhd_find(ifr, "dhd");538/* validate the interface */539if (!ifr->ifr_name[0] || dhd_check((void *)ifr)) {540if (strcmp("dldn", *argv) != 0) {541fprintf(stderr, "%s: dhd driver adapter not found\n", av0);542exit(BCME_ERROR);543}544}545546}547/* search for command */548cmd = dhd_find_cmd(*argv);549/* if not found, use default set_var and get_var commands */550if (!cmd) {551cmd = &dhd_varcmd;552}553554/* do command */555err = (*cmd->func)((void *) ifr, cmd, argv);556break;557} /* while loop end */558559/* provide for help on a particular command */560if (help && *argv) {561cmd = dhd_find_cmd(*argv);562if (cmd) {563dhd_cmd_usage(cmd);564} else {565DPRINT_ERR(ERR, "%s: Unrecognized command \"%s\", type -h for help\n",566av0, *argv);567}568} else if (!cmd)569dhd_usage(NULL);570else if (err == USAGE_ERROR)571dhd_cmd_usage(cmd);572else if (err == IOCTL_ERROR)573dhd_printlasterror((void *) ifr);574575return err;576}577578int579rwl_shell_createproc(void *wl)580{581UNUSED_PARAMETER(wl);582return fork();583}584585void586rwl_shell_killproc(int pid)587{588kill(pid, SIGKILL);589}590591#ifdef RWL_SOCKET592/* to validate hostname/ip given by the client */593int validate_server_address()594{595struct hostent *he;596struct ipv4_addr temp;597if (!dhd_atoip(g_rwl_servIP, &temp)) {598/* Wrong IP address format check for hostname */599if ((he = gethostbyname(g_rwl_servIP)) != NULL) {600if (!dhd_atoip(*he->h_addr_list, &temp)) {601g_rwl_servIP =602inet_ntoa(*(struct in_addr *)*he->h_addr_list);603if (g_rwl_servIP == NULL) {604DPRINT_ERR(ERR, "Error at inet_ntoa \n");605return FAIL;606}607} else {608DPRINT_ERR(ERR, "Error in IP address \n");609return FAIL;610}611} else {612DPRINT_ERR(ERR, "Enter correct IP address/hostname format\n");613return FAIL;614}615}616return SUCCESS;617}618#endif /* RWL_SOCKET */619620621