blob: fbcf50152e56f529df3af5d88d57df9612ccf876 [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 "inet_common.h"
Eric Andersenf15d4da2001-03-06 00:48:59 +000035#include <stdio.h>
36#include <errno.h>
Eric Andersenf15d4da2001-03-06 00:48:59 +000037#include <stdlib.h>
38#include <string.h>
39#include <unistd.h>
Eric Andersencd8c4362001-11-10 11:22:46 +000040#include <fcntl.h>
41#include <ctype.h>
42#include <sys/ioctl.h>
Eric Andersen85e5e722003-07-22 08:56:55 +000043#include <sys/types.h>
Eric Andersencd8c4362001-11-10 11:22:46 +000044#include <net/if.h>
45#include <net/if_arp.h>
Bernhard Reutner-Fischerfa939aa2006-04-05 16:21:37 +000046#include "busybox.h"
Eric Andersenf15d4da2001-03-06 00:48:59 +000047
Glenn L McGrathb54a7482003-08-29 11:34:08 +000048#ifdef CONFIG_FEATURE_IPV6
49# define HAVE_AFINET6 1
50#else
51# undef HAVE_AFINET6
52#endif
53
Eric Andersenf15d4da2001-03-06 00:48:59 +000054#define _PATH_PROCNET_DEV "/proc/net/dev"
Eric Andersen51b8bd62002-07-03 11:46:38 +000055#define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"
Eric Andersenf15d4da2001-03-06 00:48:59 +000056
Denis Vlasenkoaad49992006-11-22 02:12:07 +000057#ifdef HAVE_AFINET6
Eric Andersenf15d4da2001-03-06 00:48:59 +000058
59#ifndef _LINUX_IN6_H
60/*
61 * This is in linux/include/net/ipv6.h.
62 */
63
64struct in6_ifreq {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +000065 struct in6_addr ifr6_addr;
Glenn L McGrathb54a7482003-08-29 11:34:08 +000066 uint32_t ifr6_prefixlen;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +000067 unsigned int ifr6_ifindex;
Eric Andersenf15d4da2001-03-06 00:48:59 +000068};
69
70#endif
71
Denis Vlasenkoaad49992006-11-22 02:12:07 +000072#endif /* HAVE_AFINET6 */
Eric Andersenf15d4da2001-03-06 00:48:59 +000073
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +000074/* Defines for glibc2.0 users. */
75#ifndef SIOCSIFTXQLEN
76#define SIOCSIFTXQLEN 0x8943
77#define SIOCGIFTXQLEN 0x8942
78#endif
79
80/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
81#ifndef ifr_qlen
82#define ifr_qlen ifr_ifru.ifru_mtu
83#endif
84
85#ifndef HAVE_TXQUEUELEN
86#define HAVE_TXQUEUELEN 1
87#endif
88
89#ifndef IFF_DYNAMIC
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +000090#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +000091#endif
92
Eric Andersenf15d4da2001-03-06 00:48:59 +000093/* Display an Internet socket address. */
94static char *INET_sprint(struct sockaddr *sap, int numeric)
95{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +000096 static char buff[128];
Eric Andersenf15d4da2001-03-06 00:48:59 +000097
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +000098 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
Rob Landley4e3aff32006-05-29 04:37:28 +000099 return safe_strncpy(buff, "[NONE SET]", sizeof(buff));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000100
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000101 if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap,
102 numeric, 0xffffff00) != 0)
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000103 return NULL;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000104
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000105 return buff;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000106}
107
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000108static int INET_getsock(char *bufp, struct sockaddr *sap)
109{
110 char *sp = bufp, *bp;
111 unsigned int i;
112 unsigned val;
113 struct sockaddr_in *sock_in;
114
115 sock_in = (struct sockaddr_in *) sap;
116 sock_in->sin_family = AF_INET;
117 sock_in->sin_port = 0;
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000118
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000119 val = 0;
120 bp = (char *) &val;
121 for (i = 0; i < sizeof(sock_in->sin_addr.s_addr); i++) {
122 *sp = toupper(*sp);
123
124 if ((unsigned)(*sp - 'A') <= 5)
125 bp[i] |= (int) (*sp - ('A' - 10));
126 else if (isdigit(*sp))
127 bp[i] |= (int) (*sp - '0');
128 else
129 return -1;
130
131 bp[i] <<= 4;
132 sp++;
133 *sp = toupper(*sp);
134
135 if ((unsigned)(*sp - 'A') <= 5)
136 bp[i] |= (int) (*sp - ('A' - 10));
137 else if (isdigit(*sp))
138 bp[i] |= (int) (*sp - '0');
139 else
140 return -1;
141
142 sp++;
143 }
144 sock_in->sin_addr.s_addr = htonl(val);
145
146 return (sp - bufp);
147}
148
149static int INET_input(int type, char *bufp, struct sockaddr *sap)
150{
151 switch (type) {
152 case 1:
153 return (INET_getsock(bufp, sap));
154 case 256:
155 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 1));
156 default:
157 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0));
158 }
159}
160
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000161static struct aftype inet_aftype = {
Rob Landley2818b292006-06-20 15:52:52 +0000162 .name = "inet",
163 .title = "DARPA Internet",
164 .af = AF_INET,
Rob Landley9fe801e2006-06-20 21:13:29 +0000165 .alen = 4,
Rob Landley2818b292006-06-20 15:52:52 +0000166 .sprint = INET_sprint,
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000167 .input = INET_input,
Rob Landley2818b292006-06-20 15:52:52 +0000168 .fd = -1
Eric Andersenf15d4da2001-03-06 00:48:59 +0000169};
170
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000171#ifdef HAVE_AFINET6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000172
Eric Andersen51b8bd62002-07-03 11:46:38 +0000173/* Display an Internet socket address. */
174/* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */
175static char *INET6_sprint(struct sockaddr *sap, int numeric)
176{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000177 static char buff[128];
Eric Andersen51b8bd62002-07-03 11:46:38 +0000178
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000179 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
Rob Landley4e3aff32006-05-29 04:37:28 +0000180 return safe_strncpy(buff, "[NONE SET]", sizeof(buff));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000181 if (INET6_rresolve
182 (buff, sizeof(buff), (struct sockaddr_in6 *) sap, numeric) != 0)
Rob Landley4e3aff32006-05-29 04:37:28 +0000183 return safe_strncpy(buff, "[UNKNOWN]", sizeof(buff));
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000184 return buff;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000185}
186
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000187static int INET6_getsock(char *bufp, struct sockaddr *sap)
188{
189 struct sockaddr_in6 *sin6;
190
191 sin6 = (struct sockaddr_in6 *) sap;
192 sin6->sin6_family = AF_INET6;
193 sin6->sin6_port = 0;
194
195 if (inet_pton(AF_INET6, bufp, sin6->sin6_addr.s6_addr) <= 0)
196 return -1;
197
198 return 16; /* ?;) */
199}
200
201static int INET6_input(int type, char *bufp, struct sockaddr *sap)
202{
203 switch (type) {
204 case 1:
205 return (INET6_getsock(bufp, sap));
206 default:
207 return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap));
208 }
209}
210
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000211static struct aftype inet6_aftype = {
Rob Landley2818b292006-06-20 15:52:52 +0000212 .name = "inet6",
213 .title = "IPv6",
214 .af = AF_INET6,
215 .alen = sizeof(struct in6_addr),
216 .sprint = INET6_sprint,
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000217 .input = INET6_input,
Rob Landley2818b292006-06-20 15:52:52 +0000218 .fd = -1
Eric Andersen51b8bd62002-07-03 11:46:38 +0000219};
220
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000221#endif /* HAVE_AFINET6 */
Eric Andersen51b8bd62002-07-03 11:46:38 +0000222
Eric Andersenf15d4da2001-03-06 00:48:59 +0000223/* Display an UNSPEC address. */
224static char *UNSPEC_print(unsigned char *ptr)
225{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000226 static char buff[sizeof(struct sockaddr) * 3 + 1];
227 char *pos;
228 unsigned int i;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000229
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000230 pos = buff;
231 for (i = 0; i < sizeof(struct sockaddr); i++) {
232 /* careful -- not every libc's sprintf returns # bytes written */
233 sprintf(pos, "%02X-", (*ptr++ & 0377));
234 pos += 3;
235 }
236 /* Erase trailing "-". Works as long as sizeof(struct sockaddr) != 0 */
237 *--pos = '\0';
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000238 return buff;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000239}
240
241/* Display an UNSPEC socket address. */
242static char *UNSPEC_sprint(struct sockaddr *sap, int numeric)
243{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000244 static char buf[64];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000245
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000246 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
Rob Landley4e3aff32006-05-29 04:37:28 +0000247 return safe_strncpy(buf, "[NONE SET]", sizeof(buf));
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000248 return UNSPEC_print((unsigned char *)sap->sa_data);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000249}
250
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000251static struct aftype unspec_aftype = {
252 "unspec", "UNSPEC", AF_UNSPEC, 0,
253 UNSPEC_print, UNSPEC_sprint, NULL, NULL,
254 NULL,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000255};
256
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000257static struct aftype * const aftypes[] = {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000258 &inet_aftype,
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000259#ifdef HAVE_AFINET6
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000260 &inet6_aftype,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000261#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000262 &unspec_aftype,
263 NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +0000264};
265
Eric Andersenf15d4da2001-03-06 00:48:59 +0000266/* Check our protocol family table for this family. */
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000267struct aftype *get_aftype(const char *name)
268{
269 struct aftype * const *afp;
270
271 afp = aftypes;
272 while (*afp != NULL) {
273 if (!strcmp((*afp)->name, name))
274 return (*afp);
275 afp++;
276 }
277 return NULL;
278}
279
280/* Check our protocol family table for this family. */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000281static struct aftype *get_afntype(int af)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000282{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000283 struct aftype * const *afp;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000284
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000285 afp = aftypes;
286 while (*afp != NULL) {
287 if ((*afp)->af == af)
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000288 return *afp;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000289 afp++;
290 }
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000291 return NULL;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000292}
293
294/* Check our protocol family table for this family and return its socket */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000295static int get_socket_for_af(int af)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000296{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000297 struct aftype * const *afp;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000298
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000299 afp = aftypes;
300 while (*afp != NULL) {
301 if ((*afp)->af == af)
302 return (*afp)->fd;
303 afp++;
304 }
305 return -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000306}
307
Eric Andersenf15d4da2001-03-06 00:48:59 +0000308struct user_net_device_stats {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000309 unsigned long long rx_packets; /* total packets received */
310 unsigned long long tx_packets; /* total packets transmitted */
311 unsigned long long rx_bytes; /* total bytes received */
312 unsigned long long tx_bytes; /* total bytes transmitted */
313 unsigned long rx_errors; /* bad packets received */
314 unsigned long tx_errors; /* packet transmit problems */
315 unsigned long rx_dropped; /* no space in linux buffers */
316 unsigned long tx_dropped; /* no space available in linux */
317 unsigned long rx_multicast; /* multicast packets received */
318 unsigned long rx_compressed;
319 unsigned long tx_compressed;
320 unsigned long collisions;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000321
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000322 /* detailed rx_errors: */
323 unsigned long rx_length_errors;
324 unsigned long rx_over_errors; /* receiver ring buff overflow */
325 unsigned long rx_crc_errors; /* recved pkt with crc error */
326 unsigned long rx_frame_errors; /* recv'd frame alignment error */
327 unsigned long rx_fifo_errors; /* recv'r fifo overrun */
328 unsigned long rx_missed_errors; /* receiver missed packet */
329 /* detailed tx_errors */
330 unsigned long tx_aborted_errors;
331 unsigned long tx_carrier_errors;
332 unsigned long tx_fifo_errors;
333 unsigned long tx_heartbeat_errors;
334 unsigned long tx_window_errors;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000335};
336
337struct interface {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000338 struct interface *next, *prev;
339 char name[IFNAMSIZ]; /* interface name */
340 short type; /* if type */
341 short flags; /* various flags */
342 int metric; /* routing metric */
343 int mtu; /* MTU value */
344 int tx_queue_len; /* transmit queue length */
345 struct ifmap map; /* hardware setup */
346 struct sockaddr addr; /* IP address */
347 struct sockaddr dstaddr; /* P-P IP address */
348 struct sockaddr broadaddr; /* IP broadcast address */
349 struct sockaddr netmask; /* IP network mask */
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000350 int has_ip;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000351 char hwaddr[32]; /* HW address */
352 int statistics_valid;
353 struct user_net_device_stats stats; /* statistics */
354 int keepalive; /* keepalive value for SLIP */
355 int outfill; /* outfill value for SLIP */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000356};
357
358
Denis Vlasenko04b30ba2006-11-21 14:26:37 +0000359int interface_opt_a; /* show all interfaces */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000360
Eric Andersenf15d4da2001-03-06 00:48:59 +0000361static struct interface *int_list, *int_last;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000362static int skfd = -1; /* generic raw socket desc. */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000363
364
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000365static int sockets_open(int family)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000366{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000367 struct aftype * const *aft;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000368 int sfd = -1;
369 static int force = -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000370
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000371 if (force < 0) {
372 force = 0;
Bernhard Reutner-Fischere2e56c72006-05-19 11:54:02 +0000373 if (get_linux_version_code() < KERNEL_VERSION(2,1,0))
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000374 force = 1;
375 if (access("/proc/net", R_OK))
376 force = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000377 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000378 for (aft = aftypes; *aft; aft++) {
379 struct aftype *af = *aft;
380 int type = SOCK_DGRAM;
381
382 if (af->af == AF_UNSPEC)
383 continue;
384 if (family && family != af->af)
385 continue;
386 if (af->fd != -1) {
387 sfd = af->fd;
388 continue;
389 }
390 /* Check some /proc file first to not stress kmod */
391 if (!family && !force && af->flag_file) {
392 if (access(af->flag_file, R_OK))
393 continue;
394 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000395 af->fd = socket(af->af, type, 0);
396 if (af->fd >= 0)
397 sfd = af->fd;
398 }
Glenn L McGrath642f2892002-11-28 10:20:45 +0000399 if (sfd < 0) {
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000400 bb_error_msg("no usable address families found");
Glenn L McGrath642f2892002-11-28 10:20:45 +0000401 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000402 return sfd;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000403}
404
Rob Landley93983042005-05-03 21:30:26 +0000405#ifdef CONFIG_FEATURE_CLEAN_UP
406static void sockets_close(void)
407{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000408 struct aftype * const *aft;
Rob Landley93983042005-05-03 21:30:26 +0000409 for (aft = aftypes; *aft != NULL; aft++) {
410 struct aftype *af = *aft;
411 if( af->fd != -1 ) {
412 close(af->fd);
413 af->fd = -1;
414 }
415 }
416}
417#endif
Bernhard Reutner-Fischer57d83ff2006-12-07 12:25:17 +0000418#if 0
Eric Andersenf15d4da2001-03-06 00:48:59 +0000419/* like strcmp(), but knows about numbers */
Bernhard Reutner-Fischer57d83ff2006-12-07 12:25:17 +0000420except that the freshly added calls to xatoul() brf on ethernet aliases with
421uClibc with e.g.: ife->name='lo' name='eth0:1'
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000422static int nstrcmp(const char *a, const char *b)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000423{
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000424 const char *a_ptr = a;
425 const char *b_ptr = b;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000426
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000427 while (*a == *b) {
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000428 if (*a == '\0') {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000429 return 0;
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000430 }
431 if (!isdigit(*a) && isdigit(*(a+1))) {
432 a_ptr = a+1;
433 b_ptr = b+1;
434 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000435 a++;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000436 b++;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000437 }
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000438
439 if (isdigit(*a) && isdigit(*b)) {
Denis Vlasenko13858992006-10-08 12:49:22 +0000440 return xatoul(a_ptr) > xatoul(b_ptr) ? 1 : -1;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000441 }
442 return *a - *b;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000443}
Bernhard Reutner-Fischer57d83ff2006-12-07 12:25:17 +0000444#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +0000445
446static struct interface *add_interface(char *name)
447{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000448 struct interface *ife, **nextp, *new;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000449
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000450 for (ife = int_last; ife; ife = ife->prev) {
Bernhard Reutner-Fischer57d83ff2006-12-07 12:25:17 +0000451 int n = /*n*/strcmp(ife->name, name);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000452
453 if (n == 0)
454 return ife;
455 if (n < 0)
456 break;
457 }
Rob Landleya6e131d2006-05-29 06:43:55 +0000458
459 new = xzalloc(sizeof(*new));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000460 safe_strncpy(new->name, name, IFNAMSIZ);
461 nextp = ife ? &ife->next : &int_list;
462 new->prev = ife;
463 new->next = *nextp;
464 if (new->next)
465 new->next->prev = new;
466 else
467 int_last = new;
468 *nextp = new;
469 return new;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000470}
471
472
473static int if_readconf(void)
474{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000475 int numreqs = 30;
476 struct ifconf ifc;
477 struct ifreq *ifr;
478 int n, err = -1;
479 int skfd2;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000480
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000481 /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
482 (as of 2.1.128) */
483 skfd2 = get_socket_for_af(AF_INET);
484 if (skfd2 < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000485 bb_perror_msg(("warning: no inet socket available"));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000486 /* Try to soldier on with whatever socket we can get hold of. */
487 skfd2 = sockets_open(0);
488 if (skfd2 < 0)
489 return -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000490 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000491
492 ifc.ifc_buf = NULL;
493 for (;;) {
494 ifc.ifc_len = sizeof(struct ifreq) * numreqs;
495 ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);
496
497 if (ioctl(skfd2, SIOCGIFCONF, &ifc) < 0) {
498 perror("SIOCGIFCONF");
499 goto out;
500 }
501 if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
502 /* assume it overflowed and try again */
503 numreqs += 10;
504 continue;
505 }
506 break;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000507 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000508
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000509 ifr = ifc.ifc_req;
510 for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
511 add_interface(ifr->ifr_name);
512 ifr++;
513 }
514 err = 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000515
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000516 out:
517 free(ifc.ifc_buf);
518 return err;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000519}
520
Eric Andersen14f5c8d2005-04-16 19:39:00 +0000521static char *get_name(char *name, char *p)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000522{
Rob Landley9fe801e2006-06-20 21:13:29 +0000523 /* Extract <name> from nul-terminated p where p matches
524 <name>: after leading whitespace.
Eric Andersen9940e082004-08-12 16:52:00 +0000525 If match is not made, set name empty and return unchanged p */
Rob Landley9fe801e2006-06-20 21:13:29 +0000526 int namestart=0, nameend=0;
Eric Andersen9940e082004-08-12 16:52:00 +0000527 while (isspace(p[namestart]))
528 namestart++;
529 nameend=namestart;
530 while (p[nameend] && p[nameend]!=':' && !isspace(p[nameend]))
531 nameend++;
532 if (p[nameend]==':') {
Eric Andersen9940e082004-08-12 16:52:00 +0000533 if ((nameend-namestart)<IFNAMSIZ) {
534 memcpy(name,&p[namestart],nameend-namestart);
535 name[nameend-namestart]='\0';
536 p=&p[nameend];
537 } else {
538 /* Interface name too large */
539 name[0]='\0';
540 }
541 } else {
Rob Landley9fe801e2006-06-20 21:13:29 +0000542 /* trailing ':' not found - return empty */
Eric Andersen9940e082004-08-12 16:52:00 +0000543 name[0]='\0';
Eric Andersenf15d4da2001-03-06 00:48:59 +0000544 }
Eric Andersen6fea7322004-08-26 21:45:21 +0000545 return p + 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000546}
547
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000548/* If scanf supports size qualifiers for %n conversions, then we can
549 * use a modified fmt that simply stores the position in the fields
550 * having no associated fields in the proc string. Of course, we need
551 * to zero them again when we're done. But that is smaller than the
552 * old approach of multiple scanf occurrences with large numbers of
553 * args. */
554
Bernhard Reutner-Fischera901b402006-01-19 14:51:17 +0000555/* static const char * const ss_fmt[] = { */
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000556/* "%lln%llu%lu%lu%lu%lu%ln%ln%lln%llu%lu%lu%lu%lu%lu", */
557/* "%llu%llu%lu%lu%lu%lu%ln%ln%llu%llu%lu%lu%lu%lu%lu", */
558/* "%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 +0000559/* }; */
560
561 /* Lie about the size of the int pointed to for %n. */
562#if INT_MAX == LONG_MAX
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000563static const char * const ss_fmt[] = {
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000564 "%n%llu%u%u%u%u%n%n%n%llu%u%u%u%u%u",
565 "%llu%llu%u%u%u%u%n%n%llu%llu%u%u%u%u%u",
566 "%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 +0000567};
568#else
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000569static const char * const ss_fmt[] = {
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000570 "%n%llu%lu%lu%lu%lu%n%n%n%llu%lu%lu%lu%lu%lu",
571 "%llu%llu%lu%lu%lu%lu%n%n%llu%llu%lu%lu%lu%lu%lu",
572 "%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 +0000573};
574
575#endif
576
577static void get_dev_fields(char *bp, struct interface *ife, int procnetdev_vsn)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000578{
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000579 memset(&ife->stats, 0, sizeof(struct user_net_device_stats));
580
581 sscanf(bp, ss_fmt[procnetdev_vsn],
582 &ife->stats.rx_bytes, /* missing for 0 */
583 &ife->stats.rx_packets,
584 &ife->stats.rx_errors,
585 &ife->stats.rx_dropped,
586 &ife->stats.rx_fifo_errors,
587 &ife->stats.rx_frame_errors,
588 &ife->stats.rx_compressed, /* missing for <= 1 */
589 &ife->stats.rx_multicast, /* missing for <= 1 */
590 &ife->stats.tx_bytes, /* missing for 0 */
591 &ife->stats.tx_packets,
592 &ife->stats.tx_errors,
593 &ife->stats.tx_dropped,
594 &ife->stats.tx_fifo_errors,
595 &ife->stats.collisions,
596 &ife->stats.tx_carrier_errors,
597 &ife->stats.tx_compressed /* missing for <= 1 */
598 );
599
600 if (procnetdev_vsn <= 1) {
601 if (procnetdev_vsn == 0) {
602 ife->stats.rx_bytes = 0;
603 ife->stats.tx_bytes = 0;
604 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000605 ife->stats.rx_multicast = 0;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000606 ife->stats.rx_compressed = 0;
607 ife->stats.tx_compressed = 0;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000608 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000609}
610
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000611static inline int procnetdev_version(char *buf)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000612{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000613 if (strstr(buf, "compressed"))
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000614 return 2;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000615 if (strstr(buf, "bytes"))
616 return 1;
617 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000618}
619
620static int if_readlist_proc(char *target)
621{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000622 static int proc_read;
623 FILE *fh;
624 char buf[512];
625 struct interface *ife;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000626 int err, procnetdev_vsn;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000627
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000628 if (proc_read)
629 return 0;
630 if (!target)
631 proc_read = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000632
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000633 fh = fopen(_PATH_PROCNET_DEV, "r");
634 if (!fh) {
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000635 bb_perror_msg("warning: cannot open %s, limiting output", _PATH_PROCNET_DEV);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000636 return if_readconf();
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000637 }
638 fgets(buf, sizeof buf, fh); /* eat line */
639 fgets(buf, sizeof buf, fh);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000640
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000641 procnetdev_vsn = procnetdev_version(buf);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000642
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000643 err = 0;
644 while (fgets(buf, sizeof buf, fh)) {
Eric Andersenf96675b2003-07-28 06:37:04 +0000645 char *s, name[128];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000646
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000647 s = get_name(name, buf);
648 ife = add_interface(name);
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000649 get_dev_fields(s, ife, procnetdev_vsn);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000650 ife->statistics_valid = 1;
651 if (target && !strcmp(target, name))
652 break;
653 }
654 if (ferror(fh)) {
655 perror(_PATH_PROCNET_DEV);
656 err = -1;
657 proc_read = 0;
658 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000659 fclose(fh);
660 return err;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000661}
662
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000663static int if_readlist(void)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000664{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000665 int err = if_readlist_proc(NULL);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000666
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000667 if (!err)
668 err = if_readconf();
669 return err;
670}
671
672static int for_all_interfaces(int (*doit) (struct interface *, void *),
673 void *cookie)
674{
675 struct interface *ife;
676
677 if (!int_list && (if_readlist() < 0))
678 return -1;
679 for (ife = int_list; ife; ife = ife->next) {
680 int err = doit(ife, cookie);
681
682 if (err)
683 return err;
684 }
685 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000686}
687
Eric Andersenf15d4da2001-03-06 00:48:59 +0000688/* Fetch the interface configuration from the kernel. */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000689static int if_fetch(struct interface *ife)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000690{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000691 struct ifreq ifr;
692 int fd;
693 char *ifname = ife->name;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000694
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000695 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000696 if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000697 return -1;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000698 ife->flags = ifr.ifr_flags;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000699
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000700 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000701 if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
702 memset(ife->hwaddr, 0, 32);
703 else
704 memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000705
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000706 ife->type = ifr.ifr_hwaddr.sa_family;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000707
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000708 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000709 if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0)
710 ife->metric = 0;
711 else
712 ife->metric = ifr.ifr_metric;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000713
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000714 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000715 if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
716 ife->mtu = 0;
717 else
718 ife->mtu = ifr.ifr_mtu;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000719
Rob Landley93983042005-05-03 21:30:26 +0000720#ifdef SIOCGIFMAP
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000721 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Rob Landley93983042005-05-03 21:30:26 +0000722 if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0)
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000723 ife->map = ifr.ifr_map;
Rob Landley93983042005-05-03 21:30:26 +0000724 else
725#endif
726 memset(&ife->map, 0, sizeof(struct ifmap));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000727
728#ifdef HAVE_TXQUEUELEN
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000729 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000730 if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0)
731 ife->tx_queue_len = -1; /* unknown value */
732 else
733 ife->tx_queue_len = ifr.ifr_qlen;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000734#else
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000735 ife->tx_queue_len = -1; /* unknown value */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000736#endif
737
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000738 /* IPv4 address? */
739 fd = get_socket_for_af(AF_INET);
740 if (fd >= 0) {
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000741 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000742 ifr.ifr_addr.sa_family = AF_INET;
743 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
744 ife->has_ip = 1;
745 ife->addr = ifr.ifr_addr;
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000746 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000747 if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0)
748 memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
749 else
750 ife->dstaddr = ifr.ifr_dstaddr;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000751
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000752 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000753 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
754 memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
755 else
756 ife->broadaddr = ifr.ifr_broadaddr;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000757
Denis Vlasenko229b3d22006-11-27 23:44:57 +0000758 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000759 if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
760 memset(&ife->netmask, 0, sizeof(struct sockaddr));
761 else
762 ife->netmask = ifr.ifr_netmask;
763 } else
764 memset(&ife->addr, 0, sizeof(struct sockaddr));
765 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000766
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000767 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000768}
769
770
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000771static int do_if_fetch(struct interface *ife)
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000772{
773 if (if_fetch(ife) < 0) {
774 char *errmsg;
775
776 if (errno == ENODEV) {
777 /* Give better error message for this case. */
Rob Landley4e3aff32006-05-29 04:37:28 +0000778 errmsg = "Device not found";
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000779 } else {
780 errmsg = strerror(errno);
781 }
Rob Landley4e3aff32006-05-29 04:37:28 +0000782 bb_error_msg("%s: error fetching interface information: %s",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000783 ife->name, errmsg);
784 return -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000785 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000786 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000787}
788
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000789static const struct hwtype unspec_hwtype = {
"Robert P. J. Day"4137dd72006-06-26 21:54:57 +0000790 .name = "unspec",
791 .title = "UNSPEC",
792 .type = -1,
793 .print = UNSPEC_print
Eric Andersenf15d4da2001-03-06 00:48:59 +0000794};
795
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000796static const struct hwtype loop_hwtype = {
"Robert P. J. Day"4137dd72006-06-26 21:54:57 +0000797 .name = "loop",
798 .title = "Local Loopback",
799 .type = ARPHRD_LOOPBACK
Eric Andersenf15d4da2001-03-06 00:48:59 +0000800};
801
Eric Andersenf15d4da2001-03-06 00:48:59 +0000802#include <net/if_arp.h>
Eric Andersenab4e19a2003-01-14 08:54:08 +0000803
Denis Vlasenko83e5d6f2006-12-18 21:49:06 +0000804#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined(_NEWLIB_VERSION)
Eric Andersenab4e19a2003-01-14 08:54:08 +0000805#include <net/ethernet.h>
806#else
Eric Andersenf15d4da2001-03-06 00:48:59 +0000807#include <linux/if_ether.h>
Eric Andersenab4e19a2003-01-14 08:54:08 +0000808#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +0000809
Eric Andersenf15d4da2001-03-06 00:48:59 +0000810/* Display an Ethernet address in readable format. */
811static char *pr_ether(unsigned char *ptr)
812{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000813 static char buff[64];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000814
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000815 snprintf(buff, sizeof(buff), "%02X:%02X:%02X:%02X:%02X:%02X",
816 (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377),
817 (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)
818 );
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000819 return buff;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000820}
821
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000822static int in_ether(char *bufp, struct sockaddr *sap);
823
824static struct hwtype ether_hwtype = {
"Robert P. J. Day"4137dd72006-06-26 21:54:57 +0000825 .name = "ether",
826 .title = "Ethernet",
827 .type = ARPHRD_ETHER,
828 .alen = ETH_ALEN,
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000829 .print = pr_ether,
830 .input = in_ether
Eric Andersenf15d4da2001-03-06 00:48:59 +0000831};
832
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000833static unsigned hexchar2int(char c)
834{
835 if (isdigit(c))
836 return c - '0';
837 c &= ~0x20; /* a -> A */
838 if ((unsigned)(c - 'A') <= 5)
839 return c - ('A' - 10);
840 return ~0U;
841}
842
843/* Input an Ethernet address and convert to binary. */
844static int in_ether(char *bufp, struct sockaddr *sap)
845{
846 unsigned char *ptr;
847 char c, *orig;
848 int i;
849 unsigned val;
850
851 sap->sa_family = ether_hwtype.type;
852 ptr = sap->sa_data;
853
854 i = 0;
855 orig = bufp;
856 while ((*bufp != '\0') && (i < ETH_ALEN)) {
857 val = hexchar2int(*bufp++) * 0x10;
858 if (val > 0xff) {
859 errno = EINVAL;
860 return -1;
861 }
862 c = *bufp;
863 if (c == ':' || c == 0)
864 val >>= 4;
865 else {
866 val |= hexchar2int(c);
867 if (val > 0xff) {
868 errno = EINVAL;
869 return -1;
870 }
871 }
872 if (c != 0)
873 bufp++;
874 *ptr++ = (unsigned char) val;
875 i++;
876
877 /* We might get a semicolon here - not required. */
878 if (*bufp == ':') {
879 bufp++;
880 }
881 }
882 return 0;
883}
884
Eric Andersenf15d4da2001-03-06 00:48:59 +0000885#include <net/if_arp.h>
886
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000887static const struct hwtype ppp_hwtype = {
"Robert P. J. Day"4137dd72006-06-26 21:54:57 +0000888 .name = "ppp",
889 .title = "Point-to-Point Protocol",
890 .type = ARPHRD_PPP
Eric Andersenf15d4da2001-03-06 00:48:59 +0000891};
892
"Robert P. J. Day"21302c22006-06-26 22:03:43 +0000893#ifdef CONFIG_FEATURE_IPV6
894static const struct hwtype sit_hwtype = {
895 .name = "sit",
896 .title = "IPv6-in-IPv4",
897 .type = ARPHRD_SIT,
898 .print = UNSPEC_print,
899 .suppress_null_addr = 1
900} ;
901#endif
902
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000903static const struct hwtype * const hwtypes[] = {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000904 &loop_hwtype,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000905 &ether_hwtype,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000906 &ppp_hwtype,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000907 &unspec_hwtype,
"Robert P. J. Day"21302c22006-06-26 22:03:43 +0000908#ifdef CONFIG_FEATURE_IPV6
909 &sit_hwtype,
910#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000911 NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +0000912};
913
Eric Andersenf15d4da2001-03-06 00:48:59 +0000914#ifdef IFF_PORTSEL
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000915static const char * const if_port_text[] = {
916 /* Keep in step with <linux/netdevice.h> */
917 "unknown",
918 "10base2",
919 "10baseT",
920 "AUI",
921 "100baseT",
922 "100baseTX",
923 "100baseFX",
924 NULL
925};
926#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +0000927
928/* Check our hardware type table for this type. */
Denis Vlasenkofa85b862007-01-07 01:24:12 +0000929const struct hwtype *get_hwtype(const char *name)
930{
931 const struct hwtype * const *hwp;
932
933 hwp = hwtypes;
934 while (*hwp != NULL) {
935 if (!strcmp((*hwp)->name, name))
936 return (*hwp);
937 hwp++;
938 }
939 return NULL;
940}
941
942/* Check our hardware type table for this type. */
943const struct hwtype *get_hwntype(int type)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000944{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000945 const struct hwtype * const *hwp;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000946
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000947 hwp = hwtypes;
948 while (*hwp != NULL) {
949 if ((*hwp)->type == type)
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000950 return *hwp;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000951 hwp++;
952 }
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000953 return NULL;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000954}
955
956/* return 1 if address is all zeros */
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000957static int hw_null_address(const struct hwtype *hw, void *ap)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000958{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000959 unsigned int i;
960 unsigned char *address = (unsigned char *) ap;
961
962 for (i = 0; i < hw->alen; i++)
963 if (address[i])
964 return 0;
965 return 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000966}
967
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000968static const char TRext[] = "\0\0\0Ki\0Mi\0Gi\0Ti";
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000969
970static void print_bytes_scaled(unsigned long long ull, const char *end)
971{
972 unsigned long long int_part;
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000973 const char *ext;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000974 unsigned int frac_part;
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000975 int i;
976
977 frac_part = 0;
978 ext = TRext;
979 int_part = ull;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000980 i = 4;
981 do {
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000982 if (int_part >= 1024) {
983 frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
984 int_part /= 1024;
985 ext += 3; /* KiB, MiB, GiB, TiB */
986 }
987 --i;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000988 } while (i);
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000989
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000990 printf("X bytes:%llu (%llu.%u %sB)%s", ull, int_part, frac_part, ext, end);
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000991}
992
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000993static const char * const ife_print_flags_strs[] = {
994 "UP ",
995 "BROADCAST ",
996 "DEBUG ",
997 "LOOPBACK ",
998 "POINTOPOINT ",
999 "NOTRAILERS ",
1000 "RUNNING ",
1001 "NOARP ",
1002 "PROMISC ",
1003 "ALLMULTI ",
1004 "SLAVE ",
1005 "MASTER ",
1006 "MULTICAST ",
1007#ifdef HAVE_DYNAMIC
1008 "DYNAMIC "
1009#endif
1010};
1011
1012static const unsigned short ife_print_flags_mask[] = {
1013 IFF_UP,
1014 IFF_BROADCAST,
1015 IFF_DEBUG,
1016 IFF_LOOPBACK,
1017 IFF_POINTOPOINT,
1018 IFF_NOTRAILERS,
1019 IFF_RUNNING,
1020 IFF_NOARP,
1021 IFF_PROMISC,
1022 IFF_ALLMULTI,
1023 IFF_SLAVE,
1024 IFF_MASTER,
1025 IFF_MULTICAST,
1026#ifdef HAVE_DYNAMIC
1027 IFF_DYNAMIC
1028#endif
1029 0
1030};
1031
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001032static void ife_print(struct interface *ptr)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001033{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001034 struct aftype *ap;
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +00001035 const struct hwtype *hw;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001036 int hf;
1037 int can_compress = 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001038
Denis Vlasenkoaad49992006-11-22 02:12:07 +00001039#ifdef HAVE_AFINET6
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001040 FILE *f;
1041 char addr6[40], devname[20];
1042 struct sockaddr_in6 sap;
1043 int plen, scope, dad_status, if_idx;
1044 char addr6p[8][5];
Eric Andersenf15d4da2001-03-06 00:48:59 +00001045#endif
1046
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001047 ap = get_afntype(ptr->addr.sa_family);
1048 if (ap == NULL)
1049 ap = get_afntype(0);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001050
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001051 hf = ptr->type;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001052
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001053 if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
1054 can_compress = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001055
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001056 hw = get_hwntype(hf);
1057 if (hw == NULL)
1058 hw = get_hwntype(-1);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001059
Rob Landley4e3aff32006-05-29 04:37:28 +00001060 printf("%-9.9s Link encap:%s ", ptr->name, hw->title);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001061 /* For some hardware types (eg Ash, ATM) we don't print the
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001062 hardware address if it's null. */
1063 if (hw->print != NULL && (!(hw_null_address(hw, ptr->hwaddr) &&
1064 hw->suppress_null_addr)))
Rob Landley4e3aff32006-05-29 04:37:28 +00001065 printf("HWaddr %s ", hw->print((unsigned char *)ptr->hwaddr));
Eric Andersenf15d4da2001-03-06 00:48:59 +00001066#ifdef IFF_PORTSEL
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001067 if (ptr->flags & IFF_PORTSEL) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001068 printf("Media:%s", if_port_text[ptr->map.port] /* [0] */);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001069 if (ptr->flags & IFF_AUTOMEDIA)
Rob Landley4e3aff32006-05-29 04:37:28 +00001070 printf("(auto)");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001071 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001072#endif
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00001073 puts("");
Eric Andersenf15d4da2001-03-06 00:48:59 +00001074
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001075 if (ptr->has_ip) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001076 printf(" %s addr:%s ", ap->name,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001077 ap->sprint(&ptr->addr, 1));
1078 if (ptr->flags & IFF_POINTOPOINT) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001079 printf(" P-t-P:%s ", ap->sprint(&ptr->dstaddr, 1));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001080 }
1081 if (ptr->flags & IFF_BROADCAST) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001082 printf(" Bcast:%s ", ap->sprint(&ptr->broadaddr, 1));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001083 }
Rob Landley4e3aff32006-05-29 04:37:28 +00001084 printf(" Mask:%s\n", ap->sprint(&ptr->netmask, 1));
Eric Andersenf15d4da2001-03-06 00:48:59 +00001085 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001086
Denis Vlasenkoaad49992006-11-22 02:12:07 +00001087#ifdef HAVE_AFINET6
Eric Andersenf15d4da2001-03-06 00:48:59 +00001088
Eric Andersen51b8bd62002-07-03 11:46:38 +00001089#define IPV6_ADDR_ANY 0x0000U
1090
1091#define IPV6_ADDR_UNICAST 0x0001U
1092#define IPV6_ADDR_MULTICAST 0x0002U
1093#define IPV6_ADDR_ANYCAST 0x0004U
1094
1095#define IPV6_ADDR_LOOPBACK 0x0010U
1096#define IPV6_ADDR_LINKLOCAL 0x0020U
1097#define IPV6_ADDR_SITELOCAL 0x0040U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001098
Eric Andersen51b8bd62002-07-03 11:46:38 +00001099#define IPV6_ADDR_COMPATv4 0x0080U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001100
Eric Andersen51b8bd62002-07-03 11:46:38 +00001101#define IPV6_ADDR_SCOPE_MASK 0x00f0U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001102
Eric Andersen51b8bd62002-07-03 11:46:38 +00001103#define IPV6_ADDR_MAPPED 0x1000U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001104#define IPV6_ADDR_RESERVED 0x2000U /* reserved address space */
1105
1106 if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
1107 while (fscanf
1108 (f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
1109 addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
1110 addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope,
1111 &dad_status, devname) != EOF) {
1112 if (!strcmp(devname, ptr->name)) {
1113 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
1114 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
1115 addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
1116 inet_pton(AF_INET6, addr6,
1117 (struct sockaddr *) &sap.sin6_addr);
1118 sap.sin6_family = AF_INET6;
Rob Landley4e3aff32006-05-29 04:37:28 +00001119 printf(" inet6 addr: %s/%d",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001120 inet6_aftype.sprint((struct sockaddr *) &sap, 1),
1121 plen);
Rob Landley4e3aff32006-05-29 04:37:28 +00001122 printf(" Scope:");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001123 switch (scope & IPV6_ADDR_SCOPE_MASK) {
1124 case 0:
Rob Landley4e3aff32006-05-29 04:37:28 +00001125 printf("Global");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001126 break;
1127 case IPV6_ADDR_LINKLOCAL:
Rob Landley4e3aff32006-05-29 04:37:28 +00001128 printf("Link");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001129 break;
1130 case IPV6_ADDR_SITELOCAL:
Rob Landley4e3aff32006-05-29 04:37:28 +00001131 printf("Site");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001132 break;
1133 case IPV6_ADDR_COMPATv4:
Rob Landley4e3aff32006-05-29 04:37:28 +00001134 printf("Compat");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001135 break;
1136 case IPV6_ADDR_LOOPBACK:
Rob Landley4e3aff32006-05-29 04:37:28 +00001137 printf("Host");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001138 break;
1139 default:
Rob Landley4e3aff32006-05-29 04:37:28 +00001140 printf("Unknown");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001141 }
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00001142 puts("");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001143 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001144 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001145 fclose(f);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001146 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001147#endif
1148
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001149 printf(" ");
1150 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001151
1152 if (ptr->flags == 0) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001153 printf("[NO FLAGS] ");
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001154 } else {
1155 int i = 0;
1156 do {
1157 if (ptr->flags & ife_print_flags_mask[i]) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001158 printf(ife_print_flags_strs[i]);
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001159 }
1160 } while (ife_print_flags_mask[++i]);
1161 }
1162
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001163 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
Rob Landley4e3aff32006-05-29 04:37:28 +00001164 printf(" MTU:%d Metric:%d", ptr->mtu, ptr->metric ? ptr->metric : 1);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001165#ifdef SIOCSKEEPALIVE
1166 if (ptr->outfill || ptr->keepalive)
Rob Landley4e3aff32006-05-29 04:37:28 +00001167 printf(" Outfill:%d Keepalive:%d", ptr->outfill, ptr->keepalive);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001168#endif
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00001169 puts("");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001170
1171 /* If needed, display the interface statistics. */
1172
1173 if (ptr->statistics_valid) {
1174 /* XXX: statistics are currently only printed for the primary address,
1175 * not for the aliases, although strictly speaking they're shared
1176 * by all addresses.
1177 */
1178 printf(" ");
1179
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001180 printf("RX packets:%llu errors:%lu dropped:%lu overruns:%lu frame:%lu\n",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001181 ptr->stats.rx_packets, ptr->stats.rx_errors,
1182 ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors,
1183 ptr->stats.rx_frame_errors);
1184 if (can_compress)
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001185 printf(" compressed:%lu\n",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001186 ptr->stats.rx_compressed);
1187 printf(" ");
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001188 printf("TX packets:%llu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001189 ptr->stats.tx_packets, ptr->stats.tx_errors,
1190 ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
1191 ptr->stats.tx_carrier_errors);
Bernhard Reutner-Fischer214744d2006-03-30 13:38:19 +00001192 printf(" collisions:%lu ", ptr->stats.collisions);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001193 if (can_compress)
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001194 printf("compressed:%lu ", ptr->stats.tx_compressed);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001195 if (ptr->tx_queue_len != -1)
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001196 printf("txqueuelen:%d ", ptr->tx_queue_len);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001197 printf("\n R");
1198 print_bytes_scaled(ptr->stats.rx_bytes, " T");
1199 print_bytes_scaled(ptr->stats.tx_bytes, "\n");
1200
1201 }
1202
1203 if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
1204 ptr->map.base_addr)) {
1205 printf(" ");
1206 if (ptr->map.irq)
Rob Landley4e3aff32006-05-29 04:37:28 +00001207 printf("Interrupt:%d ", ptr->map.irq);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001208 if (ptr->map.base_addr >= 0x100) /* Only print devices using it for
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001209 I/O maps */
Rob Landley4e3aff32006-05-29 04:37:28 +00001210 printf("Base address:0x%lx ",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001211 (unsigned long) ptr->map.base_addr);
1212 if (ptr->map.mem_start) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001213 printf("Memory:%lx-%lx ", ptr->map.mem_start,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001214 ptr->map.mem_end);
1215 }
1216 if (ptr->map.dma)
Rob Landley4e3aff32006-05-29 04:37:28 +00001217 printf("DMA chan:%x ", ptr->map.dma);
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00001218 puts("");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001219 }
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00001220 puts("");
Eric Andersenf15d4da2001-03-06 00:48:59 +00001221}
1222
1223
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001224static int do_if_print(struct interface *ife, void *cookie)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001225{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001226 int *opt_a = (int *) cookie;
1227 int res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001228
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001229 res = do_if_fetch(ife);
1230 if (res >= 0) {
1231 if ((ife->flags & IFF_UP) || *opt_a)
1232 ife_print(ife);
1233 }
1234 return res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001235}
1236
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001237static struct interface *lookup_interface(char *name)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001238{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001239 struct interface *ife = NULL;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001240
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001241 if (if_readlist_proc(name) < 0)
1242 return NULL;
1243 ife = add_interface(name);
1244 return ife;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001245}
1246
1247/* for ipv4 add/del modes */
1248static int if_print(char *ifname)
1249{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001250 int res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001251
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001252 if (!ifname) {
1253 res = for_all_interfaces(do_if_print, &interface_opt_a);
1254 } else {
1255 struct interface *ife;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001256
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001257 ife = lookup_interface(ifname);
1258 res = do_if_fetch(ife);
1259 if (res >= 0)
1260 ife_print(ife);
1261 }
1262 return res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001263}
1264
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001265int display_interfaces(char *ifname)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001266{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001267 int status;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001268
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001269 /* Create a channel to the NET kernel. */
1270 if ((skfd = sockets_open(0)) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +00001271 bb_perror_msg_and_die("socket");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001272 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001273
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001274 /* Do we have to show the current setup? */
1275 status = if_print(ifname);
Rob Landley93983042005-05-03 21:30:26 +00001276#ifdef CONFIG_FEATURE_CLEAN_UP
1277 sockets_close();
1278#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001279 exit(status < 0);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001280}