blob: b1b935e7efdb9d096e48160ff6d0a63183f22c89 [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"
Bernhard Reutner-Fischerfa939aa2006-04-05 16:21:37 +000037#include "busybox.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{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +000087 static char buff[128];
Eric Andersenf15d4da2001-03-06 00:48:59 +000088
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +000089 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
Denis Vlasenko7f2527e2007-03-14 22:11:20 +000090 return "[NONE SET]";
Eric Andersenf15d4da2001-03-06 00:48:59 +000091
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +000092 if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap,
93 numeric, 0xffffff00) != 0)
Denis Vlasenkoaad49992006-11-22 02:12:07 +000094 return NULL;
Eric Andersenf15d4da2001-03-06 00:48:59 +000095
Denis Vlasenkoaad49992006-11-22 02:12:07 +000096 return buff;
Eric Andersenf15d4da2001-03-06 00:48:59 +000097}
98
Denis Vlasenko7f2527e2007-03-14 22:11:20 +000099#ifdef UNUSED_AND_BUGGY
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000100static int INET_getsock(char *bufp, struct sockaddr *sap)
101{
102 char *sp = bufp, *bp;
103 unsigned int i;
104 unsigned val;
105 struct sockaddr_in *sock_in;
106
107 sock_in = (struct sockaddr_in *) sap;
108 sock_in->sin_family = AF_INET;
109 sock_in->sin_port = 0;
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000110
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000111 val = 0;
112 bp = (char *) &val;
113 for (i = 0; i < sizeof(sock_in->sin_addr.s_addr); i++) {
114 *sp = toupper(*sp);
115
116 if ((unsigned)(*sp - 'A') <= 5)
117 bp[i] |= (int) (*sp - ('A' - 10));
118 else if (isdigit(*sp))
119 bp[i] |= (int) (*sp - '0');
120 else
121 return -1;
122
123 bp[i] <<= 4;
124 sp++;
125 *sp = toupper(*sp);
126
127 if ((unsigned)(*sp - 'A') <= 5)
128 bp[i] |= (int) (*sp - ('A' - 10));
129 else if (isdigit(*sp))
130 bp[i] |= (int) (*sp - '0');
131 else
132 return -1;
133
134 sp++;
135 }
136 sock_in->sin_addr.s_addr = htonl(val);
137
138 return (sp - bufp);
139}
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000140#endif
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000141
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000142static int INET_input(/*int type,*/ const char *bufp, struct sockaddr *sap)
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000143{
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000144 return INET_resolve(bufp, (struct sockaddr_in *) sap, 0);
145/*
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000146 switch (type) {
147 case 1:
148 return (INET_getsock(bufp, sap));
149 case 256:
150 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 1));
151 default:
152 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0));
153 }
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000154*/
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000155}
156
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000157static const struct aftype inet_aftype = {
Rob Landley2818b292006-06-20 15:52:52 +0000158 .name = "inet",
159 .title = "DARPA Internet",
160 .af = AF_INET,
Rob Landley9fe801e2006-06-20 21:13:29 +0000161 .alen = 4,
Rob Landley2818b292006-06-20 15:52:52 +0000162 .sprint = INET_sprint,
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000163 .input = INET_input,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000164};
165
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000166#ifdef HAVE_AFINET6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000167
Eric Andersen51b8bd62002-07-03 11:46:38 +0000168/* Display an Internet socket address. */
169/* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000170static const char *INET6_sprint(struct sockaddr *sap, int numeric)
Eric Andersen51b8bd62002-07-03 11:46:38 +0000171{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000172 static char buff[128];
Eric Andersen51b8bd62002-07-03 11:46:38 +0000173
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000174 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000175 return "[NONE SET]";
Denis Vlasenko322661d2007-01-29 23:43:52 +0000176 if (INET6_rresolve(buff, sizeof(buff), (struct sockaddr_in6 *) sap, numeric))
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000177 return "[UNKNOWN]";
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000178 return buff;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000179}
180
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000181#ifdef UNUSED
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000182static int INET6_getsock(char *bufp, struct sockaddr *sap)
183{
184 struct sockaddr_in6 *sin6;
185
186 sin6 = (struct sockaddr_in6 *) sap;
187 sin6->sin6_family = AF_INET6;
188 sin6->sin6_port = 0;
189
190 if (inet_pton(AF_INET6, bufp, sin6->sin6_addr.s6_addr) <= 0)
191 return -1;
192
193 return 16; /* ?;) */
194}
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000195#endif
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000196
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000197static int INET6_input(/*int type,*/ const char *bufp, struct sockaddr *sap)
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000198{
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000199 return INET6_resolve(bufp, (struct sockaddr_in6 *) sap);
200/*
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000201 switch (type) {
202 case 1:
203 return (INET6_getsock(bufp, sap));
204 default:
205 return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap));
206 }
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000207*/
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000208}
209
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000210static const struct aftype inet6_aftype = {
Rob Landley2818b292006-06-20 15:52:52 +0000211 .name = "inet6",
212 .title = "IPv6",
213 .af = AF_INET6,
214 .alen = sizeof(struct in6_addr),
215 .sprint = INET6_sprint,
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000216 .input = INET6_input,
Eric Andersen51b8bd62002-07-03 11:46:38 +0000217};
218
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000219#endif /* HAVE_AFINET6 */
Eric Andersen51b8bd62002-07-03 11:46:38 +0000220
Eric Andersenf15d4da2001-03-06 00:48:59 +0000221/* Display an UNSPEC address. */
222static char *UNSPEC_print(unsigned char *ptr)
223{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000224 static char buff[sizeof(struct sockaddr) * 3 + 1];
225 char *pos;
226 unsigned int i;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000227
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 Vlasenko04b30ba2006-11-21 14:26:37 +0000344int 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) {
525 perror("SIOCGIFCONF");
526 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{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000551 static int proc_read;
552 FILE *fh;
553 char buf[512];
554 struct interface *ife;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000555 int err, procnetdev_vsn;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000556
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000557 if (proc_read)
558 return 0;
559 if (!target)
560 proc_read = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000561
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000562 fh = fopen(_PATH_PROCNET_DEV, "r");
563 if (!fh) {
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000564 bb_perror_msg("warning: cannot open %s, limiting output", _PATH_PROCNET_DEV);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000565 return if_readconf();
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000566 }
567 fgets(buf, sizeof buf, fh); /* eat line */
568 fgets(buf, sizeof buf, fh);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000569
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000570 procnetdev_vsn = procnetdev_version(buf);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000571
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000572 err = 0;
573 while (fgets(buf, sizeof buf, fh)) {
Eric Andersenf96675b2003-07-28 06:37:04 +0000574 char *s, name[128];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000575
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000576 s = get_name(name, buf);
577 ife = add_interface(name);
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000578 get_dev_fields(s, ife, procnetdev_vsn);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000579 ife->statistics_valid = 1;
580 if (target && !strcmp(target, name))
581 break;
582 }
583 if (ferror(fh)) {
584 perror(_PATH_PROCNET_DEV);
585 err = -1;
586 proc_read = 0;
587 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000588 fclose(fh);
589 return err;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000590}
591
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000592static int if_readlist(void)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000593{
Denis Vlasenkod0587ed2007-03-22 19:35:51 +0000594 int err = if_readlist_proc(NULL);
595 /* Needed in order to get ethN:M aliases */
596 if (!err)
597 err = if_readconf();
598 return err;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000599}
600
601static int for_all_interfaces(int (*doit) (struct interface *, void *),
602 void *cookie)
603{
604 struct interface *ife;
605
606 if (!int_list && (if_readlist() < 0))
607 return -1;
608 for (ife = int_list; ife; ife = ife->next) {
609 int err = doit(ife, cookie);
610
611 if (err)
612 return err;
613 }
614 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000615}
616
Eric Andersenf15d4da2001-03-06 00:48:59 +0000617/* Fetch the interface configuration from the kernel. */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000618static int if_fetch(struct interface *ife)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000619{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000620 struct ifreq ifr;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000621 char *ifname = ife->name;
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000622 int skfd;
623
624 skfd = xsocket(AF_INET, SOCK_DGRAM, 0);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000625
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000626 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000627 if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
628 close(skfd);
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000629 return -1;
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000630 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000631 ife->flags = ifr.ifr_flags;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000632
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000633 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000634 memset(ife->hwaddr, 0, 32);
635 if (ioctl(skfd, SIOCGIFHWADDR, &ifr) >= 0)
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000636 memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000637
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000638 ife->type = ifr.ifr_hwaddr.sa_family;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000639
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000640 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000641 ife->metric = 0;
642 if (ioctl(skfd, SIOCGIFMETRIC, &ifr) >= 0)
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000643 ife->metric = ifr.ifr_metric;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000644
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000645 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000646 ife->mtu = 0;
647 if (ioctl(skfd, SIOCGIFMTU, &ifr) >= 0)
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000648 ife->mtu = ifr.ifr_mtu;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000649
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000650 memset(&ife->map, 0, sizeof(struct ifmap));
Rob Landley93983042005-05-03 21:30:26 +0000651#ifdef SIOCGIFMAP
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000652 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Rob Landley93983042005-05-03 21:30:26 +0000653 if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0)
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000654 ife->map = ifr.ifr_map;
Rob Landley93983042005-05-03 21:30:26 +0000655#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +0000656
657#ifdef HAVE_TXQUEUELEN
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000658 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000659 ife->tx_queue_len = -1; /* unknown value */
660 if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) >= 0)
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000661 ife->tx_queue_len = ifr.ifr_qlen;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000662#else
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000663 ife->tx_queue_len = -1; /* unknown value */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000664#endif
665
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000666 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
667 ifr.ifr_addr.sa_family = AF_INET;
668 memset(&ife->addr, 0, sizeof(struct sockaddr));
669 if (ioctl(skfd, SIOCGIFADDR, &ifr) == 0) {
670 ife->has_ip = 1;
671 ife->addr = ifr.ifr_addr;
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000672 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000673 memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
674 if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) >= 0)
675 ife->dstaddr = ifr.ifr_dstaddr;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000676
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000677 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
678 memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
679 if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) >= 0)
680 ife->broadaddr = ifr.ifr_broadaddr;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000681
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000682 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
683 memset(&ife->netmask, 0, sizeof(struct sockaddr));
684 if (ioctl(skfd, SIOCGIFNETMASK, &ifr) >= 0)
685 ife->netmask = ifr.ifr_netmask;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000686 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000687
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000688 close(skfd);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000689 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000690}
691
692
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000693static int do_if_fetch(struct interface *ife)
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000694{
695 if (if_fetch(ife) < 0) {
Denis Vlasenko322661d2007-01-29 23:43:52 +0000696 const char *errmsg;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000697
698 if (errno == ENODEV) {
699 /* Give better error message for this case. */
Rob Landley4e3aff32006-05-29 04:37:28 +0000700 errmsg = "Device not found";
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000701 } else {
702 errmsg = strerror(errno);
703 }
Rob Landley4e3aff32006-05-29 04:37:28 +0000704 bb_error_msg("%s: error fetching interface information: %s",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000705 ife->name, errmsg);
706 return -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000707 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000708 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000709}
710
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000711static const struct hwtype unspec_hwtype = {
"Robert P. J. Day"4137dd72006-06-26 21:54:57 +0000712 .name = "unspec",
713 .title = "UNSPEC",
714 .type = -1,
715 .print = UNSPEC_print
Eric Andersenf15d4da2001-03-06 00:48:59 +0000716};
717
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000718static const struct hwtype loop_hwtype = {
"Robert P. J. Day"4137dd72006-06-26 21:54:57 +0000719 .name = "loop",
720 .title = "Local Loopback",
721 .type = ARPHRD_LOOPBACK
Eric Andersenf15d4da2001-03-06 00:48:59 +0000722};
723
Eric Andersenf15d4da2001-03-06 00:48:59 +0000724#include <net/if_arp.h>
Eric Andersenab4e19a2003-01-14 08:54:08 +0000725
Denis Vlasenko83e5d6f2006-12-18 21:49:06 +0000726#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined(_NEWLIB_VERSION)
Eric Andersenab4e19a2003-01-14 08:54:08 +0000727#include <net/ethernet.h>
728#else
Eric Andersenf15d4da2001-03-06 00:48:59 +0000729#include <linux/if_ether.h>
Eric Andersenab4e19a2003-01-14 08:54:08 +0000730#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +0000731
Eric Andersenf15d4da2001-03-06 00:48:59 +0000732/* Display an Ethernet address in readable format. */
733static char *pr_ether(unsigned char *ptr)
734{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000735 static char buff[64];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000736
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000737 snprintf(buff, sizeof(buff), "%02X:%02X:%02X:%02X:%02X:%02X",
738 (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377),
739 (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)
740 );
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000741 return buff;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000742}
743
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000744static int in_ether(const char *bufp, struct sockaddr *sap);
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000745
746static struct hwtype ether_hwtype = {
"Robert P. J. Day"4137dd72006-06-26 21:54:57 +0000747 .name = "ether",
748 .title = "Ethernet",
749 .type = ARPHRD_ETHER,
750 .alen = ETH_ALEN,
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000751 .print = pr_ether,
752 .input = in_ether
Eric Andersenf15d4da2001-03-06 00:48:59 +0000753};
754
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000755static unsigned hexchar2int(char c)
756{
757 if (isdigit(c))
758 return c - '0';
759 c &= ~0x20; /* a -> A */
760 if ((unsigned)(c - 'A') <= 5)
761 return c - ('A' - 10);
762 return ~0U;
763}
764
765/* Input an Ethernet address and convert to binary. */
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000766static int in_ether(const char *bufp, struct sockaddr *sap)
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000767{
768 unsigned char *ptr;
Denis Vlasenko7f2527e2007-03-14 22:11:20 +0000769 char c;
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000770 int i;
771 unsigned val;
772
773 sap->sa_family = ether_hwtype.type;
Denis Vlasenko731d3572007-02-02 01:16:33 +0000774 ptr = (unsigned char*) sap->sa_data;
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000775
776 i = 0;
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000777 while ((*bufp != '\0') && (i < ETH_ALEN)) {
778 val = hexchar2int(*bufp++) * 0x10;
779 if (val > 0xff) {
780 errno = EINVAL;
781 return -1;
782 }
783 c = *bufp;
784 if (c == ':' || c == 0)
785 val >>= 4;
786 else {
787 val |= hexchar2int(c);
788 if (val > 0xff) {
789 errno = EINVAL;
790 return -1;
791 }
792 }
793 if (c != 0)
794 bufp++;
795 *ptr++ = (unsigned char) val;
796 i++;
797
798 /* We might get a semicolon here - not required. */
799 if (*bufp == ':') {
800 bufp++;
801 }
802 }
803 return 0;
804}
805
Eric Andersenf15d4da2001-03-06 00:48:59 +0000806#include <net/if_arp.h>
807
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000808static const struct hwtype ppp_hwtype = {
"Robert P. J. Day"4137dd72006-06-26 21:54:57 +0000809 .name = "ppp",
810 .title = "Point-to-Point Protocol",
811 .type = ARPHRD_PPP
Eric Andersenf15d4da2001-03-06 00:48:59 +0000812};
813
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000814#if ENABLE_FEATURE_IPV6
"Robert P. J. Day"21302c22006-06-26 22:03:43 +0000815static const struct hwtype sit_hwtype = {
816 .name = "sit",
817 .title = "IPv6-in-IPv4",
818 .type = ARPHRD_SIT,
819 .print = UNSPEC_print,
820 .suppress_null_addr = 1
821} ;
822#endif
823
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000824static const struct hwtype *const hwtypes[] = {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000825 &loop_hwtype,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000826 &ether_hwtype,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000827 &ppp_hwtype,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000828 &unspec_hwtype,
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000829#if ENABLE_FEATURE_IPV6
"Robert P. J. Day"21302c22006-06-26 22:03:43 +0000830 &sit_hwtype,
831#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000832 NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +0000833};
834
Eric Andersenf15d4da2001-03-06 00:48:59 +0000835#ifdef IFF_PORTSEL
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000836static const char *const if_port_text[] = {
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000837 /* Keep in step with <linux/netdevice.h> */
838 "unknown",
839 "10base2",
840 "10baseT",
841 "AUI",
842 "100baseT",
843 "100baseTX",
844 "100baseFX",
845 NULL
846};
847#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +0000848
849/* Check our hardware type table for this type. */
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000850const struct hwtype *get_hwtype(const char *name)
851{
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000852 const struct hwtype *const *hwp;
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000853
854 hwp = hwtypes;
855 while (*hwp != NULL) {
856 if (!strcmp((*hwp)->name, name))
857 return (*hwp);
858 hwp++;
859 }
860 return NULL;
861}
862
863/* Check our hardware type table for this type. */
864const struct hwtype *get_hwntype(int type)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000865{
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000866 const struct hwtype *const *hwp;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000867
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000868 hwp = hwtypes;
869 while (*hwp != NULL) {
870 if ((*hwp)->type == type)
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000871 return *hwp;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000872 hwp++;
873 }
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000874 return NULL;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000875}
876
877/* return 1 if address is all zeros */
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000878static int hw_null_address(const struct hwtype *hw, void *ap)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000879{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000880 unsigned int i;
881 unsigned char *address = (unsigned char *) ap;
882
883 for (i = 0; i < hw->alen; i++)
884 if (address[i])
885 return 0;
886 return 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000887}
888
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000889static const char TRext[] = "\0\0\0Ki\0Mi\0Gi\0Ti";
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000890
891static void print_bytes_scaled(unsigned long long ull, const char *end)
892{
893 unsigned long long int_part;
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000894 const char *ext;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000895 unsigned int frac_part;
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000896 int i;
897
898 frac_part = 0;
899 ext = TRext;
900 int_part = ull;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000901 i = 4;
902 do {
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000903 if (int_part >= 1024) {
904 frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
905 int_part /= 1024;
906 ext += 3; /* KiB, MiB, GiB, TiB */
907 }
908 --i;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000909 } while (i);
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000910
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000911 printf("X bytes:%llu (%llu.%u %sB)%s", ull, int_part, frac_part, ext, end);
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000912}
913
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000914static const char *const ife_print_flags_strs[] = {
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000915 "UP ",
916 "BROADCAST ",
917 "DEBUG ",
918 "LOOPBACK ",
919 "POINTOPOINT ",
920 "NOTRAILERS ",
921 "RUNNING ",
922 "NOARP ",
923 "PROMISC ",
924 "ALLMULTI ",
925 "SLAVE ",
926 "MASTER ",
927 "MULTICAST ",
928#ifdef HAVE_DYNAMIC
929 "DYNAMIC "
930#endif
931};
932
933static const unsigned short ife_print_flags_mask[] = {
934 IFF_UP,
935 IFF_BROADCAST,
936 IFF_DEBUG,
937 IFF_LOOPBACK,
938 IFF_POINTOPOINT,
939 IFF_NOTRAILERS,
940 IFF_RUNNING,
941 IFF_NOARP,
942 IFF_PROMISC,
943 IFF_ALLMULTI,
944 IFF_SLAVE,
945 IFF_MASTER,
946 IFF_MULTICAST,
947#ifdef HAVE_DYNAMIC
948 IFF_DYNAMIC
949#endif
950 0
951};
952
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000953static void ife_print(struct interface *ptr)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000954{
Denis Vlasenko1cc70222007-03-15 19:46:43 +0000955 const struct aftype *ap;
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000956 const struct hwtype *hw;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000957 int hf;
958 int can_compress = 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000959
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000960#ifdef HAVE_AFINET6
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000961 FILE *f;
962 char addr6[40], devname[20];
963 struct sockaddr_in6 sap;
964 int plen, scope, dad_status, if_idx;
965 char addr6p[8][5];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000966#endif
967
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000968 ap = get_afntype(ptr->addr.sa_family);
969 if (ap == NULL)
970 ap = get_afntype(0);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000971
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000972 hf = ptr->type;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000973
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000974 if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
975 can_compress = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000976
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000977 hw = get_hwntype(hf);
978 if (hw == NULL)
979 hw = get_hwntype(-1);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000980
Rob Landley4e3aff32006-05-29 04:37:28 +0000981 printf("%-9.9s Link encap:%s ", ptr->name, hw->title);
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000982 /* For some hardware types (eg Ash, ATM) we don't print the
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000983 hardware address if it's null. */
984 if (hw->print != NULL && (!(hw_null_address(hw, ptr->hwaddr) &&
985 hw->suppress_null_addr)))
Rob Landley4e3aff32006-05-29 04:37:28 +0000986 printf("HWaddr %s ", hw->print((unsigned char *)ptr->hwaddr));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000987#ifdef IFF_PORTSEL
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000988 if (ptr->flags & IFF_PORTSEL) {
Rob Landley4e3aff32006-05-29 04:37:28 +0000989 printf("Media:%s", if_port_text[ptr->map.port] /* [0] */);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000990 if (ptr->flags & IFF_AUTOMEDIA)
Rob Landley4e3aff32006-05-29 04:37:28 +0000991 printf("(auto)");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000992 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000993#endif
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +0000994 puts("");
Eric Andersenf15d4da2001-03-06 00:48:59 +0000995
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000996 if (ptr->has_ip) {
Rob Landley4e3aff32006-05-29 04:37:28 +0000997 printf(" %s addr:%s ", ap->name,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000998 ap->sprint(&ptr->addr, 1));
999 if (ptr->flags & IFF_POINTOPOINT) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001000 printf(" P-t-P:%s ", ap->sprint(&ptr->dstaddr, 1));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001001 }
1002 if (ptr->flags & IFF_BROADCAST) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001003 printf(" Bcast:%s ", ap->sprint(&ptr->broadaddr, 1));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001004 }
Rob Landley4e3aff32006-05-29 04:37:28 +00001005 printf(" Mask:%s\n", ap->sprint(&ptr->netmask, 1));
Eric Andersenf15d4da2001-03-06 00:48:59 +00001006 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001007
Denis Vlasenkoaad49992006-11-22 02:12:07 +00001008#ifdef HAVE_AFINET6
Eric Andersenf15d4da2001-03-06 00:48:59 +00001009
Eric Andersen51b8bd62002-07-03 11:46:38 +00001010#define IPV6_ADDR_ANY 0x0000U
1011
1012#define IPV6_ADDR_UNICAST 0x0001U
1013#define IPV6_ADDR_MULTICAST 0x0002U
1014#define IPV6_ADDR_ANYCAST 0x0004U
1015
1016#define IPV6_ADDR_LOOPBACK 0x0010U
1017#define IPV6_ADDR_LINKLOCAL 0x0020U
1018#define IPV6_ADDR_SITELOCAL 0x0040U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001019
Eric Andersen51b8bd62002-07-03 11:46:38 +00001020#define IPV6_ADDR_COMPATv4 0x0080U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001021
Eric Andersen51b8bd62002-07-03 11:46:38 +00001022#define IPV6_ADDR_SCOPE_MASK 0x00f0U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001023
Eric Andersen51b8bd62002-07-03 11:46:38 +00001024#define IPV6_ADDR_MAPPED 0x1000U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001025#define IPV6_ADDR_RESERVED 0x2000U /* reserved address space */
1026
Denis Vlasenkoad67a392007-02-09 18:26:52 +00001027 f = fopen(_PATH_PROCNET_IFINET6, "r");
1028 if (f != NULL) {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001029 while (fscanf
1030 (f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
1031 addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
1032 addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope,
Denis Vlasenkoad67a392007-02-09 18:26:52 +00001033 &dad_status, devname) != EOF
1034 ) {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001035 if (!strcmp(devname, ptr->name)) {
1036 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
1037 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
1038 addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
1039 inet_pton(AF_INET6, addr6,
1040 (struct sockaddr *) &sap.sin6_addr);
1041 sap.sin6_family = AF_INET6;
Rob Landley4e3aff32006-05-29 04:37:28 +00001042 printf(" inet6 addr: %s/%d",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001043 inet6_aftype.sprint((struct sockaddr *) &sap, 1),
1044 plen);
Rob Landley4e3aff32006-05-29 04:37:28 +00001045 printf(" Scope:");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001046 switch (scope & IPV6_ADDR_SCOPE_MASK) {
1047 case 0:
Rob Landley4e3aff32006-05-29 04:37:28 +00001048 printf("Global");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001049 break;
1050 case IPV6_ADDR_LINKLOCAL:
Rob Landley4e3aff32006-05-29 04:37:28 +00001051 printf("Link");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001052 break;
1053 case IPV6_ADDR_SITELOCAL:
Rob Landley4e3aff32006-05-29 04:37:28 +00001054 printf("Site");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001055 break;
1056 case IPV6_ADDR_COMPATv4:
Rob Landley4e3aff32006-05-29 04:37:28 +00001057 printf("Compat");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001058 break;
1059 case IPV6_ADDR_LOOPBACK:
Rob Landley4e3aff32006-05-29 04:37:28 +00001060 printf("Host");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001061 break;
1062 default:
Rob Landley4e3aff32006-05-29 04:37:28 +00001063 printf("Unknown");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001064 }
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00001065 puts("");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001066 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001067 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001068 fclose(f);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001069 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001070#endif
1071
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001072 printf(" ");
1073 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001074
1075 if (ptr->flags == 0) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001076 printf("[NO FLAGS] ");
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001077 } else {
1078 int i = 0;
1079 do {
1080 if (ptr->flags & ife_print_flags_mask[i]) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001081 printf(ife_print_flags_strs[i]);
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001082 }
1083 } while (ife_print_flags_mask[++i]);
1084 }
1085
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001086 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
Rob Landley4e3aff32006-05-29 04:37:28 +00001087 printf(" MTU:%d Metric:%d", ptr->mtu, ptr->metric ? ptr->metric : 1);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001088#ifdef SIOCSKEEPALIVE
1089 if (ptr->outfill || ptr->keepalive)
Rob Landley4e3aff32006-05-29 04:37:28 +00001090 printf(" Outfill:%d Keepalive:%d", ptr->outfill, ptr->keepalive);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001091#endif
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00001092 puts("");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001093
1094 /* If needed, display the interface statistics. */
1095
1096 if (ptr->statistics_valid) {
1097 /* XXX: statistics are currently only printed for the primary address,
1098 * not for the aliases, although strictly speaking they're shared
1099 * by all addresses.
1100 */
1101 printf(" ");
1102
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001103 printf("RX packets:%llu errors:%lu dropped:%lu overruns:%lu frame:%lu\n",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001104 ptr->stats.rx_packets, ptr->stats.rx_errors,
1105 ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors,
1106 ptr->stats.rx_frame_errors);
1107 if (can_compress)
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001108 printf(" compressed:%lu\n",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001109 ptr->stats.rx_compressed);
1110 printf(" ");
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001111 printf("TX packets:%llu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001112 ptr->stats.tx_packets, ptr->stats.tx_errors,
1113 ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
1114 ptr->stats.tx_carrier_errors);
Bernhard Reutner-Fischer214744d2006-03-30 13:38:19 +00001115 printf(" collisions:%lu ", ptr->stats.collisions);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001116 if (can_compress)
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001117 printf("compressed:%lu ", ptr->stats.tx_compressed);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001118 if (ptr->tx_queue_len != -1)
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001119 printf("txqueuelen:%d ", ptr->tx_queue_len);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001120 printf("\n R");
1121 print_bytes_scaled(ptr->stats.rx_bytes, " T");
1122 print_bytes_scaled(ptr->stats.tx_bytes, "\n");
1123
1124 }
1125
1126 if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
1127 ptr->map.base_addr)) {
1128 printf(" ");
1129 if (ptr->map.irq)
Rob Landley4e3aff32006-05-29 04:37:28 +00001130 printf("Interrupt:%d ", ptr->map.irq);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001131 if (ptr->map.base_addr >= 0x100) /* Only print devices using it for
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001132 I/O maps */
Rob Landley4e3aff32006-05-29 04:37:28 +00001133 printf("Base address:0x%lx ",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001134 (unsigned long) ptr->map.base_addr);
1135 if (ptr->map.mem_start) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001136 printf("Memory:%lx-%lx ", ptr->map.mem_start,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001137 ptr->map.mem_end);
1138 }
1139 if (ptr->map.dma)
Rob Landley4e3aff32006-05-29 04:37:28 +00001140 printf("DMA chan:%x ", ptr->map.dma);
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00001141 puts("");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001142 }
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00001143 puts("");
Eric Andersenf15d4da2001-03-06 00:48:59 +00001144}
1145
1146
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001147static int do_if_print(struct interface *ife, void *cookie)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001148{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001149 int *opt_a = (int *) cookie;
1150 int res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001151
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001152 res = do_if_fetch(ife);
1153 if (res >= 0) {
1154 if ((ife->flags & IFF_UP) || *opt_a)
1155 ife_print(ife);
1156 }
1157 return res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001158}
1159
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001160static struct interface *lookup_interface(char *name)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001161{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001162 struct interface *ife = NULL;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001163
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001164 if (if_readlist_proc(name) < 0)
1165 return NULL;
1166 ife = add_interface(name);
1167 return ife;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001168}
1169
1170/* for ipv4 add/del modes */
1171static int if_print(char *ifname)
1172{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001173 int res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001174
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001175 if (!ifname) {
1176 res = for_all_interfaces(do_if_print, &interface_opt_a);
1177 } else {
1178 struct interface *ife;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001179
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001180 ife = lookup_interface(ifname);
1181 res = do_if_fetch(ife);
1182 if (res >= 0)
1183 ife_print(ife);
1184 }
1185 return res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001186}
1187
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001188int display_interfaces(char *ifname)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001189{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001190 int status;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001191
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001192 status = if_print(ifname);
Denis Vlasenko1cc70222007-03-15 19:46:43 +00001193
1194 return (status < 0); /* status < 0 == 1 -- error */
Eric Andersenf15d4da2001-03-06 00:48:59 +00001195}