/* * Linux port of dhd command line utility, hacked from wl utility. * * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that * you also meet, for each linked independent module, the terms and conditions of * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * * $Id: dhdu_linux.c,v 1.3.10.2.2.3 2009/01/27 01:02:28 Exp $ */ #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 <sys/ioctl.h> #include <net/if.h> typedef u_int64_t u64; typedef u_int32_t u32; typedef u_int16_t u16; typedef u_int8_t u8; #include <linux/sockios.h> #include <linux/ethtool.h> #include <typedefs.h> #include <dhdioctl.h> #include "dhdu.h" #define DEV_TYPE_LEN 4 /* length for devtype 'dhd' */ static void syserr(char *s) { fprintf(stderr, "%s: ", dhdu_av0); perror(s); exit(errno); } static int dhd_ioctl(void *dhd, int cmd, void *buf, int len, bool set) { struct ifreq *ifr = (struct ifreq *)dhd; dhd_ioctl_t ioc; int ret = 0; int s; /* open socket to kernel */ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) syserr("socket"); /* do it */ ioc.cmd = cmd; ioc.buf = buf; ioc.len = len; ioc.set = set; ioc.driver = DHD_IOCTL_MAGIC; ifr->ifr_data = (caddr_t) &ioc; if ((ret = ioctl(s, SIOCDEVPRIVATE, ifr)) < 0) { if (cmd != DHD_GET_MAGIC) { ret = IOCTL_ERROR; } } /* cleanup */ close(s); return ret; } static int dhd_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; strcpy(info.driver, "?dhd"); 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("dhd_get_dev_type"); *(char *)buf = '\0'; } else strncpy(buf, info.driver, len); close(s); return ret; } int dhd_get(void *dhd, int cmd, void *buf, int len) { return dhd_ioctl(dhd, cmd, buf, len, FALSE); } int dhd_set(void *dhd, int cmd, void *buf, int len) { return dhd_ioctl(dhd, cmd, buf, len, TRUE); } void dhd_find(struct ifreq *ifr) { char proc_net_dev[] = "/proc/net/dev"; FILE *fp; char buf[1000], *c, *name; char dev_type[DEV_TYPE_LEN]; ifr->ifr_name[0] = '\0'; /* eat first two lines */ if (!(fp = fopen(proc_net_dev, "r")) || !fgets(buf, sizeof(buf), fp) || !fgets(buf, sizeof(buf), fp)) return; while (fgets(buf, sizeof(buf), fp)) { c = buf; while (isspace(*c)) c++; if (!(name = strsep(&c, ":"))) continue; strncpy(ifr->ifr_name, name, IFNAMSIZ); if (dhd_get_dev_type(name, dev_type, DEV_TYPE_LEN) >= 0 && !strncmp(dev_type, "dhd", 3)) if (dhd_check((void *)ifr) == 0) break; ifr->ifr_name[0] = '\0'; } fclose(fp); } int main(int argc, char **argv) { struct ifreq ifr; cmd_t *cmd = NULL; int err = 0; char *ifname = NULL; int help = 0; int status = CMD_DHD; UNUSED_PARAMETER(argc); dhdu_av0 = argv[0]; memset(&ifr, 0, sizeof(ifr)); for (++argv; *argv;) { /* command option */ if ((status = dhd_option(&argv, &ifname, &help)) == CMD_OPT) { if (help) break; if (ifname) { if (strlen(ifname) > IFNAMSIZ) { fprintf(stderr, "%s: interface name too long\n", dhdu_av0); break; } strncpy(ifr.ifr_name, ifname, IFNAMSIZ); } continue; } /* parse error */ else if (status == CMD_ERR) break; /* use default if no interface specified */ if (!*ifr.ifr_name) dhd_find(&ifr); /* validate the interface */ if (!*ifr.ifr_name || dhd_check((void *)&ifr)) { fprintf(stderr, "%s: dhd driver adapter not found\n", dhdu_av0); exit(1); } /* search for command */ for (cmd = dhd_cmds; cmd->name && strcmp(cmd->name, *argv); cmd++); /* defaults to using the set_var and get_var commands */ if (cmd->name == NULL) cmd = &dhd_varcmd; /* do command */ if (cmd->name) err = (*cmd->func)((void *)&ifr, cmd, argv); break; } /* In case of COMMAND_ERROR, command has already printed an error message */ if (!cmd) dhd_usage(NULL); else if (err == USAGE_ERROR) dhd_cmd_usage(cmd); else if (err == IOCTL_ERROR) dhd_printlasterror((void *)&ifr); return err; }