1 /*
2 * Linux port of dhd command line utility, hacked from wl utility.
3 *
4 * Copyright (C) 1999-2009, 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
syserr(char * s)56 syserr(char *s)
57 {
58 fprintf(stderr, "%s: ", dhdu_av0);
59 perror(s);
60 exit(errno);
61 }
62
63 static int
dhd_ioctl(void * dhd,int cmd,void * buf,int len,bool set)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
dhd_get_dev_type(char * name,void * buf,int len)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
dhd_get(void * dhd,int cmd,void * buf,int len)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
dhd_set(void * dhd,int cmd,void * buf,int len)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
dhd_find(struct ifreq * ifr)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
main(int argc,char ** argv)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