K2.6 patches and update.
[tomato.git] / release / src-rt / et / linux / et.c
blobc4ce9397b4a8a8b2786bf8cb9a709482095da500
1 /*
2 * et driver ioctl swiss army knife command.
4 * Copyright (C) 2010, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
8 * the contents of this file may not be disclosed to third parties, copied
9 * or duplicated in any form, in whole or in part, without the prior
10 * written permission of Broadcom Corporation.
12 * $Id: et.c,v 1.13.18.1 2010-07-01 23:24:02 Exp $
15 #include <stdio.h>
17 #include <sys/param.h>
18 #include <sys/ioctl.h>
19 #include <sys/socket.h>
20 #include <sys/sysctl.h>
21 #include <sys/time.h>
22 #include <net/if.h>
23 #include <netinet/in.h>
24 #include <typedefs.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <errno.h>
28 #include <stdlib.h>
29 #include <etioctl.h>
30 #include <proto/ethernet.h>
31 #include <linux/types.h>
33 typedef u_int64_t u64;
34 typedef u_int32_t u32;
35 typedef u_int16_t u16;
36 typedef u_int8_t u8;
37 #include <linux/sockios.h>
38 #include <linux/ethtool.h>
40 static void usage(char *av0);
41 static void syserr(char *s);
42 static void et_find(int s, struct ifreq *ifr);
43 static int et_check(int s, struct ifreq *ifr);
47 char buf[16 * 1024];
49 #define VECLEN 5
51 int
52 main(int ac, char *av[])
54 char *interface = NULL;
55 struct ifreq ifr;
56 char *endptr;
57 int arg;
58 int vecarg[VECLEN];
59 int s;
60 static int optind;
61 et_var_t var;
63 if (ac < 2)
64 usage(av[0]);
66 optind = 1;
68 if (av[1][0] == '-') {
69 if ((av[1][1] != 'a') && (av[1][1] != 'i'))
70 usage(av[0]);
71 if (ac < 4)
72 usage(av[0]);
73 interface = av[2];
74 optind += 2;
77 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
78 syserr("socket");
80 if (interface)
81 strncpy(ifr.ifr_name, interface, sizeof (ifr.ifr_name));
82 else
83 et_find(s, &ifr);
85 if (!*ifr.ifr_name) {
86 fprintf(stderr, "et interface not found\n");
87 exit(1);
90 if (strcmp(av[optind], "up") == 0) {
91 if (ioctl(s, SIOCSETCUP, (caddr_t)&ifr) < 0)
92 syserr("etcup");
93 } else if (strcmp(av[optind], "down") == 0) {
94 if (ioctl(s, SIOCSETCDOWN, (caddr_t)&ifr) < 0)
95 syserr("etcdown");
96 } else if (strcmp(av[optind], "loop") == 0) {
97 if (optind >= (ac -1))
98 usage(av[0]);
99 arg = atoi(av[optind + 1]);
100 ifr.ifr_data = (caddr_t) &arg;
101 if (ioctl(s, SIOCSETCLOOP, (caddr_t)&ifr) < 0)
102 syserr("etcloop");
103 } else if (strcmp(av[optind], "dump") == 0) {
104 ifr.ifr_data = buf;
105 if (ioctl(s, SIOCGETCDUMP, (caddr_t)&ifr) < 0)
106 syserr("etcdump");
107 printf("%s\n", buf);
108 } else if (strcmp(av[optind], "msglevel") == 0) {
109 if (optind >= (ac -1))
110 usage(av[0]);
111 arg = strtol(av[optind + 1], &endptr, 0);
112 ifr.ifr_data = (caddr_t) &arg;
113 if (ioctl(s, SIOCSETCSETMSGLEVEL, (caddr_t)&ifr) < 0)
114 syserr("etcsetmsglevel");
115 } else if (strcmp(av[optind], "promisc") == 0) {
116 if (optind >= (ac -1))
117 usage(av[0]);
118 arg = atoi(av[optind + 1]);
119 ifr.ifr_data = (caddr_t) &arg;
120 if (ioctl(s, SIOCSETCPROMISC, (caddr_t)&ifr) < 0)
121 syserr("etcpromisc");
122 } else if (strcmp(av[optind], "qos") == 0) {
123 if (optind >= (ac -1))
124 usage(av[0]);
125 arg = atoi(av[optind + 1]);
126 ifr.ifr_data = (caddr_t) &arg;
127 if (ioctl(s, SIOCSETCQOS, (caddr_t)&ifr) < 0)
128 syserr("etcqos");
129 } else if (strcmp(av[optind], "speed") == 0) {
130 if (optind >= (ac -1))
131 usage(av[0]);
132 if (strcmp(av[optind+1], "auto") == 0)
133 arg = -1;
134 else if (strcmp(av[optind+1], "10half") == 0)
135 arg = 0;
136 else if (strcmp(av[optind+1], "10full") == 0)
137 arg = 1;
138 else if (strcmp(av[optind+1], "100half") == 0)
139 arg = 2;
140 else if (strcmp(av[optind+1], "100full") == 0)
141 arg = 3;
142 else if (strcmp(av[optind+1], "1000full") == 0)
143 arg = 5;
144 else
145 usage(av[0]);
147 ifr.ifr_data = (caddr_t) &arg;
148 if (ioctl(s, SIOCSETCSPEED, (caddr_t)&ifr) < 0)
149 syserr("etcspeed");
151 else if (strcmp(av[optind], "phyrd") == 0) {
152 int cmd = -1;
154 if ((ac < (optind + 2)) || (ac > (optind + 3))) {
155 usage(av[0]);
156 } else if (ac == (optind + 3)) {
157 /* PHY address provided */
158 vecarg[0] = strtoul(av[optind + 1], NULL, 0) << 16;;
159 vecarg[0] |= strtoul(av[optind + 2], NULL, 0) & 0xffff;
160 cmd = SIOCGETCPHYRD2;
161 } else {
162 /* "My" PHY address implied */
163 vecarg[0] = strtoul(av[optind + 1], NULL, 0);
164 cmd = SIOCGETCPHYRD;
166 ifr.ifr_data = (caddr_t) vecarg;
167 if (ioctl(s, cmd, (caddr_t)&ifr) < 0)
168 syserr("etcphyrd");
170 printf("0x%04x\n", vecarg[1]);
171 } else if (strcmp(av[optind], "phywr") == 0) {
172 int cmd = -1;
174 if ((ac < (optind + 3)) || (ac > (optind + 4))) {
175 usage(av[0]);
176 } else if (ac == (optind + 4)) {
177 vecarg[0] = strtoul(av[optind + 1], NULL, 0) << 16;;
178 vecarg[0] |= strtoul(av[optind + 2], NULL, 0) & 0xffff;
179 vecarg[1] = strtoul(av[optind + 3], NULL, 0);
180 cmd = SIOCSETCPHYWR2;
181 } else {
182 vecarg[0] = strtoul(av[optind + 1], NULL, 0);
183 vecarg[1] = strtoul(av[optind + 2], NULL, 0);
184 cmd = SIOCSETCPHYWR;
186 ifr.ifr_data = (caddr_t) vecarg;
187 if (ioctl(s, cmd, (caddr_t)&ifr) < 0)
188 syserr("etcphywr");
189 } else if (strcmp(av[optind], "robord") == 0) {
190 if (ac != (optind + 3))
191 usage(av[0]);
193 vecarg[0] = strtoul(av[optind + 1], NULL, 0) << 16;;
194 vecarg[0] |= strtoul(av[optind + 2], NULL, 0) & 0xffff;
196 ifr.ifr_data = (caddr_t) vecarg;
197 if (ioctl(s, SIOCGETCROBORD, (caddr_t)&ifr) < 0)
198 syserr("etcrobord");
200 printf("0x%04x\n", vecarg[1]);
201 } else if (strcmp(av[optind], "robowr") == 0) {
202 if (ac != (optind + 4))
203 usage(av[0]);
205 vecarg[0] = strtoul(av[optind + 1], NULL, 0) << 16;;
206 vecarg[0] |= strtoul(av[optind + 2], NULL, 0) & 0xffff;
207 vecarg[1] = strtoul(av[optind + 3], NULL, 0);
209 ifr.ifr_data = (caddr_t) vecarg;
210 if (ioctl(s, SIOCSETCROBOWR, (caddr_t)&ifr) < 0)
211 syserr("etcrobowr");
212 } else if (strcmp(av[optind], "clear_dump") == 0) {
213 if ((ac > (optind + 2)))
214 usage(av[0]);
216 var.set = 1;
217 var.cmd = IOV_ET_CLEAR_DUMP;
218 var.buf = NULL;
219 ifr.ifr_data = (caddr_t) &var;
220 if (ioctl(s, SIOCSETGETVAR, (caddr_t)&ifr) < 0)
221 syserr("etccleardump");
222 } else {
223 if (strcmp(av[optind], "switch_mode") == 0) {
224 int all = 0;
226 /* GET case */
227 if (ac == (optind + 1)) {
228 var.set = 0;
229 vecarg[0] = VECLEN;
230 all = 1;
231 } else if (ac == (optind + 2)) {
232 var.set = 0;
233 vecarg[0] = strtoul(av[optind + 1], NULL, 0);
234 all = (int)(vecarg[0] == VECLEN);
235 } else {
236 if (ac != (optind + 3))
237 usage(av[0]);
239 vecarg[0] = strtoul(av[optind + 1], NULL, 0);
240 vecarg[1] = strtoul(av[optind + 2], NULL, 0);
241 if (vecarg[1] > 3)
242 usage(av[0]);
244 var.set = 1;
247 var.len = VECLEN * sizeof(int);
248 var.cmd = IOV_ET_POWER_SAVE_MODE;
249 var.buf = &vecarg;
251 ifr.ifr_data = (caddr_t) &var;
252 if (ioctl(s, SIOCSETGETVAR, (caddr_t)&ifr) < 0)
253 syserr("etcswitchmode");
255 if (!var.set) {
256 if (all)
257 printf("phy power save mode for all phys:"
258 " %d %d %d %d %d \n",
259 vecarg[0], vecarg[1], vecarg[2],
260 vecarg[3], vecarg[4]);
261 else
262 printf("phy power save mode for phy %d mode %d\n",
263 vecarg[0], vecarg[1]);
265 } else {
266 usage(av[0]);
270 return (0);
273 static void
274 usage(char *av0)
276 fprintf(stderr, "usage: %s [ [ -a | -i ] interface ] and one of:\n"
277 "\tup\n"
278 "\tdown\n"
279 "\tloop <0 or 1>\n"
280 "\tdump\n"
281 "\tclear_dump\n"
282 "\tmsglevel <bitvec> (error=1, trace=2, prhdr=4, prpkt=8)\n"
283 "\tpromisc <0 or 1>\n"
284 "\tqos <0 or 1>\n"
285 "\tspeed <auto, 10half, 10full, 100half, 100full, 1000full>\n"
286 "\tphyrd [<phyaddr>] <reg>\n"
287 "\tphywr [<phyaddr>] <reg> <val>\n"
288 "\trobord <page> <reg>\n"
289 "\trobowr <page> <reg> <val>\n"
290 "\tswitch_mode <phy> <mode> (mode 0, 1, 2, 3)\n"
292 av0);
293 exit(1);
296 static void
297 et_find(int s, struct ifreq *ifr)
299 char proc_net_dev[] = "/proc/net/dev";
300 FILE *fp;
301 char buf[512], *c, *name;
303 ifr->ifr_name[0] = '\0';
305 /* eat first two lines */
306 if (!(fp = fopen(proc_net_dev, "r")) ||
307 !fgets(buf, sizeof(buf), fp) ||
308 !fgets(buf, sizeof(buf), fp))
309 return;
311 while (fgets(buf, sizeof(buf), fp)) {
312 c = buf;
313 while (isspace(*c))
314 c++;
315 if (!(name = strsep(&c, ":")))
316 continue;
317 strncpy(ifr->ifr_name, name, IFNAMSIZ);
318 if (et_check(s, ifr) == 0)
319 break;
320 ifr->ifr_name[0] = '\0';
323 fclose(fp);
326 static int
327 et_check(int s, struct ifreq *ifr)
329 struct ethtool_drvinfo info;
331 memset(&info, 0, sizeof(info));
332 info.cmd = ETHTOOL_GDRVINFO;
333 ifr->ifr_data = (caddr_t)&info;
334 if (ioctl(s, SIOCETHTOOL, (caddr_t)ifr) < 0) {
335 /* print a good diagnostic if not superuser */
336 if (errno == EPERM)
337 syserr("siocethtool");
338 return (-1);
341 if (!strncmp(info.driver, "et", 2))
342 return (0);
343 else if (!strncmp(info.driver, "bcm57", 5))
344 return (0);
346 return (-1);
349 static void
350 syserr(char *s)
352 perror(s);
353 exit(1);