1/*
2 * et driver ioctl swiss army knife command.
3 *
4 * Copyright 2007, 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.
11 *
12 * $Id: et.c,v 1.1.1.1 2008/10/15 03:25:54 james26_jang Exp $
13 */
14
15#include <stdio.h>
16
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
32typedef u_int64_t u64;
33typedef u_int32_t u32;
34typedef u_int16_t u16;
35typedef u_int8_t u8;
36#include <linux/sockios.h>
37#include <linux/ethtool.h>
38
39static void usage(char *av0);
40static void syserr(char *s);
41static void et_find(int s, struct ifreq *ifr);
42static int et_check(int s, struct ifreq *ifr);
43
44
45
46char buf[16 * 1024];
47
48#define VECLEN		2
49
50static int optind;
51
52int
53main(int ac, char *av[])
54{
55	char *interface = NULL;
56	struct ifreq ifr;
57	char *endptr;
58	int arg;
59	int vecarg[VECLEN];
60	int s;
61
62	if (ac < 2)
63		usage(av[0]);
64
65	optind = 1;
66
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;
74	}
75
76	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
77		syserr("socket");
78
79	if (interface)
80		strncpy(ifr.ifr_name, interface, sizeof (ifr.ifr_name));
81	else
82		et_find(s, &ifr);
83
84	if (!*ifr.ifr_name) {
85		fprintf(stderr, "et interface not found\n");
86		exit(1);
87	}
88
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], "txdown") == 0) {
129		if (ioctl(s, SIOCSETCTXDOWN, (caddr_t)&ifr) < 0)
130			syserr("etctxdown");
131	} else if (strcmp(av[optind], "speed") == 0) {
132		if (optind >= (ac -1))
133			usage(av[0]);
134		if (strcmp(av[optind+1], "auto") == 0)
135			arg = -1;
136		else if (strcmp(av[optind+1], "10half") == 0)
137			arg = 0;
138		else if (strcmp(av[optind+1], "10full") == 0)
139			arg = 1;
140		else if (strcmp(av[optind+1], "100half") == 0)
141			arg = 2;
142		else if (strcmp(av[optind+1], "100full") == 0)
143			arg = 3;
144		else
145			usage(av[0]);
146
147		ifr.ifr_data = (caddr_t) &arg;
148		if (ioctl(s, SIOCSETCSPEED, (caddr_t)&ifr) < 0)
149			syserr("etcspeed");
150	}
151	else if (strcmp(av[optind], "phyrd") == 0) {
152		int cmd = -1;
153
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;
165		}
166		ifr.ifr_data = (caddr_t) vecarg;
167		if (ioctl(s, cmd, (caddr_t)&ifr) < 0)
168			syserr("etcphyrd");
169
170		printf("0x%04x\n", vecarg[1]);
171	} else if (strcmp(av[optind], "phywr") == 0) {
172		int cmd = -1;
173
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;
185		}
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]);
192
193		vecarg[0] = strtoul(av[optind + 1], NULL, 0) << 16;;
194		vecarg[0] |= strtoul(av[optind + 2], NULL, 0) & 0xffff;
195
196		ifr.ifr_data = (caddr_t) vecarg;
197		if (ioctl(s, SIOCGETCROBORD, (caddr_t)&ifr) < 0)
198			syserr("etcrobord");
199
200		printf("0x%04x\n", vecarg[1]);
201	} else if (strcmp(av[optind], "robowr") == 0) {
202		if (ac != (optind + 4))
203			usage(av[0]);
204
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);
208
209		ifr.ifr_data = (caddr_t) vecarg;
210		if (ioctl(s, SIOCSETCROBOWR, (caddr_t)&ifr) < 0)
211			syserr("etcrobowr");
212	} else
213		usage(av[0]);
214
215	return (0);
216}
217
218static void
219usage(char *av0)
220{
221	fprintf(stderr, "usage: %s [ [ -a | -i ] interface ] and one of:\n"
222		"\tup\n"
223		"\tdown\n"
224		"\tloop <0 or 1>\n"
225		"\tdump\n"
226		"\tmsglevel <bitvec> (error=1, trace=2, prhdr=4, prpkt=8)\n"
227		"\tpromisc <0 or 1>\n"
228		"\tqos <0 or 1>\n"
229		"\ttxdown\n"
230		"\tspeed <auto, 10half, 10full, 100half, 100full>\n"
231		"\tphyrd [<phyaddr>] <reg>\n"
232		"\tphywr [<phyaddr>] <reg> <val>\n"
233		"\trobord <page> <reg>\n"
234		"\trobowr <page> <reg> <val>\n"
235		,
236		av0);
237	exit(1);
238}
239
240static void
241et_find(int s, struct ifreq *ifr)
242{
243	char proc_net_dev[] = "/proc/net/dev";
244	FILE *fp;
245	char buf[512], *c, *name;
246
247	ifr->ifr_name[0] = '\0';
248
249	/* eat first two lines */
250        if (!(fp = fopen(proc_net_dev, "r")) ||
251            !fgets(buf, sizeof(buf), fp) ||
252            !fgets(buf, sizeof(buf), fp))
253		return;
254
255	while (fgets(buf, sizeof(buf), fp)) {
256		c = buf;
257		while (isspace(*c))
258			c++;
259		if (!(name = strsep(&c, ":")))
260			continue;
261		strncpy(ifr->ifr_name, name, IFNAMSIZ);
262		if (et_check(s, ifr) == 0)
263			break;
264		ifr->ifr_name[0] = '\0';
265	}
266
267	fclose(fp);
268}
269
270static int
271et_check(int s, struct ifreq *ifr)
272{
273	struct ethtool_drvinfo info;
274
275	memset(&info, 0, sizeof(info));
276	info.cmd = ETHTOOL_GDRVINFO;
277	ifr->ifr_data = (caddr_t)&info;
278	if (ioctl(s, SIOCETHTOOL, (caddr_t)ifr) < 0) {
279		/* print a good diagnostic if not superuser */
280		if (errno == EPERM)
281			syserr("siocethtool");
282		return (-1);
283	}
284
285	if (!strncmp(info.driver, "et", 2))
286		return (0);
287	else if (!strncmp(info.driver, "bcm57", 5))
288		return (0);
289
290	return (-1);
291}
292
293static void
294syserr(char *s)
295{
296	perror(s);
297	exit(1);
298}
299
300