blob: 204febf7d5a54fc3e8c8f4b3dec704acf29bc422 [file] [log] [blame]
"Robert P. J. Day"63fc1a92006-07-02 19:47:05 +00001/* vi: set sw=4 ts=4: */
Eric Andersenf15d4da2001-03-06 00:48:59 +00002/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +00003 * stolen from net-tools-1.59 and stripped down for busybox by
Eric Andersencb81e642003-07-14 21:21:08 +00004 * Erik Andersen <andersen@codepoet.org>
Eric Andersenbdfd0d72001-10-24 05:00:29 +00005 *
6 * Heavily modified by Manuel Novoa III Mar 12, 2001
7 *
Eric Andersenbdfd0d72001-10-24 05:00:29 +00008 * Added print_bytes_scaled function to reduce code size.
9 * Added some (potentially) missing defines.
10 * Improved display support for -a and for a named interface.
11 *
12 * -----------------------------------------------------------
13 *
Eric Andersenf15d4da2001-03-06 00:48:59 +000014 * ifconfig This file contains an implementation of the command
15 * that either displays or sets the characteristics of
16 * one or more of the system's networking interfaces.
17 *
Eric Andersenf15d4da2001-03-06 00:48:59 +000018 *
19 * Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
20 * and others. Copyright 1993 MicroWalt Corporation
21 *
Rob Landleye84f4342006-06-03 21:23:20 +000022 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
Eric Andersenf15d4da2001-03-06 00:48:59 +000023 *
24 * Patched to support 'add' and 'del' keywords for INET(4) addresses
25 * by Mrs. Brisby <mrs.brisby@nimh.org>
26 *
27 * {1.34} - 19980630 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
28 * - gettext instead of catgets for i18n
Eric Andersenc7bda1c2004-03-15 08:29:22 +000029 * 10/1998 - Andi Kleen. Use interface list primitives.
30 * 20001008 - Bernd Eckenfels, Patch from RH for setting mtu
Eric Andersenf15d4da2001-03-06 00:48:59 +000031 * (default AF was wrong)
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +000032 */
33
Eric Andersencd8c4362001-11-10 11:22:46 +000034#include <net/if.h>
35#include <net/if_arp.h>
Denis Vlasenko322661d2007-01-29 23:43:52 +000036#include "inet_common.h"
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000037#include "libbb.h"
Eric Andersenf15d4da2001-03-06 00:48:59 +000038
Denis Vlasenko1cc70222007-03-15 19:46:43 +000039#if ENABLE_FEATURE_IPV6
Glenn L McGrathb54a7482003-08-29 11:34:08 +000040# define HAVE_AFINET6 1
41#else
42# undef HAVE_AFINET6
43#endif
44
Eric Andersenf15d4da2001-03-06 00:48:59 +000045#define _PATH_PROCNET_DEV "/proc/net/dev"
Eric Andersen51b8bd62002-07-03 11:46:38 +000046#define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"
Eric Andersenf15d4da2001-03-06 00:48:59 +000047
Denis Vlasenkoaad49992006-11-22 02:12:07 +000048#ifdef HAVE_AFINET6
Eric Andersenf15d4da2001-03-06 00:48:59 +000049
50#ifndef _LINUX_IN6_H
51/*
52 * This is in linux/include/net/ipv6.h.
53 */
54
55struct in6_ifreq {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +000056 struct in6_addr ifr6_addr;
Glenn L McGrathb54a7482003-08-29 11:34:08 +000057 uint32_t ifr6_prefixlen;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +000058 unsigned int ifr6_ifindex;
Eric Andersenf15d4da2001-03-06 00:48:59 +000059};
60
61#endif
62
Denis Vlasenkoaad49992006-11-22 02:12:07 +000063#endif /* HAVE_AFINET6 */
Eric Andersenf15d4da2001-03-06 00:48:59 +000064
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +000065/* Defines for glibc2.0 users. */
66#ifndef SIOCSIFTXQLEN
67#define SIOCSIFTXQLEN 0x8943
68#define SIOCGIFTXQLEN 0x8942
69#endif
70
71/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
72#ifndef ifr_qlen
73#define ifr_qlen ifr_ifru.ifru_mtu
74#endif
75
76#ifndef HAVE_TXQUEUELEN
77#define HAVE_TXQUEUELEN 1
78#endif
79
80#ifndef IFF_DYNAMIC
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +000081#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +000082#endif
83
Eric Andersenf15d4da2001-03-06 00:48:59 +000084/* Display an Internet socket address. */
Denis Vlasenko7f2527e2007-03-14 22:11:20 +000085static const char *INET_sprint(struct sockaddr *sap, int numeric)
Eric Andersenf15d4da2001-03-06 00:48:59 +000086{
Denis Vlasenko6d9ea242007-06-19 11:12:46 +000087 static char *buff;
Eric Andersenf15d4da2001-03-06 00:48:59 +000088
Denis Vlasenko6d9ea242007-06-19 11:12:46 +000089 free(buff);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +000090 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
Denis Vlasenko7f2527e2007-03-14 22:11:20 +000091 return "[NONE SET]";
Denis Vlasenko6d9ea242007-06-19 11:12:46 +000092 buff = INET_rresolve((struct sockaddr_in *) sap, numeric, 0xffffff00);
Denis Vlasenkoaad49992006-11-22 02:12:07 +000093 return buff;
Eric Andersenf15d4da2001-03-06 00:48:59 +000094}
95
Denis Vlasenko7f2527e2007-03-14 22:11:20 +000096#ifdef UNUSED_AND_BUGGY
Denis Vlasenkofa85b862007-01-07 01:24:12 +000097static int INET_getsock(char *bufp, struct sockaddr *sap)
98{
99 char *sp = bufp, *bp;
100 unsigned int i;
101 unsigned val;
102 struct sockaddr_in *sock_in;
103
104 sock_in = (struct sockaddr_in *) sap;
105 sock_in->sin_family = AF_INET;
106 sock_in->sin_port = 0;
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000107
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000108 val = 0;
109 bp = (char *) &val;
110 for (i = 0; i < sizeof(sock_in->sin_addr.s_addr); i++) {
111 *sp = toupper(*sp);
112
113 if ((unsigned)(*sp - 'A') <= 5)
114 bp[i] |= (int) (*sp - ('A' - 10));
115 else if (isdigit(*sp))
116 bp[i] |= (int) (*sp - '0');
117 else
118 return -1;
119
120 bp[i] <<= 4;
121 sp++;
122 *sp = toupper(*sp);
123
124 if ((unsigned)(*sp - 'A') <= 5)
125 bp[i] |= (int) (*sp - ('A' - 10));
126 else if (isdigit(*sp))
127 bp[i] |= (int) (*sp - '0');
128 else
129 return -1;
130
131 sp++;
132 }
133 sock_in->sin_addr.s_addr = htonl(val);
134
135 return (sp - bufp);
136}
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000137#endif
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000138
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000139static int INET_input(/*int type,*/ const char *bufp, struct sockaddr *sap)
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000140{
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000141 return INET_resolve(bufp, (struct sockaddr_in *) sap, 0);
142/*
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000143 switch (type) {
144 case 1:
145 return (INET_getsock(bufp, sap));
146 case 256:
147 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 1));
148 default:
149 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0));
150 }
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000151*/
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000152}
153
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000154static const struct aftype inet_aftype = {
Rob Landley2818b292006-06-20 15:52:52 +0000155 .name = "inet",
156 .title = "DARPA Internet",
157 .af = AF_INET,
Rob Landley9fe801e2006-06-20 21:13:29 +0000158 .alen = 4,
Rob Landley2818b292006-06-20 15:52:52 +0000159 .sprint = INET_sprint,
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000160 .input = INET_input,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000161};
162
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000163#ifdef HAVE_AFINET6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000164
Eric Andersen51b8bd62002-07-03 11:46:38 +0000165/* Display an Internet socket address. */
166/* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000167static const char *INET6_sprint(struct sockaddr *sap, int numeric)
Eric Andersen51b8bd62002-07-03 11:46:38 +0000168{
Denis Vlasenko6d9ea242007-06-19 11:12:46 +0000169 static char *buff;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000170
Denis Vlasenko6d9ea242007-06-19 11:12:46 +0000171 free(buff);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000172 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000173 return "[NONE SET]";
Denis Vlasenko6d9ea242007-06-19 11:12:46 +0000174 buff = INET6_rresolve((struct sockaddr_in6 *) sap, numeric);
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000175 return buff;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000176}
177
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000178#ifdef UNUSED
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000179static int INET6_getsock(char *bufp, struct sockaddr *sap)
180{
181 struct sockaddr_in6 *sin6;
182
183 sin6 = (struct sockaddr_in6 *) sap;
184 sin6->sin6_family = AF_INET6;
185 sin6->sin6_port = 0;
186
187 if (inet_pton(AF_INET6, bufp, sin6->sin6_addr.s6_addr) <= 0)
188 return -1;
189
190 return 16; /* ?;) */
191}
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000192#endif
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000193
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000194static int INET6_input(/*int type,*/ const char *bufp, struct sockaddr *sap)
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000195{
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000196 return INET6_resolve(bufp, (struct sockaddr_in6 *) sap);
197/*
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000198 switch (type) {
199 case 1:
200 return (INET6_getsock(bufp, sap));
201 default:
202 return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap));
203 }
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000204*/
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000205}
206
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000207static const struct aftype inet6_aftype = {
Rob Landley2818b292006-06-20 15:52:52 +0000208 .name = "inet6",
209 .title = "IPv6",
210 .af = AF_INET6,
211 .alen = sizeof(struct in6_addr),
212 .sprint = INET6_sprint,
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000213 .input = INET6_input,
Eric Andersen51b8bd62002-07-03 11:46:38 +0000214};
215
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000216#endif /* HAVE_AFINET6 */
Eric Andersen51b8bd62002-07-03 11:46:38 +0000217
Eric Andersenf15d4da2001-03-06 00:48:59 +0000218/* Display an UNSPEC address. */
219static char *UNSPEC_print(unsigned char *ptr)
220{
Denis Vlasenko1b16bda2007-06-19 11:10:02 +0000221 static char *buff;
222
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000223 char *pos;
224 unsigned int i;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000225
Denis Vlasenko1b16bda2007-06-19 11:10:02 +0000226 if (!buff);
227 buff = xmalloc(sizeof(struct sockaddr) * 3 + 1);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000228 pos = buff;
229 for (i = 0; i < sizeof(struct sockaddr); i++) {
230 /* careful -- not every libc's sprintf returns # bytes written */
231 sprintf(pos, "%02X-", (*ptr++ & 0377));
232 pos += 3;
233 }
234 /* Erase trailing "-". Works as long as sizeof(struct sockaddr) != 0 */
235 *--pos = '\0';
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000236 return buff;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000237}
238
239/* Display an UNSPEC socket address. */
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000240static const char *UNSPEC_sprint(struct sockaddr *sap, int numeric)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000241{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000242 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000243 return "[NONE SET]";
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000244 return UNSPEC_print((unsigned char *)sap->sa_data);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000245}
246
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000247static const struct aftype unspec_aftype = {
248 .name = "unspec",
249 .title = "UNSPEC",
250 .af = AF_UNSPEC,
251 .alen = 0,
252 .print = UNSPEC_print,
253 .sprint = UNSPEC_sprint,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000254};
255
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000256static const struct aftype *const aftypes[] = {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000257 &inet_aftype,
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000258#ifdef HAVE_AFINET6
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000259 &inet6_aftype,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000260#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000261 &unspec_aftype,
262 NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +0000263};
264
Eric Andersenf15d4da2001-03-06 00:48:59 +0000265/* Check our protocol family table for this family. */
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000266const struct aftype *get_aftype(const char *name)
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000267{
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000268 const struct aftype *const *afp;
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000269
270 afp = aftypes;
271 while (*afp != NULL) {
272 if (!strcmp((*afp)->name, name))
273 return (*afp);
274 afp++;
275 }
276 return NULL;
277}
278
279/* Check our protocol family table for this family. */
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000280static const struct aftype *get_afntype(int af)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000281{
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000282 const struct aftype *const *afp;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000283
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000284 afp = aftypes;
285 while (*afp != NULL) {
286 if ((*afp)->af == af)
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000287 return *afp;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000288 afp++;
289 }
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000290 return NULL;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000291}
292
Eric Andersenf15d4da2001-03-06 00:48:59 +0000293struct user_net_device_stats {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000294 unsigned long long rx_packets; /* total packets received */
295 unsigned long long tx_packets; /* total packets transmitted */
296 unsigned long long rx_bytes; /* total bytes received */
297 unsigned long long tx_bytes; /* total bytes transmitted */
298 unsigned long rx_errors; /* bad packets received */
299 unsigned long tx_errors; /* packet transmit problems */
300 unsigned long rx_dropped; /* no space in linux buffers */
301 unsigned long tx_dropped; /* no space available in linux */
302 unsigned long rx_multicast; /* multicast packets received */
303 unsigned long rx_compressed;
304 unsigned long tx_compressed;
305 unsigned long collisions;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000306
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000307 /* detailed rx_errors: */
308 unsigned long rx_length_errors;
309 unsigned long rx_over_errors; /* receiver ring buff overflow */
310 unsigned long rx_crc_errors; /* recved pkt with crc error */
311 unsigned long rx_frame_errors; /* recv'd frame alignment error */
312 unsigned long rx_fifo_errors; /* recv'r fifo overrun */
313 unsigned long rx_missed_errors; /* receiver missed packet */
314 /* detailed tx_errors */
315 unsigned long tx_aborted_errors;
316 unsigned long tx_carrier_errors;
317 unsigned long tx_fifo_errors;
318 unsigned long tx_heartbeat_errors;
319 unsigned long tx_window_errors;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000320};
321
322struct interface {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000323 struct interface *next, *prev;
324 char name[IFNAMSIZ]; /* interface name */
325 short type; /* if type */
326 short flags; /* various flags */
327 int metric; /* routing metric */
328 int mtu; /* MTU value */
329 int tx_queue_len; /* transmit queue length */
330 struct ifmap map; /* hardware setup */
331 struct sockaddr addr; /* IP address */
332 struct sockaddr dstaddr; /* P-P IP address */
333 struct sockaddr broadaddr; /* IP broadcast address */
334 struct sockaddr netmask; /* IP network mask */
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000335 int has_ip;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000336 char hwaddr[32]; /* HW address */
337 int statistics_valid;
338 struct user_net_device_stats stats; /* statistics */
339 int keepalive; /* keepalive value for SLIP */
340 int outfill; /* outfill value for SLIP */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000341};
342
343
Denis Vlasenko1b16bda2007-06-19 11:10:02 +0000344smallint interface_opt_a; /* show all interfaces */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000345
Eric Andersenf15d4da2001-03-06 00:48:59 +0000346static struct interface *int_list, *int_last;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000347
348
Bernhard Reutner-Fischer57d83ff2006-12-07 12:25:17 +0000349#if 0
Eric Andersenf15d4da2001-03-06 00:48:59 +0000350/* like strcmp(), but knows about numbers */
Bernhard Reutner-Fischer57d83ff2006-12-07 12:25:17 +0000351except that the freshly added calls to xatoul() brf on ethernet aliases with
352uClibc with e.g.: ife->name='lo' name='eth0:1'
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000353static int nstrcmp(const char *a, const char *b)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000354{
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000355 const char *a_ptr = a;
356 const char *b_ptr = b;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000357
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000358 while (*a == *b) {
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000359 if (*a == '\0') {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000360 return 0;
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000361 }
362 if (!isdigit(*a) && isdigit(*(a+1))) {
363 a_ptr = a+1;
364 b_ptr = b+1;
365 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000366 a++;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000367 b++;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000368 }
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000369
370 if (isdigit(*a) && isdigit(*b)) {
Denis Vlasenko13858992006-10-08 12:49:22 +0000371 return xatoul(a_ptr) > xatoul(b_ptr) ? 1 : -1;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000372 }
373 return *a - *b;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000374}
Bernhard Reutner-Fischer57d83ff2006-12-07 12:25:17 +0000375#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +0000376
377static struct interface *add_interface(char *name)
378{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000379 struct interface *ife, **nextp, *new;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000380
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000381 for (ife = int_last; ife; ife = ife->prev) {
Bernhard Reutner-Fischer57d83ff2006-12-07 12:25:17 +0000382 int n = /*n*/strcmp(ife->name, name);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000383
384 if (n == 0)
385 return ife;
386 if (n < 0)
387 break;
388 }
Rob Landleya6e131d2006-05-29 06:43:55 +0000389
390 new = xzalloc(sizeof(*new));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000391 safe_strncpy(new->name, name, IFNAMSIZ);
392 nextp = ife ? &ife->next : &int_list;
393 new->prev = ife;
394 new->next = *nextp;
395 if (new->next)
396 new->next->prev = new;
397 else
398 int_last = new;
399 *nextp = new;
400 return new;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000401}
402
Eric Andersen14f5c8d2005-04-16 19:39:00 +0000403static char *get_name(char *name, char *p)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000404{
Rob Landley9fe801e2006-06-20 21:13:29 +0000405 /* Extract <name> from nul-terminated p where p matches
406 <name>: after leading whitespace.
Eric Andersen9940e082004-08-12 16:52:00 +0000407 If match is not made, set name empty and return unchanged p */
Rob Landley9fe801e2006-06-20 21:13:29 +0000408 int namestart=0, nameend=0;
Eric Andersen9940e082004-08-12 16:52:00 +0000409 while (isspace(p[namestart]))
410 namestart++;
411 nameend=namestart;
412 while (p[nameend] && p[nameend]!=':' && !isspace(p[nameend]))
413 nameend++;
414 if (p[nameend]==':') {
Eric Andersen9940e082004-08-12 16:52:00 +0000415 if ((nameend-namestart)<IFNAMSIZ) {
416 memcpy(name,&p[namestart],nameend-namestart);
417 name[nameend-namestart]='\0';
418 p=&p[nameend];
419 } else {
420 /* Interface name too large */
421 name[0]='\0';
422 }
423 } else {
Rob Landley9fe801e2006-06-20 21:13:29 +0000424 /* trailing ':' not found - return empty */
Eric Andersen9940e082004-08-12 16:52:00 +0000425 name[0]='\0';
Eric Andersenf15d4da2001-03-06 00:48:59 +0000426 }
Eric Andersen6fea7322004-08-26 21:45:21 +0000427 return p + 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000428}
429
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000430/* If scanf supports size qualifiers for %n conversions, then we can
431 * use a modified fmt that simply stores the position in the fields
432 * having no associated fields in the proc string. Of course, we need
433 * to zero them again when we're done. But that is smaller than the
434 * old approach of multiple scanf occurrences with large numbers of
435 * args. */
436
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000437/* static const char *const ss_fmt[] = { */
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000438/* "%lln%llu%lu%lu%lu%lu%ln%ln%lln%llu%lu%lu%lu%lu%lu", */
439/* "%llu%llu%lu%lu%lu%lu%ln%ln%llu%llu%lu%lu%lu%lu%lu", */
440/* "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu" */
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000441/* }; */
442
443 /* Lie about the size of the int pointed to for %n. */
444#if INT_MAX == LONG_MAX
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000445static const char *const ss_fmt[] = {
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000446 "%n%llu%u%u%u%u%n%n%n%llu%u%u%u%u%u",
447 "%llu%llu%u%u%u%u%n%n%llu%llu%u%u%u%u%u",
448 "%llu%llu%u%u%u%u%u%u%llu%llu%u%u%u%u%u%u"
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000449};
450#else
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000451static const char *const ss_fmt[] = {
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000452 "%n%llu%lu%lu%lu%lu%n%n%n%llu%lu%lu%lu%lu%lu",
453 "%llu%llu%lu%lu%lu%lu%n%n%llu%llu%lu%lu%lu%lu%lu",
454 "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu"
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000455};
456
457#endif
458
459static void get_dev_fields(char *bp, struct interface *ife, int procnetdev_vsn)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000460{
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000461 memset(&ife->stats, 0, sizeof(struct user_net_device_stats));
462
463 sscanf(bp, ss_fmt[procnetdev_vsn],
464 &ife->stats.rx_bytes, /* missing for 0 */
465 &ife->stats.rx_packets,
466 &ife->stats.rx_errors,
467 &ife->stats.rx_dropped,
468 &ife->stats.rx_fifo_errors,
469 &ife->stats.rx_frame_errors,
470 &ife->stats.rx_compressed, /* missing for <= 1 */
471 &ife->stats.rx_multicast, /* missing for <= 1 */
472 &ife->stats.tx_bytes, /* missing for 0 */
473 &ife->stats.tx_packets,
474 &ife->stats.tx_errors,
475 &ife->stats.tx_dropped,
476 &ife->stats.tx_fifo_errors,
477 &ife->stats.collisions,
478 &ife->stats.tx_carrier_errors,
479 &ife->stats.tx_compressed /* missing for <= 1 */
480 );
481
482 if (procnetdev_vsn <= 1) {
483 if (procnetdev_vsn == 0) {
484 ife->stats.rx_bytes = 0;
485 ife->stats.tx_bytes = 0;
486 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000487 ife->stats.rx_multicast = 0;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000488 ife->stats.rx_compressed = 0;
489 ife->stats.tx_compressed = 0;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000490 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000491}
492
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000493static inline int procnetdev_version(char *buf)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000494{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000495 if (strstr(buf, "compressed"))
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000496 return 2;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000497 if (strstr(buf, "bytes"))
498 return 1;
499 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000500}
501
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000502static int if_readconf(void)
503{
504 int numreqs = 30;
505 struct ifconf ifc;
506 struct ifreq *ifr;
507 int n, err = -1;
508 int skfd;
509
510 ifc.ifc_buf = NULL;
511
512 /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
513 (as of 2.1.128) */
514 skfd = socket(AF_INET, SOCK_DGRAM, 0);
515 if (skfd < 0) {
516 bb_perror_msg("error: no inet socket available");
517 return -1;
518 }
519
520 for (;;) {
521 ifc.ifc_len = sizeof(struct ifreq) * numreqs;
522 ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);
523
524 if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) {
Denis Vlasenko1b16bda2007-06-19 11:10:02 +0000525 bb_perror_msg("SIOCGIFCONF");
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000526 goto out;
527 }
528 if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
529 /* assume it overflowed and try again */
530 numreqs += 10;
531 continue;
532 }
533 break;
534 }
535
536 ifr = ifc.ifc_req;
537 for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
538 add_interface(ifr->ifr_name);
539 ifr++;
540 }
541 err = 0;
542
543 out:
544 close(skfd);
545 free(ifc.ifc_buf);
546 return err;
547}
548
Eric Andersenf15d4da2001-03-06 00:48:59 +0000549static int if_readlist_proc(char *target)
550{
Denis Vlasenko1b16bda2007-06-19 11:10:02 +0000551 static smallint proc_read;
552
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000553 FILE *fh;
554 char buf[512];
555 struct interface *ife;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000556 int err, procnetdev_vsn;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000557
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000558 if (proc_read)
559 return 0;
560 if (!target)
561 proc_read = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000562
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000563 fh = fopen(_PATH_PROCNET_DEV, "r");
564 if (!fh) {
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000565 bb_perror_msg("warning: cannot open %s, limiting output", _PATH_PROCNET_DEV);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000566 return if_readconf();
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000567 }
568 fgets(buf, sizeof buf, fh); /* eat line */
569 fgets(buf, sizeof buf, fh);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000570
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000571 procnetdev_vsn = procnetdev_version(buf);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000572
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000573 err = 0;
574 while (fgets(buf, sizeof buf, fh)) {
Eric Andersenf96675b2003-07-28 06:37:04 +0000575 char *s, name[128];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000576
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000577 s = get_name(name, buf);
578 ife = add_interface(name);
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000579 get_dev_fields(s, ife, procnetdev_vsn);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000580 ife->statistics_valid = 1;
581 if (target && !strcmp(target, name))
582 break;
583 }
584 if (ferror(fh)) {
Denis Vlasenko1b16bda2007-06-19 11:10:02 +0000585 bb_perror_msg(_PATH_PROCNET_DEV);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000586 err = -1;
587 proc_read = 0;
588 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000589 fclose(fh);
590 return err;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000591}
592
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000593static int if_readlist(void)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000594{
Denis Vlasenkod0587ed2007-03-22 19:35:51 +0000595 int err = if_readlist_proc(NULL);
596 /* Needed in order to get ethN:M aliases */
597 if (!err)
598 err = if_readconf();
599 return err;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000600}
601
Eric Andersenf15d4da2001-03-06 00:48:59 +0000602/* Fetch the interface configuration from the kernel. */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000603static int if_fetch(struct interface *ife)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000604{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000605 struct ifreq ifr;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000606 char *ifname = ife->name;
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000607 int skfd;
608
609 skfd = xsocket(AF_INET, SOCK_DGRAM, 0);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000610
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000611 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000612 if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
613 close(skfd);
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000614 return -1;
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000615 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000616 ife->flags = ifr.ifr_flags;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000617
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000618 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000619 memset(ife->hwaddr, 0, 32);
620 if (ioctl(skfd, SIOCGIFHWADDR, &ifr) >= 0)
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000621 memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000622
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000623 ife->type = ifr.ifr_hwaddr.sa_family;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000624
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000625 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000626 ife->metric = 0;
627 if (ioctl(skfd, SIOCGIFMETRIC, &ifr) >= 0)
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000628 ife->metric = ifr.ifr_metric;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000629
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000630 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000631 ife->mtu = 0;
632 if (ioctl(skfd, SIOCGIFMTU, &ifr) >= 0)
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000633 ife->mtu = ifr.ifr_mtu;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000634
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000635 memset(&ife->map, 0, sizeof(struct ifmap));
Rob Landley93983042005-05-03 21:30:26 +0000636#ifdef SIOCGIFMAP
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000637 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Rob Landley93983042005-05-03 21:30:26 +0000638 if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0)
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000639 ife->map = ifr.ifr_map;
Rob Landley93983042005-05-03 21:30:26 +0000640#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +0000641
642#ifdef HAVE_TXQUEUELEN
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000643 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000644 ife->tx_queue_len = -1; /* unknown value */
645 if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) >= 0)
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000646 ife->tx_queue_len = ifr.ifr_qlen;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000647#else
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000648 ife->tx_queue_len = -1; /* unknown value */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000649#endif
650
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000651 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
652 ifr.ifr_addr.sa_family = AF_INET;
653 memset(&ife->addr, 0, sizeof(struct sockaddr));
654 if (ioctl(skfd, SIOCGIFADDR, &ifr) == 0) {
655 ife->has_ip = 1;
656 ife->addr = ifr.ifr_addr;
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000657 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000658 memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
659 if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) >= 0)
660 ife->dstaddr = ifr.ifr_dstaddr;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000661
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000662 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
663 memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
664 if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) >= 0)
665 ife->broadaddr = ifr.ifr_broadaddr;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000666
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000667 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
668 memset(&ife->netmask, 0, sizeof(struct sockaddr));
669 if (ioctl(skfd, SIOCGIFNETMASK, &ifr) >= 0)
670 ife->netmask = ifr.ifr_netmask;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000671 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000672
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000673 close(skfd);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000674 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000675}
676
677
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000678static int do_if_fetch(struct interface *ife)
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000679{
680 if (if_fetch(ife) < 0) {
Denis Vlasenko322661d2007-01-29 23:43:52 +0000681 const char *errmsg;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000682
683 if (errno == ENODEV) {
684 /* Give better error message for this case. */
Rob Landley4e3aff32006-05-29 04:37:28 +0000685 errmsg = "Device not found";
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000686 } else {
687 errmsg = strerror(errno);
688 }
Rob Landley4e3aff32006-05-29 04:37:28 +0000689 bb_error_msg("%s: error fetching interface information: %s",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000690 ife->name, errmsg);
691 return -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000692 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000693 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000694}
695
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000696static const struct hwtype unspec_hwtype = {
"Robert P. J. Day"4137dd72006-06-26 21:54:57 +0000697 .name = "unspec",
698 .title = "UNSPEC",
699 .type = -1,
700 .print = UNSPEC_print
Eric Andersenf15d4da2001-03-06 00:48:59 +0000701};
702
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000703static const struct hwtype loop_hwtype = {
"Robert P. J. Day"4137dd72006-06-26 21:54:57 +0000704 .name = "loop",
705 .title = "Local Loopback",
706 .type = ARPHRD_LOOPBACK
Eric Andersenf15d4da2001-03-06 00:48:59 +0000707};
708
Eric Andersenf15d4da2001-03-06 00:48:59 +0000709#include <net/if_arp.h>
Eric Andersenab4e19a2003-01-14 08:54:08 +0000710
Denis Vlasenko83e5d6f2006-12-18 21:49:06 +0000711#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined(_NEWLIB_VERSION)
Eric Andersenab4e19a2003-01-14 08:54:08 +0000712#include <net/ethernet.h>
713#else
Eric Andersenf15d4da2001-03-06 00:48:59 +0000714#include <linux/if_ether.h>
Eric Andersenab4e19a2003-01-14 08:54:08 +0000715#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +0000716
Eric Andersenf15d4da2001-03-06 00:48:59 +0000717/* Display an Ethernet address in readable format. */
718static char *pr_ether(unsigned char *ptr)
719{
Denis Vlasenko1b16bda2007-06-19 11:10:02 +0000720 static char *buff;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000721
Denis Vlasenko1b16bda2007-06-19 11:10:02 +0000722 free(buff);
723 buff = xasprintf("%02X:%02X:%02X:%02X:%02X:%02X",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000724 (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377),
725 (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)
726 );
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000727 return buff;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000728}
729
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000730static int in_ether(const char *bufp, struct sockaddr *sap);
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000731
Denis Vlasenko1b16bda2007-06-19 11:10:02 +0000732static const struct hwtype ether_hwtype = {
"Robert P. J. Day"4137dd72006-06-26 21:54:57 +0000733 .name = "ether",
734 .title = "Ethernet",
735 .type = ARPHRD_ETHER,
736 .alen = ETH_ALEN,
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000737 .print = pr_ether,
738 .input = in_ether
Eric Andersenf15d4da2001-03-06 00:48:59 +0000739};
740
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000741static unsigned hexchar2int(char c)
742{
743 if (isdigit(c))
744 return c - '0';
745 c &= ~0x20; /* a -> A */
746 if ((unsigned)(c - 'A') <= 5)
747 return c - ('A' - 10);
748 return ~0U;
749}
750
751/* Input an Ethernet address and convert to binary. */
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000752static int in_ether(const char *bufp, struct sockaddr *sap)
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000753{
754 unsigned char *ptr;
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000755 char c;
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000756 int i;
757 unsigned val;
758
759 sap->sa_family = ether_hwtype.type;
Denis Vlasenko731d3572007-02-02 01:16:33 +0000760 ptr = (unsigned char*) sap->sa_data;
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000761
762 i = 0;
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000763 while ((*bufp != '\0') && (i < ETH_ALEN)) {
764 val = hexchar2int(*bufp++) * 0x10;
765 if (val > 0xff) {
766 errno = EINVAL;
767 return -1;
768 }
769 c = *bufp;
770 if (c == ':' || c == 0)
771 val >>= 4;
772 else {
773 val |= hexchar2int(c);
774 if (val > 0xff) {
775 errno = EINVAL;
776 return -1;
777 }
778 }
779 if (c != 0)
780 bufp++;
781 *ptr++ = (unsigned char) val;
782 i++;
783
784 /* We might get a semicolon here - not required. */
785 if (*bufp == ':') {
786 bufp++;
787 }
788 }
789 return 0;
790}
791
Eric Andersenf15d4da2001-03-06 00:48:59 +0000792#include <net/if_arp.h>
793
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000794static const struct hwtype ppp_hwtype = {
"Robert P. J. Day"4137dd72006-06-26 21:54:57 +0000795 .name = "ppp",
796 .title = "Point-to-Point Protocol",
797 .type = ARPHRD_PPP
Eric Andersenf15d4da2001-03-06 00:48:59 +0000798};
799
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000800#if ENABLE_FEATURE_IPV6
"Robert P. J. Day"21302c22006-06-26 22:03:43 +0000801static const struct hwtype sit_hwtype = {
802 .name = "sit",
803 .title = "IPv6-in-IPv4",
804 .type = ARPHRD_SIT,
805 .print = UNSPEC_print,
806 .suppress_null_addr = 1
807} ;
808#endif
809
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000810static const struct hwtype *const hwtypes[] = {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000811 &loop_hwtype,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000812 &ether_hwtype,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000813 &ppp_hwtype,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000814 &unspec_hwtype,
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000815#if ENABLE_FEATURE_IPV6
"Robert P. J. Day"21302c22006-06-26 22:03:43 +0000816 &sit_hwtype,
817#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000818 NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +0000819};
820
Eric Andersenf15d4da2001-03-06 00:48:59 +0000821#ifdef IFF_PORTSEL
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000822static const char *const if_port_text[] = {
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000823 /* Keep in step with <linux/netdevice.h> */
824 "unknown",
825 "10base2",
826 "10baseT",
827 "AUI",
828 "100baseT",
829 "100baseTX",
830 "100baseFX",
831 NULL
832};
833#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +0000834
835/* Check our hardware type table for this type. */
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000836const struct hwtype *get_hwtype(const char *name)
837{
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000838 const struct hwtype *const *hwp;
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000839
840 hwp = hwtypes;
841 while (*hwp != NULL) {
842 if (!strcmp((*hwp)->name, name))
843 return (*hwp);
844 hwp++;
845 }
846 return NULL;
847}
848
849/* Check our hardware type table for this type. */
850const struct hwtype *get_hwntype(int type)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000851{
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000852 const struct hwtype *const *hwp;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000853
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000854 hwp = hwtypes;
855 while (*hwp != NULL) {
856 if ((*hwp)->type == type)
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000857 return *hwp;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000858 hwp++;
859 }
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000860 return NULL;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000861}
862
863/* return 1 if address is all zeros */
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000864static int hw_null_address(const struct hwtype *hw, void *ap)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000865{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000866 unsigned int i;
867 unsigned char *address = (unsigned char *) ap;
868
869 for (i = 0; i < hw->alen; i++)
870 if (address[i])
871 return 0;
872 return 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000873}
874
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000875static const char TRext[] = "\0\0\0Ki\0Mi\0Gi\0Ti";
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000876
877static void print_bytes_scaled(unsigned long long ull, const char *end)
878{
879 unsigned long long int_part;
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000880 const char *ext;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000881 unsigned int frac_part;
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000882 int i;
883
884 frac_part = 0;
885 ext = TRext;
886 int_part = ull;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000887 i = 4;
888 do {
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000889 if (int_part >= 1024) {
890 frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
891 int_part /= 1024;
892 ext += 3; /* KiB, MiB, GiB, TiB */
893 }
894 --i;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000895 } while (i);
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000896
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000897 printf("X bytes:%llu (%llu.%u %sB)%s", ull, int_part, frac_part, ext, end);
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000898}
899
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000900static const char *const ife_print_flags_strs[] = {
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000901 "UP ",
902 "BROADCAST ",
903 "DEBUG ",
904 "LOOPBACK ",
905 "POINTOPOINT ",
906 "NOTRAILERS ",
907 "RUNNING ",
908 "NOARP ",
909 "PROMISC ",
910 "ALLMULTI ",
911 "SLAVE ",
912 "MASTER ",
913 "MULTICAST ",
914#ifdef HAVE_DYNAMIC
915 "DYNAMIC "
916#endif
917};
918
919static const unsigned short ife_print_flags_mask[] = {
920 IFF_UP,
921 IFF_BROADCAST,
922 IFF_DEBUG,
923 IFF_LOOPBACK,
924 IFF_POINTOPOINT,
925 IFF_NOTRAILERS,
926 IFF_RUNNING,
927 IFF_NOARP,
928 IFF_PROMISC,
929 IFF_ALLMULTI,
930 IFF_SLAVE,
931 IFF_MASTER,
932 IFF_MULTICAST,
933#ifdef HAVE_DYNAMIC
934 IFF_DYNAMIC
935#endif
936 0
937};
938
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000939static void ife_print(struct interface *ptr)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000940{
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000941 const struct aftype *ap;
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000942 const struct hwtype *hw;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000943 int hf;
944 int can_compress = 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000945
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000946#ifdef HAVE_AFINET6
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000947 FILE *f;
948 char addr6[40], devname[20];
949 struct sockaddr_in6 sap;
950 int plen, scope, dad_status, if_idx;
951 char addr6p[8][5];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000952#endif
953
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000954 ap = get_afntype(ptr->addr.sa_family);
955 if (ap == NULL)
956 ap = get_afntype(0);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000957
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000958 hf = ptr->type;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000959
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000960 if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
961 can_compress = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000962
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000963 hw = get_hwntype(hf);
964 if (hw == NULL)
965 hw = get_hwntype(-1);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000966
Rob Landley4e3aff32006-05-29 04:37:28 +0000967 printf("%-9.9s Link encap:%s ", ptr->name, hw->title);
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000968 /* For some hardware types (eg Ash, ATM) we don't print the
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000969 hardware address if it's null. */
970 if (hw->print != NULL && (!(hw_null_address(hw, ptr->hwaddr) &&
971 hw->suppress_null_addr)))
Rob Landley4e3aff32006-05-29 04:37:28 +0000972 printf("HWaddr %s ", hw->print((unsigned char *)ptr->hwaddr));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000973#ifdef IFF_PORTSEL
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000974 if (ptr->flags & IFF_PORTSEL) {
Rob Landley4e3aff32006-05-29 04:37:28 +0000975 printf("Media:%s", if_port_text[ptr->map.port] /* [0] */);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000976 if (ptr->flags & IFF_AUTOMEDIA)
Rob Landley4e3aff32006-05-29 04:37:28 +0000977 printf("(auto)");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000978 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000979#endif
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +0000980 puts("");
Eric Andersenf15d4da2001-03-06 00:48:59 +0000981
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000982 if (ptr->has_ip) {
Rob Landley4e3aff32006-05-29 04:37:28 +0000983 printf(" %s addr:%s ", ap->name,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000984 ap->sprint(&ptr->addr, 1));
985 if (ptr->flags & IFF_POINTOPOINT) {
Rob Landley4e3aff32006-05-29 04:37:28 +0000986 printf(" P-t-P:%s ", ap->sprint(&ptr->dstaddr, 1));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000987 }
988 if (ptr->flags & IFF_BROADCAST) {
Rob Landley4e3aff32006-05-29 04:37:28 +0000989 printf(" Bcast:%s ", ap->sprint(&ptr->broadaddr, 1));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000990 }
Rob Landley4e3aff32006-05-29 04:37:28 +0000991 printf(" Mask:%s\n", ap->sprint(&ptr->netmask, 1));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000992 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000993
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000994#ifdef HAVE_AFINET6
Eric Andersenf15d4da2001-03-06 00:48:59 +0000995
Eric Andersen51b8bd62002-07-03 11:46:38 +0000996#define IPV6_ADDR_ANY 0x0000U
997
998#define IPV6_ADDR_UNICAST 0x0001U
999#define IPV6_ADDR_MULTICAST 0x0002U
1000#define IPV6_ADDR_ANYCAST 0x0004U
1001
1002#define IPV6_ADDR_LOOPBACK 0x0010U
1003#define IPV6_ADDR_LINKLOCAL 0x0020U
1004#define IPV6_ADDR_SITELOCAL 0x0040U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001005
Eric Andersen51b8bd62002-07-03 11:46:38 +00001006#define IPV6_ADDR_COMPATv4 0x0080U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001007
Eric Andersen51b8bd62002-07-03 11:46:38 +00001008#define IPV6_ADDR_SCOPE_MASK 0x00f0U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001009
Eric Andersen51b8bd62002-07-03 11:46:38 +00001010#define IPV6_ADDR_MAPPED 0x1000U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001011#define IPV6_ADDR_RESERVED 0x2000U /* reserved address space */
1012
Denis Vlasenkoad67a392007-02-09 18:26:52 +00001013 f = fopen(_PATH_PROCNET_IFINET6, "r");
1014 if (f != NULL) {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001015 while (fscanf
1016 (f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
1017 addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
1018 addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope,
Denis Vlasenkoad67a392007-02-09 18:26:52 +00001019 &dad_status, devname) != EOF
1020 ) {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001021 if (!strcmp(devname, ptr->name)) {
1022 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
1023 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
1024 addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
1025 inet_pton(AF_INET6, addr6,
1026 (struct sockaddr *) &sap.sin6_addr);
1027 sap.sin6_family = AF_INET6;
Rob Landley4e3aff32006-05-29 04:37:28 +00001028 printf(" inet6 addr: %s/%d",
Denis Vlasenko1b16bda2007-06-19 11:10:02 +00001029 INET6_sprint((struct sockaddr *) &sap, 1),
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001030 plen);
Rob Landley4e3aff32006-05-29 04:37:28 +00001031 printf(" Scope:");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001032 switch (scope & IPV6_ADDR_SCOPE_MASK) {
1033 case 0:
Denis Vlasenko1b16bda2007-06-19 11:10:02 +00001034 puts("Global");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001035 break;
1036 case IPV6_ADDR_LINKLOCAL:
Denis Vlasenko1b16bda2007-06-19 11:10:02 +00001037 puts("Link");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001038 break;
1039 case IPV6_ADDR_SITELOCAL:
Denis Vlasenko1b16bda2007-06-19 11:10:02 +00001040 puts("Site");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001041 break;
1042 case IPV6_ADDR_COMPATv4:
Denis Vlasenko1b16bda2007-06-19 11:10:02 +00001043 puts("Compat");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001044 break;
1045 case IPV6_ADDR_LOOPBACK:
Denis Vlasenko1b16bda2007-06-19 11:10:02 +00001046 puts("Host");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001047 break;
1048 default:
Denis Vlasenko1b16bda2007-06-19 11:10:02 +00001049 puts("Unknown");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001050 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001051 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001052 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001053 fclose(f);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001054 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001055#endif
1056
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001057 printf(" ");
1058 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001059
1060 if (ptr->flags == 0) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001061 printf("[NO FLAGS] ");
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001062 } else {
1063 int i = 0;
1064 do {
1065 if (ptr->flags & ife_print_flags_mask[i]) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001066 printf(ife_print_flags_strs[i]);
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001067 }
1068 } while (ife_print_flags_mask[++i]);
1069 }
1070
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001071 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
Rob Landley4e3aff32006-05-29 04:37:28 +00001072 printf(" MTU:%d Metric:%d", ptr->mtu, ptr->metric ? ptr->metric : 1);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001073#ifdef SIOCSKEEPALIVE
1074 if (ptr->outfill || ptr->keepalive)
Rob Landley4e3aff32006-05-29 04:37:28 +00001075 printf(" Outfill:%d Keepalive:%d", ptr->outfill, ptr->keepalive);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001076#endif
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00001077 puts("");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001078
1079 /* If needed, display the interface statistics. */
1080
1081 if (ptr->statistics_valid) {
1082 /* XXX: statistics are currently only printed for the primary address,
1083 * not for the aliases, although strictly speaking they're shared
1084 * by all addresses.
1085 */
1086 printf(" ");
1087
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001088 printf("RX packets:%llu errors:%lu dropped:%lu overruns:%lu frame:%lu\n",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001089 ptr->stats.rx_packets, ptr->stats.rx_errors,
1090 ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors,
1091 ptr->stats.rx_frame_errors);
1092 if (can_compress)
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001093 printf(" compressed:%lu\n",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001094 ptr->stats.rx_compressed);
1095 printf(" ");
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001096 printf("TX packets:%llu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001097 ptr->stats.tx_packets, ptr->stats.tx_errors,
1098 ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
1099 ptr->stats.tx_carrier_errors);
Bernhard Reutner-Fischer214744d2006-03-30 13:38:19 +00001100 printf(" collisions:%lu ", ptr->stats.collisions);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001101 if (can_compress)
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001102 printf("compressed:%lu ", ptr->stats.tx_compressed);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001103 if (ptr->tx_queue_len != -1)
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001104 printf("txqueuelen:%d ", ptr->tx_queue_len);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001105 printf("\n R");
1106 print_bytes_scaled(ptr->stats.rx_bytes, " T");
1107 print_bytes_scaled(ptr->stats.tx_bytes, "\n");
1108
1109 }
1110
1111 if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
1112 ptr->map.base_addr)) {
1113 printf(" ");
1114 if (ptr->map.irq)
Rob Landley4e3aff32006-05-29 04:37:28 +00001115 printf("Interrupt:%d ", ptr->map.irq);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001116 if (ptr->map.base_addr >= 0x100) /* Only print devices using it for
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001117 I/O maps */
Rob Landley4e3aff32006-05-29 04:37:28 +00001118 printf("Base address:0x%lx ",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001119 (unsigned long) ptr->map.base_addr);
1120 if (ptr->map.mem_start) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001121 printf("Memory:%lx-%lx ", ptr->map.mem_start,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001122 ptr->map.mem_end);
1123 }
1124 if (ptr->map.dma)
Rob Landley4e3aff32006-05-29 04:37:28 +00001125 printf("DMA chan:%x ", ptr->map.dma);
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00001126 puts("");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001127 }
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00001128 puts("");
Eric Andersenf15d4da2001-03-06 00:48:59 +00001129}
1130
1131
Denis Vlasenko1b16bda2007-06-19 11:10:02 +00001132static int do_if_print(struct interface *ife) /*, int *opt_a)*/
Eric Andersenf15d4da2001-03-06 00:48:59 +00001133{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001134 int res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001135
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001136 res = do_if_fetch(ife);
1137 if (res >= 0) {
Denis Vlasenko1b16bda2007-06-19 11:10:02 +00001138 if ((ife->flags & IFF_UP) || interface_opt_a)
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001139 ife_print(ife);
1140 }
1141 return res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001142}
1143
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001144static struct interface *lookup_interface(char *name)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001145{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001146 struct interface *ife = NULL;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001147
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001148 if (if_readlist_proc(name) < 0)
1149 return NULL;
1150 ife = add_interface(name);
1151 return ife;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001152}
1153
Denis Vlasenko1b16bda2007-06-19 11:10:02 +00001154#ifdef UNUSED
1155static int for_all_interfaces(int (*doit) (struct interface *, void *),
1156 void *cookie)
1157{
1158 struct interface *ife;
1159
1160 if (!int_list && (if_readlist() < 0))
1161 return -1;
1162 for (ife = int_list; ife; ife = ife->next) {
1163 int err = doit(ife, cookie);
1164
1165 if (err)
1166 return err;
1167 }
1168 return 0;
1169}
1170#endif
1171
Eric Andersenf15d4da2001-03-06 00:48:59 +00001172/* for ipv4 add/del modes */
1173static int if_print(char *ifname)
1174{
Denis Vlasenko1b16bda2007-06-19 11:10:02 +00001175 struct interface *ife;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001176 int res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001177
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001178 if (!ifname) {
Denis Vlasenko1b16bda2007-06-19 11:10:02 +00001179 /*res = for_all_interfaces(do_if_print, &interface_opt_a);*/
1180 if (!int_list && (if_readlist() < 0))
1181 return -1;
1182 for (ife = int_list; ife; ife = ife->next) {
1183 int err = do_if_print(ife); /*, &interface_opt_a);*/
1184 if (err)
1185 return err;
1186 }
1187 return 0;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001188 }
Denis Vlasenko1b16bda2007-06-19 11:10:02 +00001189 ife = lookup_interface(ifname);
1190 res = do_if_fetch(ife);
1191 if (res >= 0)
1192 ife_print(ife);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001193 return res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001194}
1195
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001196int display_interfaces(char *ifname)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001197{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001198 int status;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001199
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001200 status = if_print(ifname);
Denis Vlasenko1cc70222007-03-15 19:46:43 +00001201
1202 return (status < 0); /* status < 0 == 1 -- error */
Eric Andersenf15d4da2001-03-06 00:48:59 +00001203}