blob: 5f54fd9e5e1df54975bc3e831abf0aac7ac03ff7 [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 Andersen6fea7322004-08-26 21:45:21 +000018 * Version: $Id: interface.c,v 1.25 2004/08/26 21:45:21 andersen Exp $
Eric Andersenf15d4da2001-03-06 00:48:59 +000019 *
20 * Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
21 * and others. Copyright 1993 MicroWalt Corporation
22 *
Rob Landleye84f4342006-06-03 21:23:20 +000023 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
Eric Andersenf15d4da2001-03-06 00:48:59 +000024 *
25 * Patched to support 'add' and 'del' keywords for INET(4) addresses
26 * by Mrs. Brisby <mrs.brisby@nimh.org>
27 *
28 * {1.34} - 19980630 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
29 * - gettext instead of catgets for i18n
Eric Andersenc7bda1c2004-03-15 08:29:22 +000030 * 10/1998 - Andi Kleen. Use interface list primitives.
31 * 20001008 - Bernd Eckenfels, Patch from RH for setting mtu
Eric Andersenf15d4da2001-03-06 00:48:59 +000032 * (default AF was wrong)
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +000033 */
34
Eric Andersencd8c4362001-11-10 11:22:46 +000035#include "inet_common.h"
Eric Andersenf15d4da2001-03-06 00:48:59 +000036#include <stdio.h>
37#include <errno.h>
Eric Andersenf15d4da2001-03-06 00:48:59 +000038#include <stdlib.h>
39#include <string.h>
40#include <unistd.h>
Eric Andersencd8c4362001-11-10 11:22:46 +000041#include <fcntl.h>
42#include <ctype.h>
43#include <sys/ioctl.h>
Eric Andersen85e5e722003-07-22 08:56:55 +000044#include <sys/types.h>
Eric Andersencd8c4362001-11-10 11:22:46 +000045#include <net/if.h>
46#include <net/if_arp.h>
Bernhard Reutner-Fischerfa939aa2006-04-05 16:21:37 +000047#include "busybox.h"
Eric Andersenf15d4da2001-03-06 00:48:59 +000048
Glenn L McGrathb54a7482003-08-29 11:34:08 +000049#ifdef CONFIG_FEATURE_IPV6
50# define HAVE_AFINET6 1
51#else
52# undef HAVE_AFINET6
53#endif
54
Eric Andersenf15d4da2001-03-06 00:48:59 +000055#define _PATH_PROCNET_DEV "/proc/net/dev"
Eric Andersen51b8bd62002-07-03 11:46:38 +000056#define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"
Eric Andersenf15d4da2001-03-06 00:48:59 +000057
Denis Vlasenkoaad49992006-11-22 02:12:07 +000058#ifdef HAVE_AFINET6
Eric Andersenf15d4da2001-03-06 00:48:59 +000059
60#ifndef _LINUX_IN6_H
61/*
62 * This is in linux/include/net/ipv6.h.
63 */
64
65struct in6_ifreq {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +000066 struct in6_addr ifr6_addr;
Glenn L McGrathb54a7482003-08-29 11:34:08 +000067 uint32_t ifr6_prefixlen;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +000068 unsigned int ifr6_ifindex;
Eric Andersenf15d4da2001-03-06 00:48:59 +000069};
70
71#endif
72
Denis Vlasenkoaad49992006-11-22 02:12:07 +000073#endif /* HAVE_AFINET6 */
Eric Andersenf15d4da2001-03-06 00:48:59 +000074
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +000075/* Defines for glibc2.0 users. */
76#ifndef SIOCSIFTXQLEN
77#define SIOCSIFTXQLEN 0x8943
78#define SIOCGIFTXQLEN 0x8942
79#endif
80
81/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
82#ifndef ifr_qlen
83#define ifr_qlen ifr_ifru.ifru_mtu
84#endif
85
86#ifndef HAVE_TXQUEUELEN
87#define HAVE_TXQUEUELEN 1
88#endif
89
90#ifndef IFF_DYNAMIC
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +000091#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +000092#endif
93
Eric Andersenf15d4da2001-03-06 00:48:59 +000094/* This structure defines protocol families and their handlers. */
95struct aftype {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +000096 const char *name;
97 const char *title;
98 int af;
99 int alen;
100 char *(*print) (unsigned char *);
101 char *(*sprint) (struct sockaddr *, int numeric);
102 int (*input) (int type, char *bufp, struct sockaddr *);
103 void (*herror) (char *text);
104 int (*rprint) (int options);
105 int (*rinput) (int typ, int ext, char **argv);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000106
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000107 /* may modify src */
108 int (*getmask) (char *src, struct sockaddr * mask, char *name);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000109
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000110 int fd;
111 char *flag_file;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000112};
113
Eric Andersenf15d4da2001-03-06 00:48:59 +0000114/* Display an Internet socket address. */
115static char *INET_sprint(struct sockaddr *sap, int numeric)
116{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000117 static char buff[128];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000118
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000119 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
Rob Landley4e3aff32006-05-29 04:37:28 +0000120 return safe_strncpy(buff, "[NONE SET]", sizeof(buff));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000121
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000122 if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap,
123 numeric, 0xffffff00) != 0)
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000124 return NULL;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000125
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000126 return buff;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000127}
128
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000129static struct aftype inet_aftype = {
Rob Landley2818b292006-06-20 15:52:52 +0000130 .name = "inet",
131 .title = "DARPA Internet",
132 .af = AF_INET,
Rob Landley9fe801e2006-06-20 21:13:29 +0000133 .alen = 4,
Rob Landley2818b292006-06-20 15:52:52 +0000134 .sprint = INET_sprint,
135 .fd = -1
Eric Andersenf15d4da2001-03-06 00:48:59 +0000136};
137
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000138#ifdef HAVE_AFINET6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000139
Eric Andersen51b8bd62002-07-03 11:46:38 +0000140/* Display an Internet socket address. */
141/* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */
142static char *INET6_sprint(struct sockaddr *sap, int numeric)
143{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000144 static char buff[128];
Eric Andersen51b8bd62002-07-03 11:46:38 +0000145
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000146 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
Rob Landley4e3aff32006-05-29 04:37:28 +0000147 return safe_strncpy(buff, "[NONE SET]", sizeof(buff));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000148 if (INET6_rresolve
149 (buff, sizeof(buff), (struct sockaddr_in6 *) sap, numeric) != 0)
Rob Landley4e3aff32006-05-29 04:37:28 +0000150 return safe_strncpy(buff, "[UNKNOWN]", sizeof(buff));
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000151 return buff;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000152}
153
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000154static struct aftype inet6_aftype = {
Rob Landley2818b292006-06-20 15:52:52 +0000155 .name = "inet6",
156 .title = "IPv6",
157 .af = AF_INET6,
158 .alen = sizeof(struct in6_addr),
159 .sprint = INET6_sprint,
160 .fd = -1
Eric Andersen51b8bd62002-07-03 11:46:38 +0000161};
162
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000163#endif /* HAVE_AFINET6 */
Eric Andersen51b8bd62002-07-03 11:46:38 +0000164
Eric Andersenf15d4da2001-03-06 00:48:59 +0000165/* Display an UNSPEC address. */
166static char *UNSPEC_print(unsigned char *ptr)
167{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000168 static char buff[sizeof(struct sockaddr) * 3 + 1];
169 char *pos;
170 unsigned int i;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000171
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000172 pos = buff;
173 for (i = 0; i < sizeof(struct sockaddr); i++) {
174 /* careful -- not every libc's sprintf returns # bytes written */
175 sprintf(pos, "%02X-", (*ptr++ & 0377));
176 pos += 3;
177 }
178 /* Erase trailing "-". Works as long as sizeof(struct sockaddr) != 0 */
179 *--pos = '\0';
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000180 return buff;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000181}
182
183/* Display an UNSPEC socket address. */
184static char *UNSPEC_sprint(struct sockaddr *sap, int numeric)
185{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000186 static char buf[64];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000187
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000188 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
Rob Landley4e3aff32006-05-29 04:37:28 +0000189 return safe_strncpy(buf, "[NONE SET]", sizeof(buf));
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000190 return UNSPEC_print((unsigned char *)sap->sa_data);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000191}
192
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000193static struct aftype unspec_aftype = {
194 "unspec", "UNSPEC", AF_UNSPEC, 0,
195 UNSPEC_print, UNSPEC_sprint, NULL, NULL,
196 NULL,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000197};
198
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000199static struct aftype * const aftypes[] = {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000200 &inet_aftype,
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000201#ifdef HAVE_AFINET6
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000202 &inet6_aftype,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000203#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000204 &unspec_aftype,
205 NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +0000206};
207
Eric Andersenf15d4da2001-03-06 00:48:59 +0000208/* Check our protocol family table for this family. */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000209static struct aftype *get_afntype(int af)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000210{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000211 struct aftype * const *afp;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000212
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000213 afp = aftypes;
214 while (*afp != NULL) {
215 if ((*afp)->af == af)
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000216 return *afp;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000217 afp++;
218 }
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000219 return NULL;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000220}
221
222/* Check our protocol family table for this family and return its socket */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000223static int get_socket_for_af(int af)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000224{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000225 struct aftype * const *afp;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000226
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000227 afp = aftypes;
228 while (*afp != NULL) {
229 if ((*afp)->af == af)
230 return (*afp)->fd;
231 afp++;
232 }
233 return -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000234}
235
Eric Andersenf15d4da2001-03-06 00:48:59 +0000236struct user_net_device_stats {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000237 unsigned long long rx_packets; /* total packets received */
238 unsigned long long tx_packets; /* total packets transmitted */
239 unsigned long long rx_bytes; /* total bytes received */
240 unsigned long long tx_bytes; /* total bytes transmitted */
241 unsigned long rx_errors; /* bad packets received */
242 unsigned long tx_errors; /* packet transmit problems */
243 unsigned long rx_dropped; /* no space in linux buffers */
244 unsigned long tx_dropped; /* no space available in linux */
245 unsigned long rx_multicast; /* multicast packets received */
246 unsigned long rx_compressed;
247 unsigned long tx_compressed;
248 unsigned long collisions;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000249
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000250 /* detailed rx_errors: */
251 unsigned long rx_length_errors;
252 unsigned long rx_over_errors; /* receiver ring buff overflow */
253 unsigned long rx_crc_errors; /* recved pkt with crc error */
254 unsigned long rx_frame_errors; /* recv'd frame alignment error */
255 unsigned long rx_fifo_errors; /* recv'r fifo overrun */
256 unsigned long rx_missed_errors; /* receiver missed packet */
257 /* detailed tx_errors */
258 unsigned long tx_aborted_errors;
259 unsigned long tx_carrier_errors;
260 unsigned long tx_fifo_errors;
261 unsigned long tx_heartbeat_errors;
262 unsigned long tx_window_errors;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000263};
264
265struct interface {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000266 struct interface *next, *prev;
267 char name[IFNAMSIZ]; /* interface name */
268 short type; /* if type */
269 short flags; /* various flags */
270 int metric; /* routing metric */
271 int mtu; /* MTU value */
272 int tx_queue_len; /* transmit queue length */
273 struct ifmap map; /* hardware setup */
274 struct sockaddr addr; /* IP address */
275 struct sockaddr dstaddr; /* P-P IP address */
276 struct sockaddr broadaddr; /* IP broadcast address */
277 struct sockaddr netmask; /* IP network mask */
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000278 int has_ip;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000279 char hwaddr[32]; /* HW address */
280 int statistics_valid;
281 struct user_net_device_stats stats; /* statistics */
282 int keepalive; /* keepalive value for SLIP */
283 int outfill; /* outfill value for SLIP */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000284};
285
286
Denis Vlasenko04b30ba2006-11-21 14:26:37 +0000287int interface_opt_a; /* show all interfaces */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000288
Eric Andersenf15d4da2001-03-06 00:48:59 +0000289static struct interface *int_list, *int_last;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000290static int skfd = -1; /* generic raw socket desc. */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000291
292
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000293static int sockets_open(int family)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000294{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000295 struct aftype * const *aft;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000296 int sfd = -1;
297 static int force = -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000298
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000299 if (force < 0) {
300 force = 0;
Bernhard Reutner-Fischere2e56c72006-05-19 11:54:02 +0000301 if (get_linux_version_code() < KERNEL_VERSION(2,1,0))
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000302 force = 1;
303 if (access("/proc/net", R_OK))
304 force = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000305 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000306 for (aft = aftypes; *aft; aft++) {
307 struct aftype *af = *aft;
308 int type = SOCK_DGRAM;
309
310 if (af->af == AF_UNSPEC)
311 continue;
312 if (family && family != af->af)
313 continue;
314 if (af->fd != -1) {
315 sfd = af->fd;
316 continue;
317 }
318 /* Check some /proc file first to not stress kmod */
319 if (!family && !force && af->flag_file) {
320 if (access(af->flag_file, R_OK))
321 continue;
322 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000323 af->fd = socket(af->af, type, 0);
324 if (af->fd >= 0)
325 sfd = af->fd;
326 }
Glenn L McGrath642f2892002-11-28 10:20:45 +0000327 if (sfd < 0) {
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000328 bb_error_msg("no usable address families found");
Glenn L McGrath642f2892002-11-28 10:20:45 +0000329 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000330 return sfd;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000331}
332
Rob Landley93983042005-05-03 21:30:26 +0000333#ifdef CONFIG_FEATURE_CLEAN_UP
334static void sockets_close(void)
335{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000336 struct aftype * const *aft;
Rob Landley93983042005-05-03 21:30:26 +0000337 for (aft = aftypes; *aft != NULL; aft++) {
338 struct aftype *af = *aft;
339 if( af->fd != -1 ) {
340 close(af->fd);
341 af->fd = -1;
342 }
343 }
344}
345#endif
346
Eric Andersenf15d4da2001-03-06 00:48:59 +0000347/* like strcmp(), but knows about numbers */
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000348static int nstrcmp(const char *a, const char *b)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000349{
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000350 const char *a_ptr = a;
351 const char *b_ptr = b;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000352
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000353 while (*a == *b) {
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000354 if (*a == '\0') {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000355 return 0;
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000356 }
357 if (!isdigit(*a) && isdigit(*(a+1))) {
358 a_ptr = a+1;
359 b_ptr = b+1;
360 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000361 a++;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000362 b++;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000363 }
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000364
365 if (isdigit(*a) && isdigit(*b)) {
Denis Vlasenko13858992006-10-08 12:49:22 +0000366 return xatoul(a_ptr) > xatoul(b_ptr) ? 1 : -1;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000367 }
368 return *a - *b;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000369}
370
371static struct interface *add_interface(char *name)
372{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000373 struct interface *ife, **nextp, *new;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000374
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000375 for (ife = int_last; ife; ife = ife->prev) {
376 int n = nstrcmp(ife->name, name);
377
378 if (n == 0)
379 return ife;
380 if (n < 0)
381 break;
382 }
Rob Landleya6e131d2006-05-29 06:43:55 +0000383
384 new = xzalloc(sizeof(*new));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000385 safe_strncpy(new->name, name, IFNAMSIZ);
386 nextp = ife ? &ife->next : &int_list;
387 new->prev = ife;
388 new->next = *nextp;
389 if (new->next)
390 new->next->prev = new;
391 else
392 int_last = new;
393 *nextp = new;
394 return new;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000395}
396
397
398static int if_readconf(void)
399{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000400 int numreqs = 30;
401 struct ifconf ifc;
402 struct ifreq *ifr;
403 int n, err = -1;
404 int skfd2;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000405
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000406 /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
407 (as of 2.1.128) */
408 skfd2 = get_socket_for_af(AF_INET);
409 if (skfd2 < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000410 bb_perror_msg(("warning: no inet socket available"));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000411 /* Try to soldier on with whatever socket we can get hold of. */
412 skfd2 = sockets_open(0);
413 if (skfd2 < 0)
414 return -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000415 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000416
417 ifc.ifc_buf = NULL;
418 for (;;) {
419 ifc.ifc_len = sizeof(struct ifreq) * numreqs;
420 ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);
421
422 if (ioctl(skfd2, SIOCGIFCONF, &ifc) < 0) {
423 perror("SIOCGIFCONF");
424 goto out;
425 }
426 if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
427 /* assume it overflowed and try again */
428 numreqs += 10;
429 continue;
430 }
431 break;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000432 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000433
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000434 ifr = ifc.ifc_req;
435 for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
436 add_interface(ifr->ifr_name);
437 ifr++;
438 }
439 err = 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000440
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000441 out:
442 free(ifc.ifc_buf);
443 return err;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000444}
445
Eric Andersen14f5c8d2005-04-16 19:39:00 +0000446static char *get_name(char *name, char *p)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000447{
Rob Landley9fe801e2006-06-20 21:13:29 +0000448 /* Extract <name> from nul-terminated p where p matches
449 <name>: after leading whitespace.
Eric Andersen9940e082004-08-12 16:52:00 +0000450 If match is not made, set name empty and return unchanged p */
Rob Landley9fe801e2006-06-20 21:13:29 +0000451 int namestart=0, nameend=0;
Eric Andersen9940e082004-08-12 16:52:00 +0000452 while (isspace(p[namestart]))
453 namestart++;
454 nameend=namestart;
455 while (p[nameend] && p[nameend]!=':' && !isspace(p[nameend]))
456 nameend++;
457 if (p[nameend]==':') {
Eric Andersen9940e082004-08-12 16:52:00 +0000458 if ((nameend-namestart)<IFNAMSIZ) {
459 memcpy(name,&p[namestart],nameend-namestart);
460 name[nameend-namestart]='\0';
461 p=&p[nameend];
462 } else {
463 /* Interface name too large */
464 name[0]='\0';
465 }
466 } else {
Rob Landley9fe801e2006-06-20 21:13:29 +0000467 /* trailing ':' not found - return empty */
Eric Andersen9940e082004-08-12 16:52:00 +0000468 name[0]='\0';
Eric Andersenf15d4da2001-03-06 00:48:59 +0000469 }
Eric Andersen6fea7322004-08-26 21:45:21 +0000470 return p + 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000471}
472
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000473/* If scanf supports size qualifiers for %n conversions, then we can
474 * use a modified fmt that simply stores the position in the fields
475 * having no associated fields in the proc string. Of course, we need
476 * to zero them again when we're done. But that is smaller than the
477 * old approach of multiple scanf occurrences with large numbers of
478 * args. */
479
Bernhard Reutner-Fischera901b402006-01-19 14:51:17 +0000480/* static const char * const ss_fmt[] = { */
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000481/* "%lln%llu%lu%lu%lu%lu%ln%ln%lln%llu%lu%lu%lu%lu%lu", */
482/* "%llu%llu%lu%lu%lu%lu%ln%ln%llu%llu%lu%lu%lu%lu%lu", */
483/* "%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 +0000484/* }; */
485
486 /* Lie about the size of the int pointed to for %n. */
487#if INT_MAX == LONG_MAX
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000488static const char * const ss_fmt[] = {
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000489 "%n%llu%u%u%u%u%n%n%n%llu%u%u%u%u%u",
490 "%llu%llu%u%u%u%u%n%n%llu%llu%u%u%u%u%u",
491 "%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 +0000492};
493#else
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000494static const char * const ss_fmt[] = {
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000495 "%n%llu%lu%lu%lu%lu%n%n%n%llu%lu%lu%lu%lu%lu",
496 "%llu%llu%lu%lu%lu%lu%n%n%llu%llu%lu%lu%lu%lu%lu",
497 "%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 +0000498};
499
500#endif
501
502static void get_dev_fields(char *bp, struct interface *ife, int procnetdev_vsn)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000503{
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000504 memset(&ife->stats, 0, sizeof(struct user_net_device_stats));
505
506 sscanf(bp, ss_fmt[procnetdev_vsn],
507 &ife->stats.rx_bytes, /* missing for 0 */
508 &ife->stats.rx_packets,
509 &ife->stats.rx_errors,
510 &ife->stats.rx_dropped,
511 &ife->stats.rx_fifo_errors,
512 &ife->stats.rx_frame_errors,
513 &ife->stats.rx_compressed, /* missing for <= 1 */
514 &ife->stats.rx_multicast, /* missing for <= 1 */
515 &ife->stats.tx_bytes, /* missing for 0 */
516 &ife->stats.tx_packets,
517 &ife->stats.tx_errors,
518 &ife->stats.tx_dropped,
519 &ife->stats.tx_fifo_errors,
520 &ife->stats.collisions,
521 &ife->stats.tx_carrier_errors,
522 &ife->stats.tx_compressed /* missing for <= 1 */
523 );
524
525 if (procnetdev_vsn <= 1) {
526 if (procnetdev_vsn == 0) {
527 ife->stats.rx_bytes = 0;
528 ife->stats.tx_bytes = 0;
529 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000530 ife->stats.rx_multicast = 0;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000531 ife->stats.rx_compressed = 0;
532 ife->stats.tx_compressed = 0;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000533 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000534}
535
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000536static inline int procnetdev_version(char *buf)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000537{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000538 if (strstr(buf, "compressed"))
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000539 return 2;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000540 if (strstr(buf, "bytes"))
541 return 1;
542 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000543}
544
545static int if_readlist_proc(char *target)
546{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000547 static int proc_read;
548 FILE *fh;
549 char buf[512];
550 struct interface *ife;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000551 int err, procnetdev_vsn;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000552
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000553 if (proc_read)
554 return 0;
555 if (!target)
556 proc_read = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000557
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000558 fh = fopen(_PATH_PROCNET_DEV, "r");
559 if (!fh) {
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000560 bb_perror_msg("warning: cannot open %s, limiting output", _PATH_PROCNET_DEV);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000561 return if_readconf();
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000562 }
563 fgets(buf, sizeof buf, fh); /* eat line */
564 fgets(buf, sizeof buf, fh);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000565
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000566 procnetdev_vsn = procnetdev_version(buf);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000567
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000568 err = 0;
569 while (fgets(buf, sizeof buf, fh)) {
Eric Andersenf96675b2003-07-28 06:37:04 +0000570 char *s, name[128];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000571
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000572 s = get_name(name, buf);
573 ife = add_interface(name);
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000574 get_dev_fields(s, ife, procnetdev_vsn);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000575 ife->statistics_valid = 1;
576 if (target && !strcmp(target, name))
577 break;
578 }
579 if (ferror(fh)) {
580 perror(_PATH_PROCNET_DEV);
581 err = -1;
582 proc_read = 0;
583 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000584 fclose(fh);
585 return err;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000586}
587
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000588static int if_readlist(void)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000589{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000590 int err = if_readlist_proc(NULL);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000591
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000592 if (!err)
593 err = if_readconf();
594 return err;
595}
596
597static int for_all_interfaces(int (*doit) (struct interface *, void *),
598 void *cookie)
599{
600 struct interface *ife;
601
602 if (!int_list && (if_readlist() < 0))
603 return -1;
604 for (ife = int_list; ife; ife = ife->next) {
605 int err = doit(ife, cookie);
606
607 if (err)
608 return err;
609 }
610 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000611}
612
Eric Andersenf15d4da2001-03-06 00:48:59 +0000613/* Fetch the interface configuration from the kernel. */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000614static int if_fetch(struct interface *ife)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000615{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000616 struct ifreq ifr;
617 int fd;
618 char *ifname = ife->name;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000619
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000620 strcpy(ifr.ifr_name, ifname);
621 if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000622 return -1;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000623 ife->flags = ifr.ifr_flags;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000624
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000625 strcpy(ifr.ifr_name, ifname);
626 if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
627 memset(ife->hwaddr, 0, 32);
628 else
629 memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000630
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000631 ife->type = ifr.ifr_hwaddr.sa_family;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000632
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000633 strcpy(ifr.ifr_name, ifname);
634 if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0)
635 ife->metric = 0;
636 else
637 ife->metric = ifr.ifr_metric;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000638
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000639 strcpy(ifr.ifr_name, ifname);
640 if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
641 ife->mtu = 0;
642 else
643 ife->mtu = ifr.ifr_mtu;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000644
Rob Landley93983042005-05-03 21:30:26 +0000645#ifdef SIOCGIFMAP
Eric Andersenf15d4da2001-03-06 00:48:59 +0000646 strcpy(ifr.ifr_name, ifname);
Rob Landley93983042005-05-03 21:30:26 +0000647 if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0)
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000648 ife->map = ifr.ifr_map;
Rob Landley93983042005-05-03 21:30:26 +0000649 else
650#endif
651 memset(&ife->map, 0, sizeof(struct ifmap));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000652
653#ifdef HAVE_TXQUEUELEN
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000654 strcpy(ifr.ifr_name, ifname);
655 if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0)
656 ife->tx_queue_len = -1; /* unknown value */
657 else
658 ife->tx_queue_len = ifr.ifr_qlen;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000659#else
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000660 ife->tx_queue_len = -1; /* unknown value */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000661#endif
662
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000663 /* IPv4 address? */
664 fd = get_socket_for_af(AF_INET);
665 if (fd >= 0) {
666 strcpy(ifr.ifr_name, ifname);
667 ifr.ifr_addr.sa_family = AF_INET;
668 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
669 ife->has_ip = 1;
670 ife->addr = ifr.ifr_addr;
671 strcpy(ifr.ifr_name, ifname);
672 if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0)
673 memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
674 else
675 ife->dstaddr = ifr.ifr_dstaddr;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000676
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000677 strcpy(ifr.ifr_name, ifname);
678 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
679 memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
680 else
681 ife->broadaddr = ifr.ifr_broadaddr;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000682
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000683 strcpy(ifr.ifr_name, ifname);
684 if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
685 memset(&ife->netmask, 0, sizeof(struct sockaddr));
686 else
687 ife->netmask = ifr.ifr_netmask;
688 } else
689 memset(&ife->addr, 0, sizeof(struct sockaddr));
690 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000691
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000692 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000693}
694
695
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000696static int do_if_fetch(struct interface *ife)
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000697{
698 if (if_fetch(ife) < 0) {
699 char *errmsg;
700
701 if (errno == ENODEV) {
702 /* Give better error message for this case. */
Rob Landley4e3aff32006-05-29 04:37:28 +0000703 errmsg = "Device not found";
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000704 } else {
705 errmsg = strerror(errno);
706 }
Rob Landley4e3aff32006-05-29 04:37:28 +0000707 bb_error_msg("%s: error fetching interface information: %s",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000708 ife->name, errmsg);
709 return -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000710 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000711 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000712}
713
714/* This structure defines hardware protocols and their handlers. */
715struct hwtype {
Bernhard Reutner-Fischera901b402006-01-19 14:51:17 +0000716 const char * const name;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000717 const char *title;
718 int type;
719 int alen;
720 char *(*print) (unsigned char *);
721 int (*input) (char *, struct sockaddr *);
722 int (*activate) (int fd);
723 int suppress_null_addr;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000724};
725
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000726static const struct hwtype unspec_hwtype = {
"Robert P. J. Day"4137dd72006-06-26 21:54:57 +0000727 .name = "unspec",
728 .title = "UNSPEC",
729 .type = -1,
730 .print = UNSPEC_print
Eric Andersenf15d4da2001-03-06 00:48:59 +0000731};
732
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000733static const struct hwtype loop_hwtype = {
"Robert P. J. Day"4137dd72006-06-26 21:54:57 +0000734 .name = "loop",
735 .title = "Local Loopback",
736 .type = ARPHRD_LOOPBACK
Eric Andersenf15d4da2001-03-06 00:48:59 +0000737};
738
Eric Andersenf15d4da2001-03-06 00:48:59 +0000739#include <net/if_arp.h>
Eric Andersenab4e19a2003-01-14 08:54:08 +0000740
Denis Vlasenkoa7189f02006-11-17 20:29:00 +0000741#if (__GLIBC__ >=2 && __GLIBC_MINOR__ >= 1) || defined(_NEWLIB_VERSION)
Eric Andersenab4e19a2003-01-14 08:54:08 +0000742#include <net/ethernet.h>
743#else
Eric Andersenf15d4da2001-03-06 00:48:59 +0000744#include <linux/if_ether.h>
Eric Andersenab4e19a2003-01-14 08:54:08 +0000745#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +0000746
Eric Andersenf15d4da2001-03-06 00:48:59 +0000747/* Display an Ethernet address in readable format. */
748static char *pr_ether(unsigned char *ptr)
749{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000750 static char buff[64];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000751
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000752 snprintf(buff, sizeof(buff), "%02X:%02X:%02X:%02X:%02X:%02X",
753 (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377),
754 (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)
755 );
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000756 return buff;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000757}
758
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000759static const struct hwtype ether_hwtype = {
"Robert P. J. Day"4137dd72006-06-26 21:54:57 +0000760 .name = "ether",
761 .title = "Ethernet",
762 .type = ARPHRD_ETHER,
763 .alen = ETH_ALEN,
764 .print = pr_ether
Eric Andersenf15d4da2001-03-06 00:48:59 +0000765};
766
Eric Andersenf15d4da2001-03-06 00:48:59 +0000767#include <net/if_arp.h>
768
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000769static const struct hwtype ppp_hwtype = {
"Robert P. J. Day"4137dd72006-06-26 21:54:57 +0000770 .name = "ppp",
771 .title = "Point-to-Point Protocol",
772 .type = ARPHRD_PPP
Eric Andersenf15d4da2001-03-06 00:48:59 +0000773};
774
"Robert P. J. Day"21302c22006-06-26 22:03:43 +0000775#ifdef CONFIG_FEATURE_IPV6
776static const struct hwtype sit_hwtype = {
777 .name = "sit",
778 .title = "IPv6-in-IPv4",
779 .type = ARPHRD_SIT,
780 .print = UNSPEC_print,
781 .suppress_null_addr = 1
782} ;
783#endif
784
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000785static const struct hwtype * const hwtypes[] = {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000786 &loop_hwtype,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000787 &ether_hwtype,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000788 &ppp_hwtype,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000789 &unspec_hwtype,
"Robert P. J. Day"21302c22006-06-26 22:03:43 +0000790#ifdef CONFIG_FEATURE_IPV6
791 &sit_hwtype,
792#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000793 NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +0000794};
795
Eric Andersenf15d4da2001-03-06 00:48:59 +0000796#ifdef IFF_PORTSEL
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000797static const char * const if_port_text[] = {
798 /* Keep in step with <linux/netdevice.h> */
799 "unknown",
800 "10base2",
801 "10baseT",
802 "AUI",
803 "100baseT",
804 "100baseTX",
805 "100baseFX",
806 NULL
807};
808#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +0000809
810/* Check our hardware type table for this type. */
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000811static const struct hwtype *get_hwntype(int type)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000812{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000813 const struct hwtype * const *hwp;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000814
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000815 hwp = hwtypes;
816 while (*hwp != NULL) {
817 if ((*hwp)->type == type)
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000818 return *hwp;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000819 hwp++;
820 }
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000821 return NULL;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000822}
823
824/* return 1 if address is all zeros */
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000825static int hw_null_address(const struct hwtype *hw, void *ap)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000826{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000827 unsigned int i;
828 unsigned char *address = (unsigned char *) ap;
829
830 for (i = 0; i < hw->alen; i++)
831 if (address[i])
832 return 0;
833 return 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000834}
835
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000836static const char TRext[] = "\0\0\0Ki\0Mi\0Gi\0Ti";
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000837
838static void print_bytes_scaled(unsigned long long ull, const char *end)
839{
840 unsigned long long int_part;
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000841 const char *ext;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000842 unsigned int frac_part;
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000843 int i;
844
845 frac_part = 0;
846 ext = TRext;
847 int_part = ull;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000848 i = 4;
849 do {
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000850 if (int_part >= 1024) {
851 frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
852 int_part /= 1024;
853 ext += 3; /* KiB, MiB, GiB, TiB */
854 }
855 --i;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000856 } while (i);
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000857
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000858 printf("X bytes:%llu (%llu.%u %sB)%s", ull, int_part, frac_part, ext, end);
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000859}
860
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000861static const char * const ife_print_flags_strs[] = {
862 "UP ",
863 "BROADCAST ",
864 "DEBUG ",
865 "LOOPBACK ",
866 "POINTOPOINT ",
867 "NOTRAILERS ",
868 "RUNNING ",
869 "NOARP ",
870 "PROMISC ",
871 "ALLMULTI ",
872 "SLAVE ",
873 "MASTER ",
874 "MULTICAST ",
875#ifdef HAVE_DYNAMIC
876 "DYNAMIC "
877#endif
878};
879
880static const unsigned short ife_print_flags_mask[] = {
881 IFF_UP,
882 IFF_BROADCAST,
883 IFF_DEBUG,
884 IFF_LOOPBACK,
885 IFF_POINTOPOINT,
886 IFF_NOTRAILERS,
887 IFF_RUNNING,
888 IFF_NOARP,
889 IFF_PROMISC,
890 IFF_ALLMULTI,
891 IFF_SLAVE,
892 IFF_MASTER,
893 IFF_MULTICAST,
894#ifdef HAVE_DYNAMIC
895 IFF_DYNAMIC
896#endif
897 0
898};
899
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000900static void ife_print(struct interface *ptr)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000901{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000902 struct aftype *ap;
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000903 const struct hwtype *hw;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000904 int hf;
905 int can_compress = 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000906
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000907#ifdef HAVE_AFINET6
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000908 FILE *f;
909 char addr6[40], devname[20];
910 struct sockaddr_in6 sap;
911 int plen, scope, dad_status, if_idx;
912 char addr6p[8][5];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000913#endif
914
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000915 ap = get_afntype(ptr->addr.sa_family);
916 if (ap == NULL)
917 ap = get_afntype(0);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000918
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000919 hf = ptr->type;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000920
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000921 if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
922 can_compress = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000923
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000924 hw = get_hwntype(hf);
925 if (hw == NULL)
926 hw = get_hwntype(-1);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000927
Rob Landley4e3aff32006-05-29 04:37:28 +0000928 printf("%-9.9s Link encap:%s ", ptr->name, hw->title);
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000929 /* For some hardware types (eg Ash, ATM) we don't print the
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000930 hardware address if it's null. */
931 if (hw->print != NULL && (!(hw_null_address(hw, ptr->hwaddr) &&
932 hw->suppress_null_addr)))
Rob Landley4e3aff32006-05-29 04:37:28 +0000933 printf("HWaddr %s ", hw->print((unsigned char *)ptr->hwaddr));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000934#ifdef IFF_PORTSEL
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000935 if (ptr->flags & IFF_PORTSEL) {
Rob Landley4e3aff32006-05-29 04:37:28 +0000936 printf("Media:%s", if_port_text[ptr->map.port] /* [0] */);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000937 if (ptr->flags & IFF_AUTOMEDIA)
Rob Landley4e3aff32006-05-29 04:37:28 +0000938 printf("(auto)");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000939 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000940#endif
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +0000941 puts("");
Eric Andersenf15d4da2001-03-06 00:48:59 +0000942
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000943 if (ptr->has_ip) {
Rob Landley4e3aff32006-05-29 04:37:28 +0000944 printf(" %s addr:%s ", ap->name,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000945 ap->sprint(&ptr->addr, 1));
946 if (ptr->flags & IFF_POINTOPOINT) {
Rob Landley4e3aff32006-05-29 04:37:28 +0000947 printf(" P-t-P:%s ", ap->sprint(&ptr->dstaddr, 1));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000948 }
949 if (ptr->flags & IFF_BROADCAST) {
Rob Landley4e3aff32006-05-29 04:37:28 +0000950 printf(" Bcast:%s ", ap->sprint(&ptr->broadaddr, 1));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000951 }
Rob Landley4e3aff32006-05-29 04:37:28 +0000952 printf(" Mask:%s\n", ap->sprint(&ptr->netmask, 1));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000953 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000954
Denis Vlasenkoaad49992006-11-22 02:12:07 +0000955#ifdef HAVE_AFINET6
Eric Andersenf15d4da2001-03-06 00:48:59 +0000956
Eric Andersen51b8bd62002-07-03 11:46:38 +0000957#define IPV6_ADDR_ANY 0x0000U
958
959#define IPV6_ADDR_UNICAST 0x0001U
960#define IPV6_ADDR_MULTICAST 0x0002U
961#define IPV6_ADDR_ANYCAST 0x0004U
962
963#define IPV6_ADDR_LOOPBACK 0x0010U
964#define IPV6_ADDR_LINKLOCAL 0x0020U
965#define IPV6_ADDR_SITELOCAL 0x0040U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000966
Eric Andersen51b8bd62002-07-03 11:46:38 +0000967#define IPV6_ADDR_COMPATv4 0x0080U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000968
Eric Andersen51b8bd62002-07-03 11:46:38 +0000969#define IPV6_ADDR_SCOPE_MASK 0x00f0U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000970
Eric Andersen51b8bd62002-07-03 11:46:38 +0000971#define IPV6_ADDR_MAPPED 0x1000U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000972#define IPV6_ADDR_RESERVED 0x2000U /* reserved address space */
973
974 if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
975 while (fscanf
976 (f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
977 addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
978 addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope,
979 &dad_status, devname) != EOF) {
980 if (!strcmp(devname, ptr->name)) {
981 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
982 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
983 addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
984 inet_pton(AF_INET6, addr6,
985 (struct sockaddr *) &sap.sin6_addr);
986 sap.sin6_family = AF_INET6;
Rob Landley4e3aff32006-05-29 04:37:28 +0000987 printf(" inet6 addr: %s/%d",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000988 inet6_aftype.sprint((struct sockaddr *) &sap, 1),
989 plen);
Rob Landley4e3aff32006-05-29 04:37:28 +0000990 printf(" Scope:");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000991 switch (scope & IPV6_ADDR_SCOPE_MASK) {
992 case 0:
Rob Landley4e3aff32006-05-29 04:37:28 +0000993 printf("Global");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000994 break;
995 case IPV6_ADDR_LINKLOCAL:
Rob Landley4e3aff32006-05-29 04:37:28 +0000996 printf("Link");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000997 break;
998 case IPV6_ADDR_SITELOCAL:
Rob Landley4e3aff32006-05-29 04:37:28 +0000999 printf("Site");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001000 break;
1001 case IPV6_ADDR_COMPATv4:
Rob Landley4e3aff32006-05-29 04:37:28 +00001002 printf("Compat");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001003 break;
1004 case IPV6_ADDR_LOOPBACK:
Rob Landley4e3aff32006-05-29 04:37:28 +00001005 printf("Host");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001006 break;
1007 default:
Rob Landley4e3aff32006-05-29 04:37:28 +00001008 printf("Unknown");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001009 }
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00001010 puts("");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001011 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001012 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001013 fclose(f);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001014 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001015#endif
1016
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001017 printf(" ");
1018 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001019
1020 if (ptr->flags == 0) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001021 printf("[NO FLAGS] ");
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001022 } else {
1023 int i = 0;
1024 do {
1025 if (ptr->flags & ife_print_flags_mask[i]) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001026 printf(ife_print_flags_strs[i]);
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001027 }
1028 } while (ife_print_flags_mask[++i]);
1029 }
1030
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001031 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
Rob Landley4e3aff32006-05-29 04:37:28 +00001032 printf(" MTU:%d Metric:%d", ptr->mtu, ptr->metric ? ptr->metric : 1);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001033#ifdef SIOCSKEEPALIVE
1034 if (ptr->outfill || ptr->keepalive)
Rob Landley4e3aff32006-05-29 04:37:28 +00001035 printf(" Outfill:%d Keepalive:%d", ptr->outfill, ptr->keepalive);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001036#endif
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00001037 puts("");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001038
1039 /* If needed, display the interface statistics. */
1040
1041 if (ptr->statistics_valid) {
1042 /* XXX: statistics are currently only printed for the primary address,
1043 * not for the aliases, although strictly speaking they're shared
1044 * by all addresses.
1045 */
1046 printf(" ");
1047
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001048 printf("RX packets:%llu errors:%lu dropped:%lu overruns:%lu frame:%lu\n",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001049 ptr->stats.rx_packets, ptr->stats.rx_errors,
1050 ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors,
1051 ptr->stats.rx_frame_errors);
1052 if (can_compress)
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001053 printf(" compressed:%lu\n",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001054 ptr->stats.rx_compressed);
1055 printf(" ");
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001056 printf("TX packets:%llu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001057 ptr->stats.tx_packets, ptr->stats.tx_errors,
1058 ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
1059 ptr->stats.tx_carrier_errors);
Bernhard Reutner-Fischer214744d2006-03-30 13:38:19 +00001060 printf(" collisions:%lu ", ptr->stats.collisions);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001061 if (can_compress)
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001062 printf("compressed:%lu ", ptr->stats.tx_compressed);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001063 if (ptr->tx_queue_len != -1)
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001064 printf("txqueuelen:%d ", ptr->tx_queue_len);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001065 printf("\n R");
1066 print_bytes_scaled(ptr->stats.rx_bytes, " T");
1067 print_bytes_scaled(ptr->stats.tx_bytes, "\n");
1068
1069 }
1070
1071 if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
1072 ptr->map.base_addr)) {
1073 printf(" ");
1074 if (ptr->map.irq)
Rob Landley4e3aff32006-05-29 04:37:28 +00001075 printf("Interrupt:%d ", ptr->map.irq);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001076 if (ptr->map.base_addr >= 0x100) /* Only print devices using it for
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001077 I/O maps */
Rob Landley4e3aff32006-05-29 04:37:28 +00001078 printf("Base address:0x%lx ",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001079 (unsigned long) ptr->map.base_addr);
1080 if (ptr->map.mem_start) {
Rob Landley4e3aff32006-05-29 04:37:28 +00001081 printf("Memory:%lx-%lx ", ptr->map.mem_start,
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001082 ptr->map.mem_end);
1083 }
1084 if (ptr->map.dma)
Rob Landley4e3aff32006-05-29 04:37:28 +00001085 printf("DMA chan:%x ", ptr->map.dma);
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00001086 puts("");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001087 }
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00001088 puts("");
Eric Andersenf15d4da2001-03-06 00:48:59 +00001089}
1090
1091
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001092static int do_if_print(struct interface *ife, void *cookie)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001093{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001094 int *opt_a = (int *) cookie;
1095 int res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001096
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001097 res = do_if_fetch(ife);
1098 if (res >= 0) {
1099 if ((ife->flags & IFF_UP) || *opt_a)
1100 ife_print(ife);
1101 }
1102 return res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001103}
1104
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001105static struct interface *lookup_interface(char *name)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001106{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001107 struct interface *ife = NULL;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001108
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001109 if (if_readlist_proc(name) < 0)
1110 return NULL;
1111 ife = add_interface(name);
1112 return ife;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001113}
1114
1115/* for ipv4 add/del modes */
1116static int if_print(char *ifname)
1117{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001118 int res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001119
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001120 if (!ifname) {
1121 res = for_all_interfaces(do_if_print, &interface_opt_a);
1122 } else {
1123 struct interface *ife;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001124
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001125 ife = lookup_interface(ifname);
1126 res = do_if_fetch(ife);
1127 if (res >= 0)
1128 ife_print(ife);
1129 }
1130 return res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001131}
1132
Mike Frysingerb5547fb2006-05-11 02:35:55 +00001133int display_interfaces(char *ifname);
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001134int display_interfaces(char *ifname)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001135{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001136 int status;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001137
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001138 /* Create a channel to the NET kernel. */
1139 if ((skfd = sockets_open(0)) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +00001140 bb_perror_msg_and_die("socket");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001141 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001142
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001143 /* Do we have to show the current setup? */
1144 status = if_print(ifname);
Rob Landley93983042005-05-03 21:30:26 +00001145#ifdef CONFIG_FEATURE_CLEAN_UP
1146 sockets_close();
1147#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001148 exit(status < 0);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001149}