blob: f5937ef3fce6cabe222a5bc61ac6acdd80d02feb [file] [log] [blame]
Eric Andersenf15d4da2001-03-06 00:48:59 +00001/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002 * stolen from net-tools-1.59 and stripped down for busybox by
Eric Andersencb81e642003-07-14 21:21:08 +00003 * Erik Andersen <andersen@codepoet.org>
Eric Andersenbdfd0d72001-10-24 05:00:29 +00004 *
5 * Heavily modified by Manuel Novoa III Mar 12, 2001
6 *
Eric Andersenbdfd0d72001-10-24 05:00:29 +00007 * Added print_bytes_scaled function to reduce code size.
8 * Added some (potentially) missing defines.
9 * Improved display support for -a and for a named interface.
10 *
11 * -----------------------------------------------------------
12 *
Eric Andersenf15d4da2001-03-06 00:48:59 +000013 * ifconfig This file contains an implementation of the command
14 * that either displays or sets the characteristics of
15 * one or more of the system's networking interfaces.
16 *
Eric Andersen6fea7322004-08-26 21:45:21 +000017 * Version: $Id: interface.c,v 1.25 2004/08/26 21:45:21 andersen Exp $
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
Eric Andersenf15d4da2001-03-06 00:48:59 +000057#if HAVE_AFINET6
58
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
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +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/* This structure defines protocol families and their handlers. */
94struct aftype {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +000095 const char *name;
96 const char *title;
97 int af;
98 int alen;
99 char *(*print) (unsigned char *);
100 char *(*sprint) (struct sockaddr *, int numeric);
101 int (*input) (int type, char *bufp, struct sockaddr *);
102 void (*herror) (char *text);
103 int (*rprint) (int options);
104 int (*rinput) (int typ, int ext, char **argv);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000105
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000106 /* may modify src */
107 int (*getmask) (char *src, struct sockaddr * mask, char *name);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000108
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000109 int fd;
110 char *flag_file;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000111};
112
Eric Andersenf15d4da2001-03-06 00:48:59 +0000113/* Display an Internet socket address. */
114static char *INET_sprint(struct sockaddr *sap, int numeric)
115{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000116 static char buff[128];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000117
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000118 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
Rob Landley4e3aff32006-05-29 04:37:28 +0000119 return safe_strncpy(buff, "[NONE SET]", sizeof(buff));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000120
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000121 if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap,
122 numeric, 0xffffff00) != 0)
123 return (NULL);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000124
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000125 return (buff);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000126}
127
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000128static struct aftype inet_aftype = {
Rob Landley2818b292006-06-20 15:52:52 +0000129 .name = "inet",
130 .title = "DARPA Internet",
131 .af = AF_INET,
Rob Landley9fe801e2006-06-20 21:13:29 +0000132 .alen = 4,
Rob Landley2818b292006-06-20 15:52:52 +0000133 .sprint = INET_sprint,
134 .fd = -1
Eric Andersenf15d4da2001-03-06 00:48:59 +0000135};
136
Eric Andersen51b8bd62002-07-03 11:46:38 +0000137#if HAVE_AFINET6
138
Eric Andersen51b8bd62002-07-03 11:46:38 +0000139/* Display an Internet socket address. */
140/* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */
141static char *INET6_sprint(struct sockaddr *sap, int numeric)
142{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000143 static char buff[128];
Eric Andersen51b8bd62002-07-03 11:46:38 +0000144
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000145 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
Rob Landley4e3aff32006-05-29 04:37:28 +0000146 return safe_strncpy(buff, "[NONE SET]", sizeof(buff));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000147 if (INET6_rresolve
148 (buff, sizeof(buff), (struct sockaddr_in6 *) sap, numeric) != 0)
Rob Landley4e3aff32006-05-29 04:37:28 +0000149 return safe_strncpy(buff, "[UNKNOWN]", sizeof(buff));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000150 return (buff);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000151}
152
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000153static struct aftype inet6_aftype = {
Rob Landley2818b292006-06-20 15:52:52 +0000154 .name = "inet6",
155 .title = "IPv6",
156 .af = AF_INET6,
157 .alen = sizeof(struct in6_addr),
158 .sprint = INET6_sprint,
159 .fd = -1
Eric Andersen51b8bd62002-07-03 11:46:38 +0000160};
161
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000162#endif /* HAVE_AFINET6 */
Eric Andersen51b8bd62002-07-03 11:46:38 +0000163
Eric Andersenf15d4da2001-03-06 00:48:59 +0000164/* Display an UNSPEC address. */
165static char *UNSPEC_print(unsigned char *ptr)
166{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000167 static char buff[sizeof(struct sockaddr) * 3 + 1];
168 char *pos;
169 unsigned int i;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000170
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000171 pos = buff;
172 for (i = 0; i < sizeof(struct sockaddr); i++) {
173 /* careful -- not every libc's sprintf returns # bytes written */
174 sprintf(pos, "%02X-", (*ptr++ & 0377));
175 pos += 3;
176 }
177 /* Erase trailing "-". Works as long as sizeof(struct sockaddr) != 0 */
178 *--pos = '\0';
179 return (buff);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000180}
181
182/* Display an UNSPEC socket address. */
183static char *UNSPEC_sprint(struct sockaddr *sap, int numeric)
184{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000185 static char buf[64];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000186
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000187 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
Rob Landley4e3aff32006-05-29 04:37:28 +0000188 return safe_strncpy(buf, "[NONE SET]", sizeof(buf));
Eric Andersen0cb6f352006-01-30 22:30:41 +0000189 return (UNSPEC_print((unsigned char *)sap->sa_data));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000190}
191
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000192static struct aftype unspec_aftype = {
193 "unspec", "UNSPEC", AF_UNSPEC, 0,
194 UNSPEC_print, UNSPEC_sprint, NULL, NULL,
195 NULL,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000196};
197
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000198static struct aftype * const aftypes[] = {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000199 &inet_aftype,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000200#if HAVE_AFINET6
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000201 &inet6_aftype,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000202#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000203 &unspec_aftype,
204 NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +0000205};
206
Eric Andersenf15d4da2001-03-06 00:48:59 +0000207/* Check our protocol family table for this family. */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000208static struct aftype *get_afntype(int af)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000209{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000210 struct aftype * const *afp;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000211
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000212 afp = aftypes;
213 while (*afp != NULL) {
214 if ((*afp)->af == af)
215 return (*afp);
216 afp++;
217 }
218 return (NULL);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000219}
220
221/* Check our protocol family table for this family and return its socket */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000222static int get_socket_for_af(int af)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000223{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000224 struct aftype * const *afp;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000225
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000226 afp = aftypes;
227 while (*afp != NULL) {
228 if ((*afp)->af == af)
229 return (*afp)->fd;
230 afp++;
231 }
232 return -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000233}
234
Eric Andersenf15d4da2001-03-06 00:48:59 +0000235struct user_net_device_stats {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000236 unsigned long long rx_packets; /* total packets received */
237 unsigned long long tx_packets; /* total packets transmitted */
238 unsigned long long rx_bytes; /* total bytes received */
239 unsigned long long tx_bytes; /* total bytes transmitted */
240 unsigned long rx_errors; /* bad packets received */
241 unsigned long tx_errors; /* packet transmit problems */
242 unsigned long rx_dropped; /* no space in linux buffers */
243 unsigned long tx_dropped; /* no space available in linux */
244 unsigned long rx_multicast; /* multicast packets received */
245 unsigned long rx_compressed;
246 unsigned long tx_compressed;
247 unsigned long collisions;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000248
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000249 /* detailed rx_errors: */
250 unsigned long rx_length_errors;
251 unsigned long rx_over_errors; /* receiver ring buff overflow */
252 unsigned long rx_crc_errors; /* recved pkt with crc error */
253 unsigned long rx_frame_errors; /* recv'd frame alignment error */
254 unsigned long rx_fifo_errors; /* recv'r fifo overrun */
255 unsigned long rx_missed_errors; /* receiver missed packet */
256 /* detailed tx_errors */
257 unsigned long tx_aborted_errors;
258 unsigned long tx_carrier_errors;
259 unsigned long tx_fifo_errors;
260 unsigned long tx_heartbeat_errors;
261 unsigned long tx_window_errors;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000262};
263
264struct interface {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000265 struct interface *next, *prev;
266 char name[IFNAMSIZ]; /* interface name */
267 short type; /* if type */
268 short flags; /* various flags */
269 int metric; /* routing metric */
270 int mtu; /* MTU value */
271 int tx_queue_len; /* transmit queue length */
272 struct ifmap map; /* hardware setup */
273 struct sockaddr addr; /* IP address */
274 struct sockaddr dstaddr; /* P-P IP address */
275 struct sockaddr broadaddr; /* IP broadcast address */
276 struct sockaddr netmask; /* IP network mask */
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000277 int has_ip;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000278 char hwaddr[32]; /* HW address */
279 int statistics_valid;
280 struct user_net_device_stats stats; /* statistics */
281 int keepalive; /* keepalive value for SLIP */
282 int outfill; /* outfill value for SLIP */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000283};
284
285
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000286int interface_opt_a = 0; /* show all interfaces */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000287
Eric Andersenf15d4da2001-03-06 00:48:59 +0000288static struct interface *int_list, *int_last;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000289static int skfd = -1; /* generic raw socket desc. */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000290
291
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000292static int sockets_open(int family)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000293{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000294 struct aftype * const *aft;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000295 int sfd = -1;
296 static int force = -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000297
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000298 if (force < 0) {
299 force = 0;
Bernhard Reutner-Fischere2e56c72006-05-19 11:54:02 +0000300 if (get_linux_version_code() < KERNEL_VERSION(2,1,0))
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000301 force = 1;
302 if (access("/proc/net", R_OK))
303 force = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000304 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000305 for (aft = aftypes; *aft; aft++) {
306 struct aftype *af = *aft;
307 int type = SOCK_DGRAM;
308
309 if (af->af == AF_UNSPEC)
310 continue;
311 if (family && family != af->af)
312 continue;
313 if (af->fd != -1) {
314 sfd = af->fd;
315 continue;
316 }
317 /* Check some /proc file first to not stress kmod */
318 if (!family && !force && af->flag_file) {
319 if (access(af->flag_file, R_OK))
320 continue;
321 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000322 af->fd = socket(af->af, type, 0);
323 if (af->fd >= 0)
324 sfd = af->fd;
325 }
Glenn L McGrath642f2892002-11-28 10:20:45 +0000326 if (sfd < 0) {
Rob Landley4e3aff32006-05-29 04:37:28 +0000327 bb_error_msg("No usable address families found.");
Glenn L McGrath642f2892002-11-28 10:20:45 +0000328 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000329 return sfd;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000330}
331
Rob Landley93983042005-05-03 21:30:26 +0000332#ifdef CONFIG_FEATURE_CLEAN_UP
333static void sockets_close(void)
334{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000335 struct aftype * const *aft;
Rob Landley93983042005-05-03 21:30:26 +0000336 for (aft = aftypes; *aft != NULL; aft++) {
337 struct aftype *af = *aft;
338 if( af->fd != -1 ) {
339 close(af->fd);
340 af->fd = -1;
341 }
342 }
343}
344#endif
345
Eric Andersenf15d4da2001-03-06 00:48:59 +0000346/* like strcmp(), but knows about numbers */
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000347static int nstrcmp(const char *a, const char *b)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000348{
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000349 const char *a_ptr = a;
350 const char *b_ptr = b;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000351
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000352 while (*a == *b) {
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000353 if (*a == '\0') {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000354 return 0;
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000355 }
356 if (!isdigit(*a) && isdigit(*(a+1))) {
357 a_ptr = a+1;
358 b_ptr = b+1;
359 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000360 a++;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000361 b++;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000362 }
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000363
364 if (isdigit(*a) && isdigit(*b)) {
365 return atoi(a_ptr) > atoi(b_ptr) ? 1 : -1;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000366 }
367 return *a - *b;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000368}
369
370static struct interface *add_interface(char *name)
371{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000372 struct interface *ife, **nextp, *new;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000373
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000374 for (ife = int_last; ife; ife = ife->prev) {
375 int n = nstrcmp(ife->name, name);
376
377 if (n == 0)
378 return ife;
379 if (n < 0)
380 break;
381 }
Rob Landleya6e131d2006-05-29 06:43:55 +0000382
383 new = xzalloc(sizeof(*new));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000384 safe_strncpy(new->name, name, IFNAMSIZ);
385 nextp = ife ? &ife->next : &int_list;
386 new->prev = ife;
387 new->next = *nextp;
388 if (new->next)
389 new->next->prev = new;
390 else
391 int_last = new;
392 *nextp = new;
393 return new;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000394}
395
396
397static int if_readconf(void)
398{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000399 int numreqs = 30;
400 struct ifconf ifc;
401 struct ifreq *ifr;
402 int n, err = -1;
403 int skfd2;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000404
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000405 /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
406 (as of 2.1.128) */
407 skfd2 = get_socket_for_af(AF_INET);
408 if (skfd2 < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000409 bb_perror_msg(("warning: no inet socket available"));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000410 /* Try to soldier on with whatever socket we can get hold of. */
411 skfd2 = sockets_open(0);
412 if (skfd2 < 0)
413 return -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000414 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000415
416 ifc.ifc_buf = NULL;
417 for (;;) {
418 ifc.ifc_len = sizeof(struct ifreq) * numreqs;
419 ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);
420
421 if (ioctl(skfd2, SIOCGIFCONF, &ifc) < 0) {
422 perror("SIOCGIFCONF");
423 goto out;
424 }
425 if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
426 /* assume it overflowed and try again */
427 numreqs += 10;
428 continue;
429 }
430 break;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000431 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000432
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000433 ifr = ifc.ifc_req;
434 for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
435 add_interface(ifr->ifr_name);
436 ifr++;
437 }
438 err = 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000439
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000440 out:
441 free(ifc.ifc_buf);
442 return err;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000443}
444
Eric Andersen14f5c8d2005-04-16 19:39:00 +0000445static char *get_name(char *name, char *p)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000446{
Rob Landley9fe801e2006-06-20 21:13:29 +0000447 /* Extract <name> from nul-terminated p where p matches
448 <name>: after leading whitespace.
Eric Andersen9940e082004-08-12 16:52:00 +0000449 If match is not made, set name empty and return unchanged p */
Rob Landley9fe801e2006-06-20 21:13:29 +0000450 int namestart=0, nameend=0;
Eric Andersen9940e082004-08-12 16:52:00 +0000451 while (isspace(p[namestart]))
452 namestart++;
453 nameend=namestart;
454 while (p[nameend] && p[nameend]!=':' && !isspace(p[nameend]))
455 nameend++;
456 if (p[nameend]==':') {
Eric Andersen9940e082004-08-12 16:52:00 +0000457 if ((nameend-namestart)<IFNAMSIZ) {
458 memcpy(name,&p[namestart],nameend-namestart);
459 name[nameend-namestart]='\0';
460 p=&p[nameend];
461 } else {
462 /* Interface name too large */
463 name[0]='\0';
464 }
465 } else {
Rob Landley9fe801e2006-06-20 21:13:29 +0000466 /* trailing ':' not found - return empty */
Eric Andersen9940e082004-08-12 16:52:00 +0000467 name[0]='\0';
Eric Andersenf15d4da2001-03-06 00:48:59 +0000468 }
Eric Andersen6fea7322004-08-26 21:45:21 +0000469 return p + 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000470}
471
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000472/* If scanf supports size qualifiers for %n conversions, then we can
473 * use a modified fmt that simply stores the position in the fields
474 * having no associated fields in the proc string. Of course, we need
475 * to zero them again when we're done. But that is smaller than the
476 * old approach of multiple scanf occurrences with large numbers of
477 * args. */
478
Bernhard Reutner-Fischera901b402006-01-19 14:51:17 +0000479/* static const char * const ss_fmt[] = { */
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000480/* "%lln%llu%lu%lu%lu%lu%ln%ln%lln%llu%lu%lu%lu%lu%lu", */
481/* "%llu%llu%lu%lu%lu%lu%ln%ln%llu%llu%lu%lu%lu%lu%lu", */
482/* "%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 +0000483/* }; */
484
485 /* Lie about the size of the int pointed to for %n. */
486#if INT_MAX == LONG_MAX
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000487static const char * const ss_fmt[] = {
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000488 "%n%llu%u%u%u%u%n%n%n%llu%u%u%u%u%u",
489 "%llu%llu%u%u%u%u%n%n%llu%llu%u%u%u%u%u",
490 "%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 +0000491};
492#else
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000493static const char * const ss_fmt[] = {
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000494 "%n%llu%lu%lu%lu%lu%n%n%n%llu%lu%lu%lu%lu%lu",
495 "%llu%llu%lu%lu%lu%lu%n%n%llu%llu%lu%lu%lu%lu%lu",
496 "%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 +0000497};
498
499#endif
500
501static void get_dev_fields(char *bp, struct interface *ife, int procnetdev_vsn)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000502{
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000503 memset(&ife->stats, 0, sizeof(struct user_net_device_stats));
504
505 sscanf(bp, ss_fmt[procnetdev_vsn],
506 &ife->stats.rx_bytes, /* missing for 0 */
507 &ife->stats.rx_packets,
508 &ife->stats.rx_errors,
509 &ife->stats.rx_dropped,
510 &ife->stats.rx_fifo_errors,
511 &ife->stats.rx_frame_errors,
512 &ife->stats.rx_compressed, /* missing for <= 1 */
513 &ife->stats.rx_multicast, /* missing for <= 1 */
514 &ife->stats.tx_bytes, /* missing for 0 */
515 &ife->stats.tx_packets,
516 &ife->stats.tx_errors,
517 &ife->stats.tx_dropped,
518 &ife->stats.tx_fifo_errors,
519 &ife->stats.collisions,
520 &ife->stats.tx_carrier_errors,
521 &ife->stats.tx_compressed /* missing for <= 1 */
522 );
523
524 if (procnetdev_vsn <= 1) {
525 if (procnetdev_vsn == 0) {
526 ife->stats.rx_bytes = 0;
527 ife->stats.tx_bytes = 0;
528 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000529 ife->stats.rx_multicast = 0;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000530 ife->stats.rx_compressed = 0;
531 ife->stats.tx_compressed = 0;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000532 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000533}
534
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000535static inline int procnetdev_version(char *buf)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000536{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000537 if (strstr(buf, "compressed"))
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000538 return 2;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000539 if (strstr(buf, "bytes"))
540 return 1;
541 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000542}
543
544static int if_readlist_proc(char *target)
545{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000546 static int proc_read;
547 FILE *fh;
548 char buf[512];
549 struct interface *ife;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000550 int err, procnetdev_vsn;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000551
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000552 if (proc_read)
553 return 0;
554 if (!target)
555 proc_read = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000556
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000557 fh = fopen(_PATH_PROCNET_DEV, "r");
558 if (!fh) {
Rob Landley4e3aff32006-05-29 04:37:28 +0000559 bb_perror_msg("Warning: cannot open %s. Limited output.", _PATH_PROCNET_DEV);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000560 return if_readconf();
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000561 }
562 fgets(buf, sizeof buf, fh); /* eat line */
563 fgets(buf, sizeof buf, fh);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000564
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000565 procnetdev_vsn = procnetdev_version(buf);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000566
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000567 err = 0;
568 while (fgets(buf, sizeof buf, fh)) {
Eric Andersenf96675b2003-07-28 06:37:04 +0000569 char *s, name[128];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000570
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000571 s = get_name(name, buf);
572 ife = add_interface(name);
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000573 get_dev_fields(s, ife, procnetdev_vsn);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000574 ife->statistics_valid = 1;
575 if (target && !strcmp(target, name))
576 break;
577 }
578 if (ferror(fh)) {
579 perror(_PATH_PROCNET_DEV);
580 err = -1;
581 proc_read = 0;
582 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000583 fclose(fh);
584 return err;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000585}
586
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000587static int if_readlist(void)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000588{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000589 int err = if_readlist_proc(NULL);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000590
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000591 if (!err)
592 err = if_readconf();
593 return err;
594}
595
596static int for_all_interfaces(int (*doit) (struct interface *, void *),
597 void *cookie)
598{
599 struct interface *ife;
600
601 if (!int_list && (if_readlist() < 0))
602 return -1;
603 for (ife = int_list; ife; ife = ife->next) {
604 int err = doit(ife, cookie);
605
606 if (err)
607 return err;
608 }
609 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000610}
611
Eric Andersenf15d4da2001-03-06 00:48:59 +0000612/* Fetch the interface configuration from the kernel. */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000613static int if_fetch(struct interface *ife)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000614{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000615 struct ifreq ifr;
616 int fd;
617 char *ifname = ife->name;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000618
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000619 strcpy(ifr.ifr_name, ifname);
620 if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
621 return (-1);
622 ife->flags = ifr.ifr_flags;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000623
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000624 strcpy(ifr.ifr_name, ifname);
625 if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
626 memset(ife->hwaddr, 0, 32);
627 else
628 memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000629
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000630 ife->type = ifr.ifr_hwaddr.sa_family;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000631
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000632 strcpy(ifr.ifr_name, ifname);
633 if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0)
634 ife->metric = 0;
635 else
636 ife->metric = ifr.ifr_metric;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000637
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000638 strcpy(ifr.ifr_name, ifname);
639 if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
640 ife->mtu = 0;
641 else
642 ife->mtu = ifr.ifr_mtu;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000643
Rob Landley93983042005-05-03 21:30:26 +0000644#ifdef SIOCGIFMAP
Eric Andersenf15d4da2001-03-06 00:48:59 +0000645 strcpy(ifr.ifr_name, ifname);
Rob Landley93983042005-05-03 21:30:26 +0000646 if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0)
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000647 ife->map = ifr.ifr_map;
Rob Landley93983042005-05-03 21:30:26 +0000648 else
649#endif
650 memset(&ife->map, 0, sizeof(struct ifmap));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000651
652#ifdef HAVE_TXQUEUELEN
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000653 strcpy(ifr.ifr_name, ifname);
654 if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0)
655 ife->tx_queue_len = -1; /* unknown value */
656 else
657 ife->tx_queue_len = ifr.ifr_qlen;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000658#else
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000659 ife->tx_queue_len = -1; /* unknown value */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000660#endif
661
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000662 /* IPv4 address? */
663 fd = get_socket_for_af(AF_INET);
664 if (fd >= 0) {
665 strcpy(ifr.ifr_name, ifname);
666 ifr.ifr_addr.sa_family = AF_INET;
667 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
668 ife->has_ip = 1;
669 ife->addr = ifr.ifr_addr;
670 strcpy(ifr.ifr_name, ifname);
671 if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0)
672 memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
673 else
674 ife->dstaddr = ifr.ifr_dstaddr;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000675
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000676 strcpy(ifr.ifr_name, ifname);
677 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
678 memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
679 else
680 ife->broadaddr = ifr.ifr_broadaddr;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000681
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000682 strcpy(ifr.ifr_name, ifname);
683 if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
684 memset(&ife->netmask, 0, sizeof(struct sockaddr));
685 else
686 ife->netmask = ifr.ifr_netmask;
687 } else
688 memset(&ife->addr, 0, sizeof(struct sockaddr));
689 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000690
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000691 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000692}
693
694
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000695static int do_if_fetch(struct interface *ife)
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000696{
697 if (if_fetch(ife) < 0) {
698 char *errmsg;
699
700 if (errno == ENODEV) {
701 /* Give better error message for this case. */
Rob Landley4e3aff32006-05-29 04:37:28 +0000702 errmsg = "Device not found";
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000703 } else {
704 errmsg = strerror(errno);
705 }
Rob Landley4e3aff32006-05-29 04:37:28 +0000706 bb_error_msg("%s: error fetching interface information: %s",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000707 ife->name, errmsg);
708 return -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000709 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000710 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000711}
712
713/* This structure defines hardware protocols and their handlers. */
714struct hwtype {
Bernhard Reutner-Fischera901b402006-01-19 14:51:17 +0000715 const char * const name;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000716 const char *title;
717 int type;
718 int alen;
719 char *(*print) (unsigned char *);
720 int (*input) (char *, struct sockaddr *);
721 int (*activate) (int fd);
722 int suppress_null_addr;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000723};
724
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000725static const struct hwtype unspec_hwtype = {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000726 "unspec", "UNSPEC", -1, 0,
727 UNSPEC_print, NULL, NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +0000728};
729
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000730static const struct hwtype loop_hwtype = {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000731 "loop", "Local Loopback", ARPHRD_LOOPBACK, 0,
732 NULL, NULL, NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +0000733};
734
Eric Andersenf15d4da2001-03-06 00:48:59 +0000735#include <net/if_arp.h>
Eric Andersenab4e19a2003-01-14 08:54:08 +0000736
Mike Frysinger3b05b802005-03-04 01:10:56 +0000737#if (__GLIBC__ >=2 && __GLIBC_MINOR >= 1) || defined(_NEWLIB_VERSION)
Eric Andersenab4e19a2003-01-14 08:54:08 +0000738#include <net/ethernet.h>
739#else
Eric Andersenf15d4da2001-03-06 00:48:59 +0000740#include <linux/if_ether.h>
Eric Andersenab4e19a2003-01-14 08:54:08 +0000741#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +0000742
Eric Andersenf15d4da2001-03-06 00:48:59 +0000743/* Display an Ethernet address in readable format. */
744static char *pr_ether(unsigned char *ptr)
745{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000746 static char buff[64];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000747
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000748 snprintf(buff, sizeof(buff), "%02X:%02X:%02X:%02X:%02X:%02X",
749 (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377),
750 (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)
751 );
752 return (buff);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000753}
754
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000755static const struct hwtype ether_hwtype = {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000756 "ether", "Ethernet", ARPHRD_ETHER, ETH_ALEN,
757 pr_ether, NULL /* UNUSED in_ether */ , NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +0000758};
759
Eric Andersenf15d4da2001-03-06 00:48:59 +0000760#include <net/if_arp.h>
761
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000762static const struct hwtype ppp_hwtype = {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000763 "ppp", "Point-Point Protocol", ARPHRD_PPP, 0,
764 NULL, NULL, NULL /* UNUSED do_ppp */ , 0
Eric Andersenf15d4da2001-03-06 00:48:59 +0000765};
766
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000767static const struct hwtype * const hwtypes[] = {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000768 &loop_hwtype,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000769 &ether_hwtype,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000770 &ppp_hwtype,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000771 &unspec_hwtype,
772 NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +0000773};
774
Eric Andersenf15d4da2001-03-06 00:48:59 +0000775#ifdef IFF_PORTSEL
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000776static const char * const if_port_text[] = {
777 /* Keep in step with <linux/netdevice.h> */
778 "unknown",
779 "10base2",
780 "10baseT",
781 "AUI",
782 "100baseT",
783 "100baseTX",
784 "100baseFX",
785 NULL
786};
787#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +0000788
789/* Check our hardware type table for this type. */
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000790static const struct hwtype *get_hwntype(int type)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000791{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000792 const struct hwtype * const *hwp;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000793
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000794 hwp = hwtypes;
795 while (*hwp != NULL) {
796 if ((*hwp)->type == type)
797 return (*hwp);
798 hwp++;
799 }
800 return (NULL);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000801}
802
803/* return 1 if address is all zeros */
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000804static int hw_null_address(const struct hwtype *hw, void *ap)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000805{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000806 unsigned int i;
807 unsigned char *address = (unsigned char *) ap;
808
809 for (i = 0; i < hw->alen; i++)
810 if (address[i])
811 return 0;
812 return 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000813}
814
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000815static const char TRext[] = "\0\0\0Ki\0Mi\0Gi\0Ti";
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000816
817static void print_bytes_scaled(unsigned long long ull, const char *end)
818{
819 unsigned long long int_part;
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000820 const char *ext;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000821 unsigned int frac_part;
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000822 int i;
823
824 frac_part = 0;
825 ext = TRext;
826 int_part = ull;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000827 i = 4;
828 do {
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000829 if (int_part >= 1024) {
830 frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
831 int_part /= 1024;
832 ext += 3; /* KiB, MiB, GiB, TiB */
833 }
834 --i;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000835 } while (i);
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000836
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000837 printf("X bytes:%llu (%llu.%u %sB)%s", ull, int_part, frac_part, ext, end);
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000838}
839
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000840static const char * const ife_print_flags_strs[] = {
841 "UP ",
842 "BROADCAST ",
843 "DEBUG ",
844 "LOOPBACK ",
845 "POINTOPOINT ",
846 "NOTRAILERS ",
847 "RUNNING ",
848 "NOARP ",
849 "PROMISC ",
850 "ALLMULTI ",
851 "SLAVE ",
852 "MASTER ",
853 "MULTICAST ",
854#ifdef HAVE_DYNAMIC
855 "DYNAMIC "
856#endif
857};
858
859static const unsigned short ife_print_flags_mask[] = {
860 IFF_UP,
861 IFF_BROADCAST,
862 IFF_DEBUG,
863 IFF_LOOPBACK,
864 IFF_POINTOPOINT,
865 IFF_NOTRAILERS,
866 IFF_RUNNING,
867 IFF_NOARP,
868 IFF_PROMISC,
869 IFF_ALLMULTI,
870 IFF_SLAVE,
871 IFF_MASTER,
872 IFF_MULTICAST,
873#ifdef HAVE_DYNAMIC
874 IFF_DYNAMIC
875#endif
876 0
877};
878
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000879static void ife_print(struct interface *ptr)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000880{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000881 struct aftype *ap;
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000882 const struct hwtype *hw;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000883 int hf;
884 int can_compress = 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000885
Eric Andersenf15d4da2001-03-06 00:48:59 +0000886#if HAVE_AFINET6
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000887 FILE *f;
888 char addr6[40], devname[20];
889 struct sockaddr_in6 sap;
890 int plen, scope, dad_status, if_idx;
891 char addr6p[8][5];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000892#endif
893
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000894 ap = get_afntype(ptr->addr.sa_family);
895 if (ap == NULL)
896 ap = get_afntype(0);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000897
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000898 hf = ptr->type;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000899
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000900 if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
901 can_compress = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000902
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000903 hw = get_hwntype(hf);
904 if (hw == NULL)
905 hw = get_hwntype(-1);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000906
Rob Landley4e3aff32006-05-29 04:37:28 +0000907 printf("%-9.9s Link encap:%s ", ptr->name, hw->title);
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000908 /* For some hardware types (eg Ash, ATM) we don't print the
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000909 hardware address if it's null. */
910 if (hw->print != NULL && (!(hw_null_address(hw, ptr->hwaddr) &&
911 hw->suppress_null_addr)))
Rob Landley4e3aff32006-05-29 04:37:28 +0000912 printf("HWaddr %s ", hw->print((unsigned char *)ptr->hwaddr));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000913#ifdef IFF_PORTSEL
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000914 if (ptr->flags & IFF_PORTSEL) {
Rob Landley4e3aff32006-05-29 04:37:28 +0000915 printf("Media:%s", if_port_text[ptr->map.port] /* [0] */);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000916 if (ptr->flags & IFF_AUTOMEDIA)
Rob Landley4e3aff32006-05-29 04:37:28 +0000917 printf("(auto)");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000918 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000919#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000920 printf("\n");
Eric Andersenf15d4da2001-03-06 00:48:59 +0000921
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000922 if (ptr->has_ip) {
Rob Landley4e3aff32006-05-29 04:37:28 +0000923 printf(" %s addr:%s ", ap->name,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000924 ap->sprint(&ptr->addr, 1));
925 if (ptr->flags & IFF_POINTOPOINT) {
Rob Landley4e3aff32006-05-29 04:37:28 +0000926 printf(" P-t-P:%s ", ap->sprint(&ptr->dstaddr, 1));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000927 }
928 if (ptr->flags & IFF_BROADCAST) {
Rob Landley4e3aff32006-05-29 04:37:28 +0000929 printf(" Bcast:%s ", ap->sprint(&ptr->broadaddr, 1));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000930 }
Rob Landley4e3aff32006-05-29 04:37:28 +0000931 printf(" Mask:%s\n", ap->sprint(&ptr->netmask, 1));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000932 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000933
934#if HAVE_AFINET6
Eric Andersenf15d4da2001-03-06 00:48:59 +0000935
Eric Andersen51b8bd62002-07-03 11:46:38 +0000936#define IPV6_ADDR_ANY 0x0000U
937
938#define IPV6_ADDR_UNICAST 0x0001U
939#define IPV6_ADDR_MULTICAST 0x0002U
940#define IPV6_ADDR_ANYCAST 0x0004U
941
942#define IPV6_ADDR_LOOPBACK 0x0010U
943#define IPV6_ADDR_LINKLOCAL 0x0020U
944#define IPV6_ADDR_SITELOCAL 0x0040U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000945
Eric Andersen51b8bd62002-07-03 11:46:38 +0000946#define IPV6_ADDR_COMPATv4 0x0080U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000947
Eric Andersen51b8bd62002-07-03 11:46:38 +0000948#define IPV6_ADDR_SCOPE_MASK 0x00f0U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000949
Eric Andersen51b8bd62002-07-03 11:46:38 +0000950#define IPV6_ADDR_MAPPED 0x1000U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000951#define IPV6_ADDR_RESERVED 0x2000U /* reserved address space */
952
953 if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
954 while (fscanf
955 (f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
956 addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
957 addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope,
958 &dad_status, devname) != EOF) {
959 if (!strcmp(devname, ptr->name)) {
960 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
961 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
962 addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
963 inet_pton(AF_INET6, addr6,
964 (struct sockaddr *) &sap.sin6_addr);
965 sap.sin6_family = AF_INET6;
Rob Landley4e3aff32006-05-29 04:37:28 +0000966 printf(" inet6 addr: %s/%d",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000967 inet6_aftype.sprint((struct sockaddr *) &sap, 1),
968 plen);
Rob Landley4e3aff32006-05-29 04:37:28 +0000969 printf(" Scope:");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000970 switch (scope & IPV6_ADDR_SCOPE_MASK) {
971 case 0:
Rob Landley4e3aff32006-05-29 04:37:28 +0000972 printf("Global");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000973 break;
974 case IPV6_ADDR_LINKLOCAL:
Rob Landley4e3aff32006-05-29 04:37:28 +0000975 printf("Link");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000976 break;
977 case IPV6_ADDR_SITELOCAL:
Rob Landley4e3aff32006-05-29 04:37:28 +0000978 printf("Site");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000979 break;
980 case IPV6_ADDR_COMPATv4:
Rob Landley4e3aff32006-05-29 04:37:28 +0000981 printf("Compat");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000982 break;
983 case IPV6_ADDR_LOOPBACK:
Rob Landley4e3aff32006-05-29 04:37:28 +0000984 printf("Host");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000985 break;
986 default:
Rob Landley4e3aff32006-05-29 04:37:28 +0000987 printf("Unknown");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000988 }
989 printf("\n");
990 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000991 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000992 fclose(f);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000993 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000994#endif
995
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000996 printf(" ");
997 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000998
999 if (ptr->flags == 0) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001000 printf("[NO FLAGS] ");
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001001 } else {
1002 int i = 0;
1003 do {
1004 if (ptr->flags & ife_print_flags_mask[i]) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001005 printf(ife_print_flags_strs[i]);
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001006 }
1007 } while (ife_print_flags_mask[++i]);
1008 }
1009
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001010 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
Rob Landley4e3aff32006-05-29 04:37:28 +00001011 printf(" MTU:%d Metric:%d", ptr->mtu, ptr->metric ? ptr->metric : 1);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001012#ifdef SIOCSKEEPALIVE
1013 if (ptr->outfill || ptr->keepalive)
Rob Landley4e3aff32006-05-29 04:37:28 +00001014 printf(" Outfill:%d Keepalive:%d", ptr->outfill, ptr->keepalive);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001015#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +00001016 printf("\n");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001017
1018 /* If needed, display the interface statistics. */
1019
1020 if (ptr->statistics_valid) {
1021 /* XXX: statistics are currently only printed for the primary address,
1022 * not for the aliases, although strictly speaking they're shared
1023 * by all addresses.
1024 */
1025 printf(" ");
1026
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001027 printf("RX packets:%llu errors:%lu dropped:%lu overruns:%lu frame:%lu\n",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001028 ptr->stats.rx_packets, ptr->stats.rx_errors,
1029 ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors,
1030 ptr->stats.rx_frame_errors);
1031 if (can_compress)
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001032 printf(" compressed:%lu\n",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001033 ptr->stats.rx_compressed);
1034 printf(" ");
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001035 printf("TX packets:%llu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001036 ptr->stats.tx_packets, ptr->stats.tx_errors,
1037 ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
1038 ptr->stats.tx_carrier_errors);
Bernhard Reutner-Fischer214744d2006-03-30 13:38:19 +00001039 printf(" collisions:%lu ", ptr->stats.collisions);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001040 if (can_compress)
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001041 printf("compressed:%lu ", ptr->stats.tx_compressed);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001042 if (ptr->tx_queue_len != -1)
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001043 printf("txqueuelen:%d ", ptr->tx_queue_len);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001044 printf("\n R");
1045 print_bytes_scaled(ptr->stats.rx_bytes, " T");
1046 print_bytes_scaled(ptr->stats.tx_bytes, "\n");
1047
1048 }
1049
1050 if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
1051 ptr->map.base_addr)) {
1052 printf(" ");
1053 if (ptr->map.irq)
Rob Landley4e3aff32006-05-29 04:37:28 +00001054 printf("Interrupt:%d ", ptr->map.irq);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001055 if (ptr->map.base_addr >= 0x100) /* Only print devices using it for
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001056 I/O maps */
Rob Landley4e3aff32006-05-29 04:37:28 +00001057 printf("Base address:0x%lx ",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001058 (unsigned long) ptr->map.base_addr);
1059 if (ptr->map.mem_start) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001060 printf("Memory:%lx-%lx ", ptr->map.mem_start,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001061 ptr->map.mem_end);
1062 }
1063 if (ptr->map.dma)
Rob Landley4e3aff32006-05-29 04:37:28 +00001064 printf("DMA chan:%x ", ptr->map.dma);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001065 printf("\n");
1066 }
1067 printf("\n");
Eric Andersenf15d4da2001-03-06 00:48:59 +00001068}
1069
1070
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001071static int do_if_print(struct interface *ife, void *cookie)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001072{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001073 int *opt_a = (int *) cookie;
1074 int res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001075
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001076 res = do_if_fetch(ife);
1077 if (res >= 0) {
1078 if ((ife->flags & IFF_UP) || *opt_a)
1079 ife_print(ife);
1080 }
1081 return res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001082}
1083
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001084static struct interface *lookup_interface(char *name)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001085{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001086 struct interface *ife = NULL;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001087
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001088 if (if_readlist_proc(name) < 0)
1089 return NULL;
1090 ife = add_interface(name);
1091 return ife;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001092}
1093
1094/* for ipv4 add/del modes */
1095static int if_print(char *ifname)
1096{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001097 int res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001098
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001099 if (!ifname) {
1100 res = for_all_interfaces(do_if_print, &interface_opt_a);
1101 } else {
1102 struct interface *ife;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001103
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001104 ife = lookup_interface(ifname);
1105 res = do_if_fetch(ife);
1106 if (res >= 0)
1107 ife_print(ife);
1108 }
1109 return res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001110}
1111
Mike Frysingerb5547fb2006-05-11 02:35:55 +00001112int display_interfaces(char *ifname);
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001113int display_interfaces(char *ifname)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001114{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001115 int status;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001116
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001117 /* Create a channel to the NET kernel. */
1118 if ((skfd = sockets_open(0)) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +00001119 bb_perror_msg_and_die("socket");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001120 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001121
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001122 /* Do we have to show the current setup? */
1123 status = if_print(ifname);
Rob Landley93983042005-05-03 21:30:26 +00001124#ifdef CONFIG_FEATURE_CLEAN_UP
1125 sockets_close();
1126#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001127 exit(status < 0);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001128}