1 /* 2 * Linux port of dhd command line utility, hacked from wl utility. 3 * 4 * Copyright (C) 1999-2010, Broadcom Corporation 5 * 6 * Unless you and Broadcom execute a separate written software license 7 * agreement governing use of this software, this software is licensed to you 8 * under the terms of the GNU General Public License version 2 (the "GPL"), 9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the 10 * following added to such license: 11 * 12 * As a special exception, the copyright holders of this software give you 13 * permission to link this software with independent modules, and to copy and 14 * distribute the resulting executable under terms of your choice, provided that 15 * you also meet, for each linked independent module, the terms and conditions of 16 * the license of that module. An independent module is a module which is not 17 * derived from this software. The special exception does not apply to any 18 * modifications of the software. 19 * 20 * Notwithstanding the above, under no circumstances may you combine this 21 * software in any way with any other Broadcom software provided under a license 22 * other than the GPL, without Broadcom's express prior written consent. 23 * 24 * $Id: dhdu_linux.c,v 1.3.10.2.2.3 2009/01/27 01:02:28 Exp $ 25 */ 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <unistd.h> 30 #include <ctype.h> 31 #include <string.h> 32 #include <errno.h> 33 #ifndef TARGETENV_android 34 #include <error.h> 35 #endif /* TARGETENV_android */ 36 #include <sys/types.h> 37 #include <sys/socket.h> 38 #include <sys/ioctl.h> 39 #include <net/if.h> 40 41 42 typedef u_int64_t u64; 43 typedef u_int32_t u32; 44 typedef u_int16_t u16; 45 typedef u_int8_t u8; 46 #include <linux/sockios.h> 47 #include <linux/ethtool.h> 48 49 #include <typedefs.h> 50 #include <dhdioctl.h> 51 #include "dhdu.h" 52 53 #define DEV_TYPE_LEN 4 /* length for devtype 'dhd' */ 54 55 static void 56 syserr(char *s) 57 { 58 fprintf(stderr, "%s: ", dhdu_av0); 59 perror(s); 60 exit(errno); 61 } 62 63 static int 64 dhd_ioctl(void *dhd, int cmd, void *buf, int len, bool set) 65 { 66 struct ifreq *ifr = (struct ifreq *)dhd; 67 dhd_ioctl_t ioc; 68 int ret = 0; 69 int s; 70 71 /* open socket to kernel */ 72 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 73 syserr("socket"); 74 75 /* do it */ 76 ioc.cmd = cmd; 77 ioc.buf = buf; 78 ioc.len = len; 79 ioc.set = set; 80 ioc.driver = DHD_IOCTL_MAGIC; 81 ifr->ifr_data = (caddr_t) &ioc; 82 if ((ret = ioctl(s, SIOCDEVPRIVATE, ifr)) < 0) { 83 if (cmd != DHD_GET_MAGIC) { 84 ret = IOCTL_ERROR; 85 } 86 } 87 88 /* cleanup */ 89 close(s); 90 return ret; 91 } 92 93 static int 94 dhd_get_dev_type(char *name, void *buf, int len) 95 { 96 int s; 97 int ret; 98 struct ifreq ifr; 99 struct ethtool_drvinfo info; 100 101 /* open socket to kernel */ 102 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 103 syserr("socket"); 104 105 /* get device type */ 106 memset(&info, 0, sizeof(info)); 107 info.cmd = ETHTOOL_GDRVINFO; 108 strcpy(info.driver, "?dhd"); 109 ifr.ifr_data = (caddr_t)&info; 110 strncpy(ifr.ifr_name, name, IFNAMSIZ); 111 if ((ret = ioctl(s, SIOCETHTOOL, &ifr)) < 0) { 112 113 /* print a good diagnostic if not superuser */ 114 if (errno == EPERM) 115 syserr("dhd_get_dev_type"); 116 117 *(char *)buf = '\0'; 118 } 119 else 120 strncpy(buf, info.driver, len); 121 122 close(s); 123 return ret; 124 } 125 126 int 127 dhd_get(void *dhd, int cmd, void *buf, int len) 128 { 129 return dhd_ioctl(dhd, cmd, buf, len, FALSE); 130 } 131 132 int 133 dhd_set(void *dhd, int cmd, void *buf, int len) 134 { 135 return dhd_ioctl(dhd, cmd, buf, len, TRUE); 136 } 137 138 void 139 dhd_find(struct ifreq *ifr) 140 { 141 char proc_net_dev[] = "/proc/net/dev"; 142 FILE *fp; 143 char buf[1000], *c, *name; 144 char dev_type[DEV_TYPE_LEN]; 145 146 ifr->ifr_name[0] = '\0'; 147 148 /* eat first two lines */ 149 if (!(fp = fopen(proc_net_dev, "r")) || 150 !fgets(buf, sizeof(buf), fp) || 151 !fgets(buf, sizeof(buf), fp)) 152 return; 153 154 while (fgets(buf, sizeof(buf), fp)) { 155 c = buf; 156 while (isspace(*c)) 157 c++; 158 if (!(name = strsep(&c, ":"))) 159 continue; 160 strncpy(ifr->ifr_name, name, IFNAMSIZ); 161 if (dhd_get_dev_type(name, dev_type, DEV_TYPE_LEN) >= 0 && 162 !strncmp(dev_type, "dhd", 3)) 163 if (dhd_check((void *)ifr) == 0) 164 break; 165 ifr->ifr_name[0] = '\0'; 166 } 167 168 fclose(fp); 169 } 170 171 int 172 main(int argc, char **argv) 173 { 174 struct ifreq ifr; 175 cmd_t *cmd = NULL; 176 int err = 0; 177 char *ifname = NULL; 178 int help = 0; 179 int status = CMD_DHD; 180 181 UNUSED_PARAMETER(argc); 182 183 dhdu_av0 = argv[0]; 184 185 memset(&ifr, 0, sizeof(ifr)); 186 187 for (++argv; *argv;) { 188 189 /* command option */ 190 if ((status = dhd_option(&argv, &ifname, &help)) == CMD_OPT) { 191 if (help) 192 break; 193 if (ifname) { 194 if (strlen(ifname) > IFNAMSIZ) { 195 fprintf(stderr, "%s: interface name too long\n", dhdu_av0); 196 break; 197 } 198 strncpy(ifr.ifr_name, ifname, IFNAMSIZ); 199 } 200 continue; 201 } 202 203 /* parse error */ 204 else if (status == CMD_ERR) 205 break; 206 207 /* use default if no interface specified */ 208 if (!*ifr.ifr_name) 209 dhd_find(&ifr); 210 /* validate the interface */ 211 if (!*ifr.ifr_name || dhd_check((void *)&ifr)) { 212 fprintf(stderr, "%s: dhd driver adapter not found\n", dhdu_av0); 213 exit(1); 214 } 215 216 /* search for command */ 217 for (cmd = dhd_cmds; cmd->name && strcmp(cmd->name, *argv); cmd++); 218 219 /* defaults to using the set_var and get_var commands */ 220 if (cmd->name == NULL) 221 cmd = &dhd_varcmd; 222 223 /* do command */ 224 if (cmd->name) 225 err = (*cmd->func)((void *)&ifr, cmd, argv); 226 break; 227 } 228 229 /* In case of COMMAND_ERROR, command has already printed an error message */ 230 if (!cmd) 231 dhd_usage(NULL); 232 else if (err == USAGE_ERROR) 233 dhd_cmd_usage(cmd); 234 else if (err == IOCTL_ERROR) 235 dhd_printlasterror((void *)&ifr); 236 237 return err; 238 } 239