blob: c0347123816848a9303be928e3aecad41edc347d [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
Glenn L McGrathb54a7482003-08-29 11:34:08 +000039#ifdef CONFIG_FEATURE_IPV6
40# 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. */
85static char *INET_sprint(struct sockaddr *sap, int numeric)
86{
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)
Rob Landley4e3aff32006-05-29 04:37:28 +000090 return safe_strncpy(buff, "[NONE SET]", sizeof(buff));
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 Vlasenkofa85b862007-01-07 01:24:12 +000099static int INET_getsock(char *bufp, struct sockaddr *sap)
100{
101 char *sp = bufp, *bp;
102 unsigned int i;
103 unsigned val;
104 struct sockaddr_in *sock_in;
105
106 sock_in = (struct sockaddr_in *) sap;
107 sock_in->sin_family = AF_INET;
108 sock_in->sin_port = 0;
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000109
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000110 val = 0;
111 bp = (char *) &val;
112 for (i = 0; i < sizeof(sock_in->sin_addr.s_addr); i++) {
113 *sp = toupper(*sp);
114
115 if ((unsigned)(*sp - 'A') <= 5)
116 bp[i] |= (int) (*sp - ('A' - 10));
117 else if (isdigit(*sp))
118 bp[i] |= (int) (*sp - '0');
119 else
120 return -1;
121
122 bp[i] <<= 4;
123 sp++;
124 *sp = toupper(*sp);
125
126 if ((unsigned)(*sp - 'A') <= 5)
127 bp[i] |= (int) (*sp - ('A' - 10));
128 else if (isdigit(*sp))
129 bp[i] |= (int) (*sp - '0');
130 else
131 return -1;
132
133 sp++;
134 }
135 sock_in->sin_addr.s_addr = htonl(val);
136
137 return (sp - bufp);
138}
139
140static int INET_input(int type, char *bufp, struct sockaddr *sap)
141{
142 switch (type) {
143 case 1:
144 return (INET_getsock(bufp, sap));
145 case 256:
146 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 1));
147 default:
148 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0));
149 }
150}
151
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000152static struct aftype inet_aftype = {
Rob Landley2818b292006-06-20 15:52:52 +0000153 .name = "inet",
154 .title = "DARPA Internet",
155 .af = AF_INET,
Rob Landley9fe801e2006-06-20 21:13:29 +0000156 .alen = 4,
Rob Landley2818b292006-06-20 15:52:52 +0000157 .sprint = INET_sprint,
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000158 .input = INET_input,
Rob Landley2818b292006-06-20 15:52:52 +0000159 .fd = -1
Eric Andersenf15d4da2001-03-06 00:48:59 +0000160};
161
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000162#ifdef HAVE_AFINET6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000163
Eric Andersen51b8bd62002-07-03 11:46:38 +0000164/* Display an Internet socket address. */
165/* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */
166static char *INET6_sprint(struct sockaddr *sap, int numeric)
167{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000168 static char buff[128];
Eric Andersen51b8bd62002-07-03 11:46:38 +0000169
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000170 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
Rob Landley4e3aff32006-05-29 04:37:28 +0000171 return safe_strncpy(buff, "[NONE SET]", sizeof(buff));
Denis Vlasenko322661d2007-01-29 23:43:52 +0000172 if (INET6_rresolve(buff, sizeof(buff), (struct sockaddr_in6 *) sap, numeric))
Rob Landley4e3aff32006-05-29 04:37:28 +0000173 return safe_strncpy(buff, "[UNKNOWN]", sizeof(buff));
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000174 return buff;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000175}
176
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000177static int INET6_getsock(char *bufp, struct sockaddr *sap)
178{
179 struct sockaddr_in6 *sin6;
180
181 sin6 = (struct sockaddr_in6 *) sap;
182 sin6->sin6_family = AF_INET6;
183 sin6->sin6_port = 0;
184
185 if (inet_pton(AF_INET6, bufp, sin6->sin6_addr.s6_addr) <= 0)
186 return -1;
187
188 return 16; /* ?;) */
189}
190
191static int INET6_input(int type, char *bufp, struct sockaddr *sap)
192{
193 switch (type) {
194 case 1:
195 return (INET6_getsock(bufp, sap));
196 default:
197 return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap));
198 }
199}
200
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000201static struct aftype inet6_aftype = {
Rob Landley2818b292006-06-20 15:52:52 +0000202 .name = "inet6",
203 .title = "IPv6",
204 .af = AF_INET6,
205 .alen = sizeof(struct in6_addr),
206 .sprint = INET6_sprint,
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000207 .input = INET6_input,
Rob Landley2818b292006-06-20 15:52:52 +0000208 .fd = -1
Eric Andersen51b8bd62002-07-03 11:46:38 +0000209};
210
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000211#endif /* HAVE_AFINET6 */
Eric Andersen51b8bd62002-07-03 11:46:38 +0000212
Eric Andersenf15d4da2001-03-06 00:48:59 +0000213/* Display an UNSPEC address. */
214static char *UNSPEC_print(unsigned char *ptr)
215{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000216 static char buff[sizeof(struct sockaddr) * 3 + 1];
217 char *pos;
218 unsigned int i;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000219
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000220 pos = buff;
221 for (i = 0; i < sizeof(struct sockaddr); i++) {
222 /* careful -- not every libc's sprintf returns # bytes written */
223 sprintf(pos, "%02X-", (*ptr++ & 0377));
224 pos += 3;
225 }
226 /* Erase trailing "-". Works as long as sizeof(struct sockaddr) != 0 */
227 *--pos = '\0';
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000228 return buff;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000229}
230
231/* Display an UNSPEC socket address. */
232static char *UNSPEC_sprint(struct sockaddr *sap, int numeric)
233{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000234 static char buf[64];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000235
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000236 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
Rob Landley4e3aff32006-05-29 04:37:28 +0000237 return safe_strncpy(buf, "[NONE SET]", sizeof(buf));
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000238 return UNSPEC_print((unsigned char *)sap->sa_data);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000239}
240
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000241static struct aftype unspec_aftype = {
242 "unspec", "UNSPEC", AF_UNSPEC, 0,
243 UNSPEC_print, UNSPEC_sprint, NULL, NULL,
244 NULL,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000245};
246
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000247static struct aftype * const aftypes[] = {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000248 &inet_aftype,
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000249#ifdef HAVE_AFINET6
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000250 &inet6_aftype,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000251#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000252 &unspec_aftype,
253 NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +0000254};
255
Eric Andersenf15d4da2001-03-06 00:48:59 +0000256/* Check our protocol family table for this family. */
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000257struct aftype *get_aftype(const char *name)
258{
259 struct aftype * const *afp;
260
261 afp = aftypes;
262 while (*afp != NULL) {
263 if (!strcmp((*afp)->name, name))
264 return (*afp);
265 afp++;
266 }
267 return NULL;
268}
269
270/* Check our protocol family table for this family. */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000271static struct aftype *get_afntype(int af)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000272{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000273 struct aftype * const *afp;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000274
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000275 afp = aftypes;
276 while (*afp != NULL) {
277 if ((*afp)->af == af)
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000278 return *afp;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000279 afp++;
280 }
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000281 return NULL;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000282}
283
284/* Check our protocol family table for this family and return its socket */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000285static int get_socket_for_af(int af)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000286{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000287 struct aftype * const *afp;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000288
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000289 afp = aftypes;
290 while (*afp != NULL) {
291 if ((*afp)->af == af)
292 return (*afp)->fd;
293 afp++;
294 }
295 return -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000296}
297
Eric Andersenf15d4da2001-03-06 00:48:59 +0000298struct user_net_device_stats {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000299 unsigned long long rx_packets; /* total packets received */
300 unsigned long long tx_packets; /* total packets transmitted */
301 unsigned long long rx_bytes; /* total bytes received */
302 unsigned long long tx_bytes; /* total bytes transmitted */
303 unsigned long rx_errors; /* bad packets received */
304 unsigned long tx_errors; /* packet transmit problems */
305 unsigned long rx_dropped; /* no space in linux buffers */
306 unsigned long tx_dropped; /* no space available in linux */
307 unsigned long rx_multicast; /* multicast packets received */
308 unsigned long rx_compressed;
309 unsigned long tx_compressed;
310 unsigned long collisions;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000311
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000312 /* detailed rx_errors: */
313 unsigned long rx_length_errors;
314 unsigned long rx_over_errors; /* receiver ring buff overflow */
315 unsigned long rx_crc_errors; /* recved pkt with crc error */
316 unsigned long rx_frame_errors; /* recv'd frame alignment error */
317 unsigned long rx_fifo_errors; /* recv'r fifo overrun */
318 unsigned long rx_missed_errors; /* receiver missed packet */
319 /* detailed tx_errors */
320 unsigned long tx_aborted_errors;
321 unsigned long tx_carrier_errors;
322 unsigned long tx_fifo_errors;
323 unsigned long tx_heartbeat_errors;
324 unsigned long tx_window_errors;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000325};
326
327struct interface {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000328 struct interface *next, *prev;
329 char name[IFNAMSIZ]; /* interface name */
330 short type; /* if type */
331 short flags; /* various flags */
332 int metric; /* routing metric */
333 int mtu; /* MTU value */
334 int tx_queue_len; /* transmit queue length */
335 struct ifmap map; /* hardware setup */
336 struct sockaddr addr; /* IP address */
337 struct sockaddr dstaddr; /* P-P IP address */
338 struct sockaddr broadaddr; /* IP broadcast address */
339 struct sockaddr netmask; /* IP network mask */
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000340 int has_ip;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000341 char hwaddr[32]; /* HW address */
342 int statistics_valid;
343 struct user_net_device_stats stats; /* statistics */
344 int keepalive; /* keepalive value for SLIP */
345 int outfill; /* outfill value for SLIP */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000346};
347
348
Denis Vlasenko04b30ba2006-11-21 14:26:37 +0000349int interface_opt_a; /* show all interfaces */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000350
Eric Andersenf15d4da2001-03-06 00:48:59 +0000351static struct interface *int_list, *int_last;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000352static int skfd = -1; /* generic raw socket desc. */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000353
354
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000355static int sockets_open(int family)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000356{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000357 struct aftype * const *aft;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000358 int sfd = -1;
359 static int force = -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000360
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000361 if (force < 0) {
362 force = 0;
Bernhard Reutner-Fischere2e56c72006-05-19 11:54:02 +0000363 if (get_linux_version_code() < KERNEL_VERSION(2,1,0))
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000364 force = 1;
365 if (access("/proc/net", R_OK))
366 force = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000367 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000368 for (aft = aftypes; *aft; aft++) {
369 struct aftype *af = *aft;
370 int type = SOCK_DGRAM;
371
372 if (af->af == AF_UNSPEC)
373 continue;
374 if (family && family != af->af)
375 continue;
376 if (af->fd != -1) {
377 sfd = af->fd;
378 continue;
379 }
380 /* Check some /proc file first to not stress kmod */
381 if (!family && !force && af->flag_file) {
382 if (access(af->flag_file, R_OK))
383 continue;
384 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000385 af->fd = socket(af->af, type, 0);
386 if (af->fd >= 0)
387 sfd = af->fd;
388 }
Glenn L McGrath642f2892002-11-28 10:20:45 +0000389 if (sfd < 0) {
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000390 bb_error_msg("no usable address families found");
Glenn L McGrath642f2892002-11-28 10:20:45 +0000391 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000392 return sfd;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000393}
394
Rob Landley93983042005-05-03 21:30:26 +0000395#ifdef CONFIG_FEATURE_CLEAN_UP
396static void sockets_close(void)
397{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000398 struct aftype * const *aft;
Rob Landley93983042005-05-03 21:30:26 +0000399 for (aft = aftypes; *aft != NULL; aft++) {
400 struct aftype *af = *aft;
401 if( af->fd != -1 ) {
402 close(af->fd);
403 af->fd = -1;
404 }
405 }
406}
407#endif
Bernhard Reutner-Fischer57d83ff2006-12-07 12:25:17 +0000408#if 0
Eric Andersenf15d4da2001-03-06 00:48:59 +0000409/* like strcmp(), but knows about numbers */
Bernhard Reutner-Fischer57d83ff2006-12-07 12:25:17 +0000410except that the freshly added calls to xatoul() brf on ethernet aliases with
411uClibc with e.g.: ife->name='lo' name='eth0:1'
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000412static int nstrcmp(const char *a, const char *b)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000413{
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000414 const char *a_ptr = a;
415 const char *b_ptr = b;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000416
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000417 while (*a == *b) {
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000418 if (*a == '\0') {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000419 return 0;
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000420 }
421 if (!isdigit(*a) && isdigit(*(a+1))) {
422 a_ptr = a+1;
423 b_ptr = b+1;
424 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000425 a++;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000426 b++;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000427 }
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000428
429 if (isdigit(*a) && isdigit(*b)) {
Denis Vlasenko13858992006-10-08 12:49:22 +0000430 return xatoul(a_ptr) > xatoul(b_ptr) ? 1 : -1;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000431 }
432 return *a - *b;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000433}
Bernhard Reutner-Fischer57d83ff2006-12-07 12:25:17 +0000434#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +0000435
436static struct interface *add_interface(char *name)
437{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000438 struct interface *ife, **nextp, *new;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000439
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000440 for (ife = int_last; ife; ife = ife->prev) {
Bernhard Reutner-Fischer57d83ff2006-12-07 12:25:17 +0000441 int n = /*n*/strcmp(ife->name, name);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000442
443 if (n == 0)
444 return ife;
445 if (n < 0)
446 break;
447 }
Rob Landleya6e131d2006-05-29 06:43:55 +0000448
449 new = xzalloc(sizeof(*new));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000450 safe_strncpy(new->name, name, IFNAMSIZ);
451 nextp = ife ? &ife->next : &int_list;
452 new->prev = ife;
453 new->next = *nextp;
454 if (new->next)
455 new->next->prev = new;
456 else
457 int_last = new;
458 *nextp = new;
459 return new;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000460}
461
462
463static int if_readconf(void)
464{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000465 int numreqs = 30;
466 struct ifconf ifc;
467 struct ifreq *ifr;
468 int n, err = -1;
469 int skfd2;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000470
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000471 /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
472 (as of 2.1.128) */
473 skfd2 = get_socket_for_af(AF_INET);
474 if (skfd2 < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000475 bb_perror_msg(("warning: no inet socket available"));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000476 /* Try to soldier on with whatever socket we can get hold of. */
477 skfd2 = sockets_open(0);
478 if (skfd2 < 0)
479 return -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000480 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000481
482 ifc.ifc_buf = NULL;
483 for (;;) {
484 ifc.ifc_len = sizeof(struct ifreq) * numreqs;
485 ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);
486
487 if (ioctl(skfd2, SIOCGIFCONF, &ifc) < 0) {
488 perror("SIOCGIFCONF");
489 goto out;
490 }
491 if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
492 /* assume it overflowed and try again */
493 numreqs += 10;
494 continue;
495 }
496 break;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000497 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000498
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000499 ifr = ifc.ifc_req;
500 for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
501 add_interface(ifr->ifr_name);
502 ifr++;
503 }
504 err = 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000505
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000506 out:
507 free(ifc.ifc_buf);
508 return err;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000509}
510
Eric Andersen14f5c8d2005-04-16 19:39:00 +0000511static char *get_name(char *name, char *p)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000512{
Rob Landley9fe801e2006-06-20 21:13:29 +0000513 /* Extract <name> from nul-terminated p where p matches
514 <name>: after leading whitespace.
Eric Andersen9940e082004-08-12 16:52:00 +0000515 If match is not made, set name empty and return unchanged p */
Rob Landley9fe801e2006-06-20 21:13:29 +0000516 int namestart=0, nameend=0;
Eric Andersen9940e082004-08-12 16:52:00 +0000517 while (isspace(p[namestart]))
518 namestart++;
519 nameend=namestart;
520 while (p[nameend] && p[nameend]!=':' && !isspace(p[nameend]))
521 nameend++;
522 if (p[nameend]==':') {
Eric Andersen9940e082004-08-12 16:52:00 +0000523 if ((nameend-namestart)<IFNAMSIZ) {
524 memcpy(name,&p[namestart],nameend-namestart);
525 name[nameend-namestart]='\0';
526 p=&p[nameend];
527 } else {
528 /* Interface name too large */
529 name[0]='\0';
530 }
531 } else {
Rob Landley9fe801e2006-06-20 21:13:29 +0000532 /* trailing ':' not found - return empty */
Eric Andersen9940e082004-08-12 16:52:00 +0000533 name[0]='\0';
Eric Andersenf15d4da2001-03-06 00:48:59 +0000534 }
Eric Andersen6fea7322004-08-26 21:45:21 +0000535 return p + 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000536}
537
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000538/* If scanf supports size qualifiers for %n conversions, then we can
539 * use a modified fmt that simply stores the position in the fields
540 * having no associated fields in the proc string. Of course, we need
541 * to zero them again when we're done. But that is smaller than the
542 * old approach of multiple scanf occurrences with large numbers of
543 * args. */
544
Bernhard Reutner-Fischera901b402006-01-19 14:51:17 +0000545/* static const char * const ss_fmt[] = { */
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000546/* "%lln%llu%lu%lu%lu%lu%ln%ln%lln%llu%lu%lu%lu%lu%lu", */
547/* "%llu%llu%lu%lu%lu%lu%ln%ln%llu%llu%lu%lu%lu%lu%lu", */
548/* "%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 +0000549/* }; */
550
551 /* Lie about the size of the int pointed to for %n. */
552#if INT_MAX == LONG_MAX
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000553static const char * const ss_fmt[] = {
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000554 "%n%llu%u%u%u%u%n%n%n%llu%u%u%u%u%u",
555 "%llu%llu%u%u%u%u%n%n%llu%llu%u%u%u%u%u",
556 "%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 +0000557};
558#else
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000559static const char * const ss_fmt[] = {
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000560 "%n%llu%lu%lu%lu%lu%n%n%n%llu%lu%lu%lu%lu%lu",
561 "%llu%llu%lu%lu%lu%lu%n%n%llu%llu%lu%lu%lu%lu%lu",
562 "%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 +0000563};
564
565#endif
566
567static void get_dev_fields(char *bp, struct interface *ife, int procnetdev_vsn)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000568{
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000569 memset(&ife->stats, 0, sizeof(struct user_net_device_stats));
570
571 sscanf(bp, ss_fmt[procnetdev_vsn],
572 &ife->stats.rx_bytes, /* missing for 0 */
573 &ife->stats.rx_packets,
574 &ife->stats.rx_errors,
575 &ife->stats.rx_dropped,
576 &ife->stats.rx_fifo_errors,
577 &ife->stats.rx_frame_errors,
578 &ife->stats.rx_compressed, /* missing for <= 1 */
579 &ife->stats.rx_multicast, /* missing for <= 1 */
580 &ife->stats.tx_bytes, /* missing for 0 */
581 &ife->stats.tx_packets,
582 &ife->stats.tx_errors,
583 &ife->stats.tx_dropped,
584 &ife->stats.tx_fifo_errors,
585 &ife->stats.collisions,
586 &ife->stats.tx_carrier_errors,
587 &ife->stats.tx_compressed /* missing for <= 1 */
588 );
589
590 if (procnetdev_vsn <= 1) {
591 if (procnetdev_vsn == 0) {
592 ife->stats.rx_bytes = 0;
593 ife->stats.tx_bytes = 0;
594 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000595 ife->stats.rx_multicast = 0;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000596 ife->stats.rx_compressed = 0;
597 ife->stats.tx_compressed = 0;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000598 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000599}
600
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000601static inline int procnetdev_version(char *buf)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000602{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000603 if (strstr(buf, "compressed"))
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000604 return 2;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000605 if (strstr(buf, "bytes"))
606 return 1;
607 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000608}
609
610static int if_readlist_proc(char *target)
611{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000612 static int proc_read;
613 FILE *fh;
614 char buf[512];
615 struct interface *ife;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000616 int err, procnetdev_vsn;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000617
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000618 if (proc_read)
619 return 0;
620 if (!target)
621 proc_read = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000622
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000623 fh = fopen(_PATH_PROCNET_DEV, "r");
624 if (!fh) {
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000625 bb_perror_msg("warning: cannot open %s, limiting output", _PATH_PROCNET_DEV);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000626 return if_readconf();
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000627 }
628 fgets(buf, sizeof buf, fh); /* eat line */
629 fgets(buf, sizeof buf, fh);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000630
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000631 procnetdev_vsn = procnetdev_version(buf);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000632
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000633 err = 0;
634 while (fgets(buf, sizeof buf, fh)) {
Eric Andersenf96675b2003-07-28 06:37:04 +0000635 char *s, name[128];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000636
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000637 s = get_name(name, buf);
638 ife = add_interface(name);
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000639 get_dev_fields(s, ife, procnetdev_vsn);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000640 ife->statistics_valid = 1;
641 if (target && !strcmp(target, name))
642 break;
643 }
644 if (ferror(fh)) {
645 perror(_PATH_PROCNET_DEV);
646 err = -1;
647 proc_read = 0;
648 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000649 fclose(fh);
650 return err;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000651}
652
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000653static int if_readlist(void)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000654{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000655 int err = if_readlist_proc(NULL);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000656
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000657 if (!err)
658 err = if_readconf();
659 return err;
660}
661
662static int for_all_interfaces(int (*doit) (struct interface *, void *),
663 void *cookie)
664{
665 struct interface *ife;
666
667 if (!int_list && (if_readlist() < 0))
668 return -1;
669 for (ife = int_list; ife; ife = ife->next) {
670 int err = doit(ife, cookie);
671
672 if (err)
673 return err;
674 }
675 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000676}
677
Eric Andersenf15d4da2001-03-06 00:48:59 +0000678/* Fetch the interface configuration from the kernel. */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000679static int if_fetch(struct interface *ife)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000680{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000681 struct ifreq ifr;
682 int fd;
683 char *ifname = ife->name;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000684
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000685 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000686 if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000687 return -1;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000688 ife->flags = ifr.ifr_flags;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000689
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000690 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000691 if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
692 memset(ife->hwaddr, 0, 32);
693 else
694 memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000695
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000696 ife->type = ifr.ifr_hwaddr.sa_family;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000697
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000698 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000699 if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0)
700 ife->metric = 0;
701 else
702 ife->metric = ifr.ifr_metric;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000703
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000704 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000705 if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
706 ife->mtu = 0;
707 else
708 ife->mtu = ifr.ifr_mtu;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000709
Rob Landley93983042005-05-03 21:30:26 +0000710#ifdef SIOCGIFMAP
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000711 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Rob Landley93983042005-05-03 21:30:26 +0000712 if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0)
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000713 ife->map = ifr.ifr_map;
Rob Landley93983042005-05-03 21:30:26 +0000714 else
715#endif
716 memset(&ife->map, 0, sizeof(struct ifmap));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000717
718#ifdef HAVE_TXQUEUELEN
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000719 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000720 if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0)
721 ife->tx_queue_len = -1; /* unknown value */
722 else
723 ife->tx_queue_len = ifr.ifr_qlen;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000724#else
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000725 ife->tx_queue_len = -1; /* unknown value */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000726#endif
727
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000728 /* IPv4 address? */
729 fd = get_socket_for_af(AF_INET);
730 if (fd >= 0) {
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000731 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000732 ifr.ifr_addr.sa_family = AF_INET;
733 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
734 ife->has_ip = 1;
735 ife->addr = ifr.ifr_addr;
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000736 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000737 if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0)
738 memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
739 else
740 ife->dstaddr = ifr.ifr_dstaddr;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000741
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000742 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000743 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
744 memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
745 else
746 ife->broadaddr = ifr.ifr_broadaddr;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000747
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000748 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000749 if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
750 memset(&ife->netmask, 0, sizeof(struct sockaddr));
751 else
752 ife->netmask = ifr.ifr_netmask;
753 } else
754 memset(&ife->addr, 0, sizeof(struct sockaddr));
755 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000756
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000757 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000758}
759
760
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000761static int do_if_fetch(struct interface *ife)
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000762{
763 if (if_fetch(ife) < 0) {
Denis Vlasenko322661d2007-01-29 23:43:52 +0000764 const char *errmsg;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000765
766 if (errno == ENODEV) {
767 /* Give better error message for this case. */
Rob Landley4e3aff32006-05-29 04:37:28 +0000768 errmsg = "Device not found";
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000769 } else {
770 errmsg = strerror(errno);
771 }
Rob Landley4e3aff32006-05-29 04:37:28 +0000772 bb_error_msg("%s: error fetching interface information: %s",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000773 ife->name, errmsg);
774 return -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000775 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000776 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000777}
778
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000779static const struct hwtype unspec_hwtype = {
"Robert P. J. Day"4137dd72006-06-26 21:54:57 +0000780 .name = "unspec",
781 .title = "UNSPEC",
782 .type = -1,
783 .print = UNSPEC_print
Eric Andersenf15d4da2001-03-06 00:48:59 +0000784};
785
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000786static const struct hwtype loop_hwtype = {
"Robert P. J. Day"4137dd72006-06-26 21:54:57 +0000787 .name = "loop",
788 .title = "Local Loopback",
789 .type = ARPHRD_LOOPBACK
Eric Andersenf15d4da2001-03-06 00:48:59 +0000790};
791
Eric Andersenf15d4da2001-03-06 00:48:59 +0000792#include <net/if_arp.h>
Eric Andersenab4e19a2003-01-14 08:54:08 +0000793
Denis Vlasenko83e5d6f2006-12-18 21:49:06 +0000794#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined(_NEWLIB_VERSION)
Eric Andersenab4e19a2003-01-14 08:54:08 +0000795#include <net/ethernet.h>
796#else
Eric Andersenf15d4da2001-03-06 00:48:59 +0000797#include <linux/if_ether.h>
Eric Andersenab4e19a2003-01-14 08:54:08 +0000798#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +0000799
Eric Andersenf15d4da2001-03-06 00:48:59 +0000800/* Display an Ethernet address in readable format. */
801static char *pr_ether(unsigned char *ptr)
802{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000803 static char buff[64];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000804
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000805 snprintf(buff, sizeof(buff), "%02X:%02X:%02X:%02X:%02X:%02X",
806 (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377),
807 (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)
808 );
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000809 return buff;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000810}
811
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000812static int in_ether(char *bufp, struct sockaddr *sap);
813
814static struct hwtype ether_hwtype = {
"Robert P. J. Day"4137dd72006-06-26 21:54:57 +0000815 .name = "ether",
816 .title = "Ethernet",
817 .type = ARPHRD_ETHER,
818 .alen = ETH_ALEN,
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000819 .print = pr_ether,
820 .input = in_ether
Eric Andersenf15d4da2001-03-06 00:48:59 +0000821};
822
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000823static unsigned hexchar2int(char c)
824{
825 if (isdigit(c))
826 return c - '0';
827 c &= ~0x20; /* a -> A */
828 if ((unsigned)(c - 'A') <= 5)
829 return c - ('A' - 10);
830 return ~0U;
831}
832
833/* Input an Ethernet address and convert to binary. */
834static int in_ether(char *bufp, struct sockaddr *sap)
835{
836 unsigned char *ptr;
837 char c, *orig;
838 int i;
839 unsigned val;
840
841 sap->sa_family = ether_hwtype.type;
Denis Vlasenko731d3572007-02-02 01:16:33 +0000842 ptr = (unsigned char*) sap->sa_data;
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000843
844 i = 0;
845 orig = bufp;
846 while ((*bufp != '\0') && (i < ETH_ALEN)) {
847 val = hexchar2int(*bufp++) * 0x10;
848 if (val > 0xff) {
849 errno = EINVAL;
850 return -1;
851 }
852 c = *bufp;
853 if (c == ':' || c == 0)
854 val >>= 4;
855 else {
856 val |= hexchar2int(c);
857 if (val > 0xff) {
858 errno = EINVAL;
859 return -1;
860 }
861 }
862 if (c != 0)
863 bufp++;
864 *ptr++ = (unsigned char) val;
865 i++;
866
867 /* We might get a semicolon here - not required. */
868 if (*bufp == ':') {
869 bufp++;
870 }
871 }
872 return 0;
873}
874
Eric Andersenf15d4da2001-03-06 00:48:59 +0000875#include <net/if_arp.h>
876
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000877static const struct hwtype ppp_hwtype = {
"Robert P. J. Day"4137dd72006-06-26 21:54:57 +0000878 .name = "ppp",
879 .title = "Point-to-Point Protocol",
880 .type = ARPHRD_PPP
Eric Andersenf15d4da2001-03-06 00:48:59 +0000881};
882
"Robert P. J. Day"21302c22006-06-26 22:03:43 +0000883#ifdef CONFIG_FEATURE_IPV6
884static const struct hwtype sit_hwtype = {
885 .name = "sit",
886 .title = "IPv6-in-IPv4",
887 .type = ARPHRD_SIT,
888 .print = UNSPEC_print,
889 .suppress_null_addr = 1
890} ;
891#endif
892
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000893static const struct hwtype * const hwtypes[] = {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000894 &loop_hwtype,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000895 &ether_hwtype,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000896 &ppp_hwtype,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000897 &unspec_hwtype,
"Robert P. J. Day"21302c22006-06-26 22:03:43 +0000898#ifdef CONFIG_FEATURE_IPV6
899 &sit_hwtype,
900#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000901 NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +0000902};
903
Eric Andersenf15d4da2001-03-06 00:48:59 +0000904#ifdef IFF_PORTSEL
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000905static const char * const if_port_text[] = {
906 /* Keep in step with <linux/netdevice.h> */
907 "unknown",
908 "10base2",
909 "10baseT",
910 "AUI",
911 "100baseT",
912 "100baseTX",
913 "100baseFX",
914 NULL
915};
916#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +0000917
918/* Check our hardware type table for this type. */
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000919const struct hwtype *get_hwtype(const char *name)
920{
921 const struct hwtype * const *hwp;
922
923 hwp = hwtypes;
924 while (*hwp != NULL) {
925 if (!strcmp((*hwp)->name, name))
926 return (*hwp);
927 hwp++;
928 }
929 return NULL;
930}
931
932/* Check our hardware type table for this type. */
933const struct hwtype *get_hwntype(int type)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000934{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000935 const struct hwtype * const *hwp;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000936
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000937 hwp = hwtypes;
938 while (*hwp != NULL) {
939 if ((*hwp)->type == type)
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000940 return *hwp;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000941 hwp++;
942 }
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000943 return NULL;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000944}
945
946/* return 1 if address is all zeros */
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000947static int hw_null_address(const struct hwtype *hw, void *ap)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000948{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000949 unsigned int i;
950 unsigned char *address = (unsigned char *) ap;
951
952 for (i = 0; i < hw->alen; i++)
953 if (address[i])
954 return 0;
955 return 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000956}
957
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000958static const char TRext[] = "\0\0\0Ki\0Mi\0Gi\0Ti";
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000959
960static void print_bytes_scaled(unsigned long long ull, const char *end)
961{
962 unsigned long long int_part;
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000963 const char *ext;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000964 unsigned int frac_part;
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000965 int i;
966
967 frac_part = 0;
968 ext = TRext;
969 int_part = ull;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000970 i = 4;
971 do {
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000972 if (int_part >= 1024) {
973 frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
974 int_part /= 1024;
975 ext += 3; /* KiB, MiB, GiB, TiB */
976 }
977 --i;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000978 } while (i);
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000979
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000980 printf("X bytes:%llu (%llu.%u %sB)%s", ull, int_part, frac_part, ext, end);
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000981}
982
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000983static const char * const ife_print_flags_strs[] = {
984 "UP ",
985 "BROADCAST ",
986 "DEBUG ",
987 "LOOPBACK ",
988 "POINTOPOINT ",
989 "NOTRAILERS ",
990 "RUNNING ",
991 "NOARP ",
992 "PROMISC ",
993 "ALLMULTI ",
994 "SLAVE ",
995 "MASTER ",
996 "MULTICAST ",
997#ifdef HAVE_DYNAMIC
998 "DYNAMIC "
999#endif
1000};
1001
1002static const unsigned short ife_print_flags_mask[] = {
1003 IFF_UP,
1004 IFF_BROADCAST,
1005 IFF_DEBUG,
1006 IFF_LOOPBACK,
1007 IFF_POINTOPOINT,
1008 IFF_NOTRAILERS,
1009 IFF_RUNNING,
1010 IFF_NOARP,
1011 IFF_PROMISC,
1012 IFF_ALLMULTI,
1013 IFF_SLAVE,
1014 IFF_MASTER,
1015 IFF_MULTICAST,
1016#ifdef HAVE_DYNAMIC
1017 IFF_DYNAMIC
1018#endif
1019 0
1020};
1021
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001022static void ife_print(struct interface *ptr)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001023{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001024 struct aftype *ap;
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +00001025 const struct hwtype *hw;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001026 int hf;
1027 int can_compress = 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001028
Denis Vlasenkoaad49992006-11-22 02:12:07 +00001029#ifdef HAVE_AFINET6
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001030 FILE *f;
1031 char addr6[40], devname[20];
1032 struct sockaddr_in6 sap;
1033 int plen, scope, dad_status, if_idx;
1034 char addr6p[8][5];
Eric Andersenf15d4da2001-03-06 00:48:59 +00001035#endif
1036
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001037 ap = get_afntype(ptr->addr.sa_family);
1038 if (ap == NULL)
1039 ap = get_afntype(0);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001040
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001041 hf = ptr->type;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001042
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001043 if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
1044 can_compress = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001045
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001046 hw = get_hwntype(hf);
1047 if (hw == NULL)
1048 hw = get_hwntype(-1);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001049
Rob Landley4e3aff32006-05-29 04:37:28 +00001050 printf("%-9.9s Link encap:%s ", ptr->name, hw->title);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001051 /* For some hardware types (eg Ash, ATM) we don't print the
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001052 hardware address if it's null. */
1053 if (hw->print != NULL && (!(hw_null_address(hw, ptr->hwaddr) &&
1054 hw->suppress_null_addr)))
Rob Landley4e3aff32006-05-29 04:37:28 +00001055 printf("HWaddr %s ", hw->print((unsigned char *)ptr->hwaddr));
Eric Andersenf15d4da2001-03-06 00:48:59 +00001056#ifdef IFF_PORTSEL
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001057 if (ptr->flags & IFF_PORTSEL) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001058 printf("Media:%s", if_port_text[ptr->map.port] /* [0] */);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001059 if (ptr->flags & IFF_AUTOMEDIA)
Rob Landley4e3aff32006-05-29 04:37:28 +00001060 printf("(auto)");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001061 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001062#endif
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00001063 puts("");
Eric Andersenf15d4da2001-03-06 00:48:59 +00001064
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001065 if (ptr->has_ip) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001066 printf(" %s addr:%s ", ap->name,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001067 ap->sprint(&ptr->addr, 1));
1068 if (ptr->flags & IFF_POINTOPOINT) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001069 printf(" P-t-P:%s ", ap->sprint(&ptr->dstaddr, 1));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001070 }
1071 if (ptr->flags & IFF_BROADCAST) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001072 printf(" Bcast:%s ", ap->sprint(&ptr->broadaddr, 1));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001073 }
Rob Landley4e3aff32006-05-29 04:37:28 +00001074 printf(" Mask:%s\n", ap->sprint(&ptr->netmask, 1));
Eric Andersenf15d4da2001-03-06 00:48:59 +00001075 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001076
Denis Vlasenkoaad49992006-11-22 02:12:07 +00001077#ifdef HAVE_AFINET6
Eric Andersenf15d4da2001-03-06 00:48:59 +00001078
Eric Andersen51b8bd62002-07-03 11:46:38 +00001079#define IPV6_ADDR_ANY 0x0000U
1080
1081#define IPV6_ADDR_UNICAST 0x0001U
1082#define IPV6_ADDR_MULTICAST 0x0002U
1083#define IPV6_ADDR_ANYCAST 0x0004U
1084
1085#define IPV6_ADDR_LOOPBACK 0x0010U
1086#define IPV6_ADDR_LINKLOCAL 0x0020U
1087#define IPV6_ADDR_SITELOCAL 0x0040U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001088
Eric Andersen51b8bd62002-07-03 11:46:38 +00001089#define IPV6_ADDR_COMPATv4 0x0080U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001090
Eric Andersen51b8bd62002-07-03 11:46:38 +00001091#define IPV6_ADDR_SCOPE_MASK 0x00f0U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001092
Eric Andersen51b8bd62002-07-03 11:46:38 +00001093#define IPV6_ADDR_MAPPED 0x1000U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001094#define IPV6_ADDR_RESERVED 0x2000U /* reserved address space */
1095
Denis Vlasenkoad67a392007-02-09 18:26:52 +00001096 f = fopen(_PATH_PROCNET_IFINET6, "r");
1097 if (f != NULL) {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001098 while (fscanf
1099 (f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
1100 addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
1101 addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope,
Denis Vlasenkoad67a392007-02-09 18:26:52 +00001102 &dad_status, devname) != EOF
1103 ) {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001104 if (!strcmp(devname, ptr->name)) {
1105 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
1106 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
1107 addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
1108 inet_pton(AF_INET6, addr6,
1109 (struct sockaddr *) &sap.sin6_addr);
1110 sap.sin6_family = AF_INET6;
Rob Landley4e3aff32006-05-29 04:37:28 +00001111 printf(" inet6 addr: %s/%d",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001112 inet6_aftype.sprint((struct sockaddr *) &sap, 1),
1113 plen);
Rob Landley4e3aff32006-05-29 04:37:28 +00001114 printf(" Scope:");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001115 switch (scope & IPV6_ADDR_SCOPE_MASK) {
1116 case 0:
Rob Landley4e3aff32006-05-29 04:37:28 +00001117 printf("Global");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001118 break;
1119 case IPV6_ADDR_LINKLOCAL:
Rob Landley4e3aff32006-05-29 04:37:28 +00001120 printf("Link");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001121 break;
1122 case IPV6_ADDR_SITELOCAL:
Rob Landley4e3aff32006-05-29 04:37:28 +00001123 printf("Site");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001124 break;
1125 case IPV6_ADDR_COMPATv4:
Rob Landley4e3aff32006-05-29 04:37:28 +00001126 printf("Compat");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001127 break;
1128 case IPV6_ADDR_LOOPBACK:
Rob Landley4e3aff32006-05-29 04:37:28 +00001129 printf("Host");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001130 break;
1131 default:
Rob Landley4e3aff32006-05-29 04:37:28 +00001132 printf("Unknown");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001133 }
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00001134 puts("");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001135 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001136 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001137 fclose(f);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001138 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001139#endif
1140
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001141 printf(" ");
1142 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001143
1144 if (ptr->flags == 0) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001145 printf("[NO FLAGS] ");
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001146 } else {
1147 int i = 0;
1148 do {
1149 if (ptr->flags & ife_print_flags_mask[i]) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001150 printf(ife_print_flags_strs[i]);
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001151 }
1152 } while (ife_print_flags_mask[++i]);
1153 }
1154
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001155 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
Rob Landley4e3aff32006-05-29 04:37:28 +00001156 printf(" MTU:%d Metric:%d", ptr->mtu, ptr->metric ? ptr->metric : 1);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001157#ifdef SIOCSKEEPALIVE
1158 if (ptr->outfill || ptr->keepalive)
Rob Landley4e3aff32006-05-29 04:37:28 +00001159 printf(" Outfill:%d Keepalive:%d", ptr->outfill, ptr->keepalive);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001160#endif
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00001161 puts("");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001162
1163 /* If needed, display the interface statistics. */
1164
1165 if (ptr->statistics_valid) {
1166 /* XXX: statistics are currently only printed for the primary address,
1167 * not for the aliases, although strictly speaking they're shared
1168 * by all addresses.
1169 */
1170 printf(" ");
1171
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001172 printf("RX packets:%llu errors:%lu dropped:%lu overruns:%lu frame:%lu\n",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001173 ptr->stats.rx_packets, ptr->stats.rx_errors,
1174 ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors,
1175 ptr->stats.rx_frame_errors);
1176 if (can_compress)
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001177 printf(" compressed:%lu\n",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001178 ptr->stats.rx_compressed);
1179 printf(" ");
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001180 printf("TX packets:%llu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001181 ptr->stats.tx_packets, ptr->stats.tx_errors,
1182 ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
1183 ptr->stats.tx_carrier_errors);
Bernhard Reutner-Fischer214744d2006-03-30 13:38:19 +00001184 printf(" collisions:%lu ", ptr->stats.collisions);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001185 if (can_compress)
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001186 printf("compressed:%lu ", ptr->stats.tx_compressed);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001187 if (ptr->tx_queue_len != -1)
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001188 printf("txqueuelen:%d ", ptr->tx_queue_len);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001189 printf("\n R");
1190 print_bytes_scaled(ptr->stats.rx_bytes, " T");
1191 print_bytes_scaled(ptr->stats.tx_bytes, "\n");
1192
1193 }
1194
1195 if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
1196 ptr->map.base_addr)) {
1197 printf(" ");
1198 if (ptr->map.irq)
Rob Landley4e3aff32006-05-29 04:37:28 +00001199 printf("Interrupt:%d ", ptr->map.irq);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001200 if (ptr->map.base_addr >= 0x100) /* Only print devices using it for
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001201 I/O maps */
Rob Landley4e3aff32006-05-29 04:37:28 +00001202 printf("Base address:0x%lx ",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001203 (unsigned long) ptr->map.base_addr);
1204 if (ptr->map.mem_start) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001205 printf("Memory:%lx-%lx ", ptr->map.mem_start,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001206 ptr->map.mem_end);
1207 }
1208 if (ptr->map.dma)
Rob Landley4e3aff32006-05-29 04:37:28 +00001209 printf("DMA chan:%x ", ptr->map.dma);
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00001210 puts("");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001211 }
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00001212 puts("");
Eric Andersenf15d4da2001-03-06 00:48:59 +00001213}
1214
1215
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001216static int do_if_print(struct interface *ife, void *cookie)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001217{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001218 int *opt_a = (int *) cookie;
1219 int res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001220
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001221 res = do_if_fetch(ife);
1222 if (res >= 0) {
1223 if ((ife->flags & IFF_UP) || *opt_a)
1224 ife_print(ife);
1225 }
1226 return res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001227}
1228
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001229static struct interface *lookup_interface(char *name)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001230{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001231 struct interface *ife = NULL;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001232
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001233 if (if_readlist_proc(name) < 0)
1234 return NULL;
1235 ife = add_interface(name);
1236 return ife;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001237}
1238
1239/* for ipv4 add/del modes */
1240static int if_print(char *ifname)
1241{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001242 int res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001243
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001244 if (!ifname) {
1245 res = for_all_interfaces(do_if_print, &interface_opt_a);
1246 } else {
1247 struct interface *ife;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001248
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001249 ife = lookup_interface(ifname);
1250 res = do_if_fetch(ife);
1251 if (res >= 0)
1252 ife_print(ife);
1253 }
1254 return res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001255}
1256
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001257int display_interfaces(char *ifname)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001258{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001259 int status;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001260
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001261 /* Create a channel to the NET kernel. */
1262 if ((skfd = sockets_open(0)) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +00001263 bb_perror_msg_and_die("socket");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001264 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001265
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001266 /* Do we have to show the current setup? */
1267 status = if_print(ifname);
Rob Landley93983042005-05-03 21:30:26 +00001268#ifdef CONFIG_FEATURE_CLEAN_UP
1269 sockets_close();
1270#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001271 exit(status < 0);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001272}