libsodium: Needed for Dnscrypto-proxy Release 1.3.0
[tomato.git] / release / src / router / et / et.c
blobafa539ac9e4b31fc90968d4565689f18cc20a5cc
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.9.130.4 2009/07/17 03:09:33 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;
62 if (ac < 2)
63 usage(av[0]);
65 optind = 1;
67 if (av[1][0] == '-') {
68 if ((av[1][1] != 'a') && (av[1][1] != 'i'))
69 usage(av[0]);
70 if (ac < 4)
71 usage(av[0]);
72 interface = av[2];
73 optind += 2;
76 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
77 syserr("socket");
79 if (interface)
80 strncpy(ifr.ifr_name, interface, sizeof (ifr.ifr_name));
81 else
82 et_find(s, &ifr);
84 if (!*ifr.ifr_name) {
85 fprintf(stderr, "et interface not found\n");
86 exit(1);
89 if (strcmp(av[optind], "up") == 0) {
90 if (ioctl(s, SIOCSETCUP, (caddr_t)&ifr) < 0)
91 syserr("etcup");
92 } else if (strcmp(av[optind], "down") == 0) {
93 if (ioctl(s, SIOCSETCDOWN, (caddr_t)&ifr) < 0)
94 syserr("etcdown");
95 } else if (strcmp(av[optind], "loop") == 0) {
96 if (optind >= (ac -1))
97 usage(av[0]);
98 arg = atoi(av[optind + 1]);
99 ifr.ifr_data = (caddr_t) &arg;
100 if (ioctl(s, SIOCSETCLOOP, (caddr_t)&ifr) < 0)
101 syserr("etcloop");
102 } else if (strcmp(av[optind], "dump") == 0) {
103 ifr.ifr_data = buf;
104 if (ioctl(s, SIOCGETCDUMP, (caddr_t)&ifr) < 0)
105 syserr("etcdump");
106 printf("%s\n", buf);
107 } else if (strcmp(av[optind], "msglevel") == 0) {
108 if (optind >= (ac -1))
109 usage(av[0]);
110 arg = strtol(av[optind + 1], &endptr, 0);
111 ifr.ifr_data = (caddr_t) &arg;
112 if (ioctl(s, SIOCSETCSETMSGLEVEL, (caddr_t)&ifr) < 0)
113 syserr("etcsetmsglevel");
114 } else if (strcmp(av[optind], "promisc") == 0) {
115 if (optind >= (ac -1))
116 usage(av[0]);
117 arg = atoi(av[optind + 1]);
118 ifr.ifr_data = (caddr_t) &arg;
119 if (ioctl(s, SIOCSETCPROMISC, (caddr_t)&ifr) < 0)
120 syserr("etcpromisc");
121 } else if (strcmp(av[optind], "qos") == 0) {
122 if (optind >= (ac -1))
123 usage(av[0]);
124 arg = atoi(av[optind + 1]);
125 ifr.ifr_data = (caddr_t) &arg;
126 if (ioctl(s, SIOCSETCQOS, (caddr_t)&ifr) < 0)
127 syserr("etcqos");
128 } else if (strcmp(av[optind], "speed") == 0) {
129 if (optind >= (ac -1))
130 usage(av[0]);
131 if (strcmp(av[optind+1], "auto") == 0)
132 arg = -1;
133 else if (strcmp(av[optind+1], "10half") == 0)
134 arg = 0;
135 else if (strcmp(av[optind+1], "10full") == 0)
136 arg = 1;
137 else if (strcmp(av[optind+1], "100half") == 0)
138 arg = 2;
139 else if (strcmp(av[optind+1], "100full") == 0)
140 arg = 3;
141 else if (strcmp(av[optind+1], "1000full") == 0)
142 arg = 5;
143 else
144 usage(av[0]);
146 ifr.ifr_data = (caddr_t) &arg;
147 if (ioctl(s, SIOCSETCSPEED, (caddr_t)&ifr) < 0)
148 syserr("etcspeed");
150 else if (strcmp(av[optind], "phyrd") == 0) {
151 int cmd = -1;
153 if ((ac < (optind + 2)) || (ac > (optind + 3))) {
154 usage(av[0]);
155 } else if (ac == (optind + 3)) {
156 /* PHY address provided */
157 vecarg[0] = strtoul(av[optind + 1], NULL, 0) << 16;;
158 vecarg[0] |= strtoul(av[optind + 2], NULL, 0) & 0xffff;
159 cmd = SIOCGETCPHYRD2;
160 } else {
161 /* "My" PHY address implied */
162 vecarg[0] = strtoul(av[optind + 1], NULL, 0);
163 cmd = SIOCGETCPHYRD;
165 ifr.ifr_data = (caddr_t) vecarg;
166 if (ioctl(s, cmd, (caddr_t)&ifr) < 0)
167 syserr("etcphyrd");
169 printf("000x%04x\n", vecarg[1]);
170 } else if (strcmp(av[optind], "phywr") == 0) {
171 int cmd = -1;
173 if ((ac < (optind + 3)) || (ac > (optind + 4))) {
174 usage(av[0]);
175 } else if (ac == (optind + 4)) {
176 vecarg[0] = strtoul(av[optind + 1], NULL, 0) << 16;;
177 vecarg[0] |= strtoul(av[optind + 2], NULL, 0) & 0xffff;
178 vecarg[1] = strtoul(av[optind + 3], NULL, 0);
179 cmd = SIOCSETCPHYWR2;
180 } else {
181 vecarg[0] = strtoul(av[optind + 1], NULL, 0);
182 vecarg[1] = strtoul(av[optind + 2], NULL, 0);
183 cmd = SIOCSETCPHYWR;
185 ifr.ifr_data = (caddr_t) vecarg;
186 if (ioctl(s, cmd, (caddr_t)&ifr) < 0)
187 syserr("etcphywr");
188 } else if (strcmp(av[optind], "robord") == 0) {
189 if (ac != (optind + 3))
190 usage(av[0]);
192 vecarg[0] = strtoul(av[optind + 1], NULL, 0) << 16;;
193 vecarg[0] |= strtoul(av[optind + 2], NULL, 0) & 0xffff;
195 ifr.ifr_data = (caddr_t) vecarg;
196 if (ioctl(s, SIOCGETCROBORD, (caddr_t)&ifr) < 0)
197 syserr("etcrobord");
199 printf("000x%04x\n", vecarg[1]);
200 } else if (strcmp(av[optind], "robowr") == 0) {
201 if (ac != (optind + 4))
202 usage(av[0]);
204 vecarg[0] = strtoul(av[optind + 1], NULL, 0) << 16;;
205 vecarg[0] |= strtoul(av[optind + 2], NULL, 0) & 0xffff;
206 vecarg[1] = strtoul(av[optind + 3], NULL, 0);
208 ifr.ifr_data = (caddr_t) vecarg;
209 if (ioctl(s, SIOCSETCROBOWR, (caddr_t)&ifr) < 0)
210 syserr("etcrobowr");
211 #ifdef IOV_ET_CLEAR_DUMP
212 } else if (strcmp(av[optind], "clear_dump") == 0) {
213 et_var_t var;
215 if ((ac > (optind + 2)))
216 usage(av[0]);
218 var.set = 1;
219 var.cmd = IOV_ET_CLEAR_DUMP;
220 var.buf = NULL;
221 ifr.ifr_data = (caddr_t) &var;
222 if (ioctl(s, SIOCSETGETVAR, (caddr_t)&ifr) < 0)
223 syserr("etccleardump");
224 #endif
225 } else {
226 #ifdef IOV_ET_POWER_SAVE_MODE
227 if (strcmp(av[optind], "switch_mode") == 0) {
228 int all = 0;
229 et_var_t var;
231 /* GET case */
232 if (ac == (optind + 1)) {
233 var.set = 0;
234 vecarg[0] = VECLEN;
235 all = 1;
236 } else if (ac == (optind + 2)) {
237 var.set = 0;
238 vecarg[0] = strtoul(av[optind + 1], NULL, 0);
239 all = (int)(vecarg[0] == VECLEN);
240 } else {
241 if (ac != (optind + 3))
242 usage(av[0]);
244 vecarg[0] = strtoul(av[optind + 1], NULL, 0);
245 vecarg[1] = strtoul(av[optind + 2], NULL, 0);
246 if (vecarg[1] > 3)
247 usage(av[0]);
249 var.set = 1;
252 var.len = VECLEN * sizeof(int);
253 var.cmd = IOV_ET_POWER_SAVE_MODE;
254 var.buf = &vecarg;
256 ifr.ifr_data = (caddr_t) &var;
257 if (ioctl(s, SIOCSETGETVAR, (caddr_t)&ifr) < 0)
258 syserr("etcswitchmode");
260 if (!var.set) {
261 if (all)
262 printf("phy power save mode for all phys:"
263 " %d %d %d %d %d \n",
264 vecarg[0], vecarg[1], vecarg[2],
265 vecarg[3], vecarg[4]);
266 else
267 printf("phy power save mode for phy %d mode %d\n",
268 vecarg[0], vecarg[1]);
270 } else
271 #endif // IOV_ET_POWER_SAVE_MODE
273 usage(av[0]);
277 return (0);
280 static void
281 usage(char *av0)
283 fprintf(stderr, "usage: %s [ [ -a | -i ] interface ] and one of:\n"
284 "\tup\n"
285 "\tdown\n"
286 "\tloop <0 or 1>\n"
287 "\tdump\n"
288 "\tclear_dump\n"
289 "\tmsglevel <bitvec> (error=1, trace=2, prhdr=4, prpkt=8)\n"
290 "\tpromisc <0 or 1>\n"
291 "\tqos <0 or 1>\n"
292 "\tspeed <auto, 10half, 10full, 100half, 100full, 1000full>\n"
293 "\tphyrd [<phyaddr>] <reg>\n"
294 "\tphywr [<phyaddr>] <reg> <val>\n"
295 "\trobord <page> <reg>\n"
296 "\trobowr <page> <reg> <val>\n"
297 #ifdef IOV_ET_POWER_SAVE_MODE
298 "\tswitch_mode <phy> <mode> (mode 0, 1, 2, 3)\n"
299 #endif
301 av0);
302 exit(1);
305 static void
306 et_find(int s, struct ifreq *ifr)
308 char proc_net_dev[] = "/proc/net/dev";
309 FILE *fp;
310 char buf[512], *c, *name;
312 ifr->ifr_name[0] = '\0';
314 /* eat first two lines */
315 if (!(fp = fopen(proc_net_dev, "r")) ||
316 !fgets(buf, sizeof(buf), fp) ||
317 !fgets(buf, sizeof(buf), fp))
318 return;
320 while (fgets(buf, sizeof(buf), fp)) {
321 c = buf;
322 while (isspace(*c))
323 c++;
324 if (!(name = strsep(&c, ":")))
325 continue;
326 strncpy(ifr->ifr_name, name, IFNAMSIZ);
327 if (et_check(s, ifr) == 0)
328 break;
329 ifr->ifr_name[0] = '\0';
332 fclose(fp);
335 static int
336 et_check(int s, struct ifreq *ifr)
338 struct ethtool_drvinfo info;
340 memset(&info, 0, sizeof(info));
341 info.cmd = ETHTOOL_GDRVINFO;
342 ifr->ifr_data = (caddr_t)&info;
343 if (ioctl(s, SIOCETHTOOL, (caddr_t)ifr) < 0) {
344 /* print a good diagnostic if not superuser */
345 if (errno == EPERM)
346 syserr("siocethtool");
347 return (-1);
350 if (!strncmp(info.driver, "et", 2))
351 return (0);
352 else if (!strncmp(info.driver, "bcm57", 5))
353 return (0);
355 return (-1);
358 static void
359 syserr(char *s)
361 perror(s);
362 exit(1);