blob: eec696fefc79f36604b61bb9c7b5cddb19694e11 [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 *
7 * Pruned unused code using KEEP_UNUSED define.
8 * 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 *
23 * This program is free software; you can redistribute it
24 * and/or modify it under the terms of the GNU General
25 * Public License as published by the Free Software
26 * Foundation; either version 2 of the License, or (at
27 * your option) any later version.
28 *
29 * Patched to support 'add' and 'del' keywords for INET(4) addresses
30 * by Mrs. Brisby <mrs.brisby@nimh.org>
31 *
32 * {1.34} - 19980630 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
33 * - gettext instead of catgets for i18n
Eric Andersenc7bda1c2004-03-15 08:29:22 +000034 * 10/1998 - Andi Kleen. Use interface list primitives.
35 * 20001008 - Bernd Eckenfels, Patch from RH for setting mtu
Eric Andersenf15d4da2001-03-06 00:48:59 +000036 * (default AF was wrong)
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +000037 */
38
39/* #define KEEP_UNUSED */
40
Eric Andersenc7bda1c2004-03-15 08:29:22 +000041/*
42 *
Eric Andersenf15d4da2001-03-06 00:48:59 +000043 * Protocol Families.
Eric Andersenc7bda1c2004-03-15 08:29:22 +000044 *
Eric Andersenf15d4da2001-03-06 00:48:59 +000045 */
46#define HAVE_AFINET 1
Eric Andersenf15d4da2001-03-06 00:48:59 +000047
Eric Andersenc7bda1c2004-03-15 08:29:22 +000048/*
49 *
Eric Andersenf15d4da2001-03-06 00:48:59 +000050 * Device Hardware types.
Eric Andersenc7bda1c2004-03-15 08:29:22 +000051 *
Eric Andersenf15d4da2001-03-06 00:48:59 +000052 */
53#define HAVE_HWETHER 1
54#define HAVE_HWPPP 1
55#undef HAVE_HWSLIP
56
57
Eric Andersencd8c4362001-11-10 11:22:46 +000058#include "inet_common.h"
Eric Andersenf15d4da2001-03-06 00:48:59 +000059#include <stdio.h>
60#include <errno.h>
Eric Andersenf15d4da2001-03-06 00:48:59 +000061#include <stdlib.h>
62#include <string.h>
63#include <unistd.h>
Eric Andersencd8c4362001-11-10 11:22:46 +000064#include <fcntl.h>
65#include <ctype.h>
66#include <sys/ioctl.h>
Eric Andersen85e5e722003-07-22 08:56:55 +000067#include <sys/types.h>
Eric Andersencd8c4362001-11-10 11:22:46 +000068#include <net/if.h>
69#include <net/if_arp.h>
Bernhard Reutner-Fischerfa939aa2006-04-05 16:21:37 +000070#include "busybox.h"
Eric Andersenf15d4da2001-03-06 00:48:59 +000071
Glenn L McGrathb54a7482003-08-29 11:34:08 +000072#ifdef CONFIG_FEATURE_IPV6
73# define HAVE_AFINET6 1
74#else
75# undef HAVE_AFINET6
76#endif
77
Eric Andersenf15d4da2001-03-06 00:48:59 +000078#define _PATH_PROCNET_DEV "/proc/net/dev"
Eric Andersen51b8bd62002-07-03 11:46:38 +000079#define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"
Eric Andersenf15d4da2001-03-06 00:48:59 +000080#define new(p) ((p) = xcalloc(1,sizeof(*(p))))
Eric Andersen8b113f92001-06-01 21:47:15 +000081#define KRELEASE(maj,min,patch) ((maj) * 65536 + (min)*256 + (patch))
Eric Andersenf15d4da2001-03-06 00:48:59 +000082
Eric Andersenf15d4da2001-03-06 00:48:59 +000083#ifdef HAVE_HWSLIP
Eric Andersenab4e19a2003-01-14 08:54:08 +000084#include <net/if_slip.h>
Eric Andersenf15d4da2001-03-06 00:48:59 +000085#endif
86
87#if HAVE_AFINET6
88
89#ifndef _LINUX_IN6_H
90/*
91 * This is in linux/include/net/ipv6.h.
92 */
93
94struct in6_ifreq {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +000095 struct in6_addr ifr6_addr;
Glenn L McGrathb54a7482003-08-29 11:34:08 +000096 uint32_t ifr6_prefixlen;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +000097 unsigned int ifr6_ifindex;
Eric Andersenf15d4da2001-03-06 00:48:59 +000098};
99
100#endif
101
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000102#endif /* HAVE_AFINET6 */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000103
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000104/* Defines for glibc2.0 users. */
105#ifndef SIOCSIFTXQLEN
106#define SIOCSIFTXQLEN 0x8943
107#define SIOCGIFTXQLEN 0x8942
108#endif
109
110/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
111#ifndef ifr_qlen
112#define ifr_qlen ifr_ifru.ifru_mtu
113#endif
114
115#ifndef HAVE_TXQUEUELEN
116#define HAVE_TXQUEUELEN 1
117#endif
118
119#ifndef IFF_DYNAMIC
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000120#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000121#endif
122
Eric Andersenf15d4da2001-03-06 00:48:59 +0000123/* This structure defines protocol families and their handlers. */
124struct aftype {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000125 const char *name;
126 const char *title;
127 int af;
128 int alen;
129 char *(*print) (unsigned char *);
130 char *(*sprint) (struct sockaddr *, int numeric);
131 int (*input) (int type, char *bufp, struct sockaddr *);
132 void (*herror) (char *text);
133 int (*rprint) (int options);
134 int (*rinput) (int typ, int ext, char **argv);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000135
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000136 /* may modify src */
137 int (*getmask) (char *src, struct sockaddr * mask, char *name);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000138
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000139 int fd;
140 char *flag_file;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000141};
142
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000143#ifdef KEEP_UNUSED
144
145static int flag_unx;
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000146static int flag_inet;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000147
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000148static struct aftrans_t {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000149 char *alias;
150 char *name;
151 int *flag;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000152} aftrans[] = {
153
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000154 {
155 "ip", "inet", &flag_inet},
Eric Andersen8b113f92001-06-01 21:47:15 +0000156#ifdef HAVE_AFINET6
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000157 {
158 "ip6", "inet6", &flag_inet6},
Eric Andersen8b113f92001-06-01 21:47:15 +0000159#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000160 {
161 "inet", "inet", &flag_inet},
Eric Andersen8b113f92001-06-01 21:47:15 +0000162#ifdef HAVE_AFINET6
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000163 {
164 "inet6", "inet6", &flag_inet6},
Eric Andersen8b113f92001-06-01 21:47:15 +0000165#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000166 {
167 "unix", "unix", &flag_unx}, {
168 "tcpip", "inet", &flag_inet},
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000169 {
170 0, 0, 0}
Eric Andersenf15d4da2001-03-06 00:48:59 +0000171};
172
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000173static char afname[256] = "";
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000174#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000175
176#if HAVE_AFUNIX
177
178/* Display a UNIX domain address. */
179static char *UNIX_print(unsigned char *ptr)
180{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000181 return (ptr);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000182}
183
184
185/* Display a UNIX domain address. */
186static char *UNIX_sprint(struct sockaddr *sap, int numeric)
187{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000188 static char buf[64];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000189
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000190 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
191 return safe_strncpy(buf, _("[NONE SET]"), sizeof(buf));
192 return (UNIX_print(sap->sa_data));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000193}
194
195
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000196static struct aftype unix_aftype = {
197 "unix", "UNIX Domain", AF_UNIX, 0,
198 UNIX_print, UNIX_sprint, NULL, NULL,
199 NULL, NULL, NULL,
200 -1,
201 "/proc/net/unix"
Eric Andersenf15d4da2001-03-06 00:48:59 +0000202};
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000203#endif /* HAVE_AFUNIX */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000204
205#if HAVE_AFINET
206
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000207#ifdef KEEP_UNUSED
Eric Andersenf15d4da2001-03-06 00:48:59 +0000208static void INET_reserror(char *text)
209{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000210 herror(text);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000211}
212
Eric Andersenf15d4da2001-03-06 00:48:59 +0000213/* Display an Internet socket address. */
214static char *INET_print(unsigned char *ptr)
215{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000216 return (inet_ntoa((*(struct in_addr *) ptr)));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000217}
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000218#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000219
220/* Display an Internet socket address. */
221static char *INET_sprint(struct sockaddr *sap, int numeric)
222{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000223 static char buff[128];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000224
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000225 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
226 return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000227
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000228 if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap,
229 numeric, 0xffffff00) != 0)
230 return (NULL);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000231
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000232 return (buff);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000233}
234
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000235#ifdef KEEP_UNUSED
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000236static char *INET_sprintmask(struct sockaddr *sap, int numeric,
237 unsigned int netmask)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000238{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000239 static char buff[128];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000240
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000241 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
242 return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff));
243 if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap,
244 numeric, netmask) != 0)
245 return (NULL);
246 return (buff);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000247}
248
Eric Andersenf15d4da2001-03-06 00:48:59 +0000249static int INET_getsock(char *bufp, struct sockaddr *sap)
250{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000251 char *sp = bufp, *bp;
252 unsigned int i;
253 unsigned val;
254 struct sockaddr_in *sin;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000255
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000256 sin = (struct sockaddr_in *) sap;
257 sin->sin_family = AF_INET;
258 sin->sin_port = 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000259
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000260 val = 0;
261 bp = (char *) &val;
262 for (i = 0; i < sizeof(sin->sin_addr.s_addr); i++) {
263 *sp = toupper(*sp);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000264
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000265 if ((*sp >= 'A') && (*sp <= 'F'))
266 bp[i] |= (int) (*sp - 'A') + 10;
267 else if ((*sp >= '0') && (*sp <= '9'))
268 bp[i] |= (int) (*sp - '0');
269 else
270 return (-1);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000271
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000272 bp[i] <<= 4;
273 sp++;
274 *sp = toupper(*sp);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000275
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000276 if ((*sp >= 'A') && (*sp <= 'F'))
277 bp[i] |= (int) (*sp - 'A') + 10;
278 else if ((*sp >= '0') && (*sp <= '9'))
279 bp[i] |= (int) (*sp - '0');
280 else
281 return (-1);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000282
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000283 sp++;
284 }
285 sin->sin_addr.s_addr = htonl(val);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000286
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000287 return (sp - bufp);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000288}
289
290static int INET_input(int type, char *bufp, struct sockaddr *sap)
291{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000292 switch (type) {
293 case 1:
294 return (INET_getsock(bufp, sap));
295 case 256:
296 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 1));
297 default:
298 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0));
299 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000300}
301
302static int INET_getnetmask(char *adr, struct sockaddr *m, char *name)
303{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000304 struct sockaddr_in *mask = (struct sockaddr_in *) m;
305 char *slash, *end;
306 int prefix;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000307
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000308 if ((slash = strchr(adr, '/')) == NULL)
309 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000310
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000311 *slash++ = '\0';
312 prefix = strtoul(slash, &end, 0);
313 if (*end != '\0')
314 return -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000315
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000316 if (name) {
317 sprintf(name, "/%d", prefix);
318 }
319 mask->sin_family = AF_INET;
320 mask->sin_addr.s_addr = htonl(~(0xffffffffU >> prefix));
321 return 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000322}
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000323#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000324
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000325static struct aftype inet_aftype = {
326 "inet", "DARPA Internet", AF_INET, sizeof(unsigned long),
327 NULL /* UNUSED INET_print */ , INET_sprint,
328 NULL /* UNUSED INET_input */ , NULL /* UNUSED INET_reserror */ ,
329 NULL /*INET_rprint */ , NULL /*INET_rinput */ ,
330 NULL /* UNUSED INET_getnetmask */ ,
331 -1,
332 NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +0000333};
334
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000335#endif /* HAVE_AFINET */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000336
Eric Andersen51b8bd62002-07-03 11:46:38 +0000337#if HAVE_AFINET6
338
339#ifdef KEEP_UNUSED
340static void INET6_reserror(char *text)
341{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000342 herror(text);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000343}
344
345/* Display an Internet socket address. */
346static char *INET6_print(unsigned char *ptr)
347{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000348 static char name[80];
Eric Andersen51b8bd62002-07-03 11:46:38 +0000349
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000350 inet_ntop(AF_INET6, (struct in6_addr *) ptr, name, 80);
351 return name;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000352}
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000353#endif /* KEEP_UNUSED */
Eric Andersen51b8bd62002-07-03 11:46:38 +0000354
355/* Display an Internet socket address. */
356/* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */
357static char *INET6_sprint(struct sockaddr *sap, int numeric)
358{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000359 static char buff[128];
Eric Andersen51b8bd62002-07-03 11:46:38 +0000360
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000361 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
362 return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff));
363 if (INET6_rresolve
364 (buff, sizeof(buff), (struct sockaddr_in6 *) sap, numeric) != 0)
365 return safe_strncpy(buff, _("[UNKNOWN]"), sizeof(buff));
366 return (buff);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000367}
368
369#ifdef KEEP_UNUSED
370static int INET6_getsock(char *bufp, struct sockaddr *sap)
371{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000372 struct sockaddr_in6 *sin6;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000373
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000374 sin6 = (struct sockaddr_in6 *) sap;
375 sin6->sin6_family = AF_INET6;
376 sin6->sin6_port = 0;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000377
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000378 if (inet_pton(AF_INET6, bufp, sin6->sin6_addr.s6_addr) <= 0)
379 return (-1);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000380
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000381 return 16; /* ?;) */
Eric Andersen51b8bd62002-07-03 11:46:38 +0000382}
383
384static int INET6_input(int type, char *bufp, struct sockaddr *sap)
385{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000386 switch (type) {
387 case 1:
388 return (INET6_getsock(bufp, sap));
389 default:
390 return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap));
391 }
Eric Andersen51b8bd62002-07-03 11:46:38 +0000392}
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000393#endif /* KEEP_UNUSED */
Eric Andersen51b8bd62002-07-03 11:46:38 +0000394
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000395static struct aftype inet6_aftype = {
396 "inet6", "IPv6", AF_INET6, sizeof(struct in6_addr),
397 NULL /* UNUSED INET6_print */ , INET6_sprint,
398 NULL /* UNUSED INET6_input */ , NULL /* UNUSED INET6_reserror */ ,
399 NULL /*INET6_rprint */ , NULL /*INET6_rinput */ ,
400 NULL /* UNUSED INET6_getnetmask */ ,
401 -1,
402 NULL
Eric Andersen51b8bd62002-07-03 11:46:38 +0000403};
404
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000405#endif /* HAVE_AFINET6 */
Eric Andersen51b8bd62002-07-03 11:46:38 +0000406
Eric Andersenf15d4da2001-03-06 00:48:59 +0000407/* Display an UNSPEC address. */
408static char *UNSPEC_print(unsigned char *ptr)
409{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000410 static char buff[sizeof(struct sockaddr) * 3 + 1];
411 char *pos;
412 unsigned int i;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000413
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000414 pos = buff;
415 for (i = 0; i < sizeof(struct sockaddr); i++) {
416 /* careful -- not every libc's sprintf returns # bytes written */
417 sprintf(pos, "%02X-", (*ptr++ & 0377));
418 pos += 3;
419 }
420 /* Erase trailing "-". Works as long as sizeof(struct sockaddr) != 0 */
421 *--pos = '\0';
422 return (buff);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000423}
424
425/* Display an UNSPEC socket address. */
426static char *UNSPEC_sprint(struct sockaddr *sap, int numeric)
427{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000428 static char buf[64];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000429
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000430 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
431 return safe_strncpy(buf, _("[NONE SET]"), sizeof(buf));
Eric Andersen0cb6f352006-01-30 22:30:41 +0000432 return (UNSPEC_print((unsigned char *)sap->sa_data));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000433}
434
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000435static struct aftype unspec_aftype = {
436 "unspec", "UNSPEC", AF_UNSPEC, 0,
437 UNSPEC_print, UNSPEC_sprint, NULL, NULL,
438 NULL,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000439};
440
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000441static struct aftype * const aftypes[] = {
Eric Andersenf15d4da2001-03-06 00:48:59 +0000442#if HAVE_AFUNIX
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000443 &unix_aftype,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000444#endif
445#if HAVE_AFINET
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000446 &inet_aftype,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000447#endif
448#if HAVE_AFINET6
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000449 &inet6_aftype,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000450#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000451 &unspec_aftype,
452 NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +0000453};
454
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000455#ifdef KEEP_UNUSED
456static short sVafinit = 0;
457
458static void afinit()
Eric Andersenf15d4da2001-03-06 00:48:59 +0000459{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000460 unspec_aftype.title = _("UNSPEC");
Eric Andersenf15d4da2001-03-06 00:48:59 +0000461#if HAVE_AFUNIX
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000462 unix_aftype.title = _("UNIX Domain");
Eric Andersenf15d4da2001-03-06 00:48:59 +0000463#endif
464#if HAVE_AFINET
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000465 inet_aftype.title = _("DARPA Internet");
Eric Andersenf15d4da2001-03-06 00:48:59 +0000466#endif
467#if HAVE_AFINET6
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000468 inet6_aftype.title = _("IPv6");
Eric Andersenf15d4da2001-03-06 00:48:59 +0000469#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000470 sVafinit = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000471}
472
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000473static int aftrans_opt(const char *arg)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000474{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000475 struct aftrans_t *paft;
476 char *tmp1, *tmp2;
477 char buf[256];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000478
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000479 safe_strncpy(buf, arg, sizeof(buf));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000480
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000481 tmp1 = buf;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000482
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000483 while (tmp1) {
Eric Andersenf15d4da2001-03-06 00:48:59 +0000484
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000485 tmp2 = strchr(tmp1, ',');
Eric Andersenf15d4da2001-03-06 00:48:59 +0000486
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000487 if (tmp2)
488 *(tmp2++) = '\0';
Eric Andersenf15d4da2001-03-06 00:48:59 +0000489
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000490 paft = aftrans;
491 for (paft = aftrans; paft->alias; paft++) {
492 if (strcmp(tmp1, paft->alias))
493 continue;
494 if (strlen(paft->name) + strlen(afname) + 1 >= sizeof(afname)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000495 bb_error_msg(_("Too many address family arguments."));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000496 return (0);
497 }
498 if (paft->flag)
499 (*paft->flag)++;
500 if (afname[0])
501 strcat(afname, ",");
502 strcat(afname, paft->name);
503 break;
504 }
505 if (!paft->alias) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000506 bb_error_msg(_("Unknown address family `%s'."), tmp1);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000507 return (1);
508 }
509 tmp1 = tmp2;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000510 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000511
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000512 return (0);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000513}
514
515/* set the default AF list from the program name or a constant value */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000516static void aftrans_def(char *tool, char *argv0, char *dflt)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000517{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000518 char *tmp;
519 char *buf;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000520
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000521 strcpy(afname, dflt);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000522
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000523 if (!(tmp = strrchr(argv0, '/')))
524 tmp = argv0; /* no slash?! */
525 else
526 tmp++;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000527
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000528 if (!(buf = strdup(tmp)))
529 return;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000530
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000531 if (strlen(tool) >= strlen(tmp)) {
532 free(buf);
533 return;
534 }
535 tmp = buf + (strlen(tmp) - strlen(tool));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000536
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000537 if (strcmp(tmp, tool) != 0) {
538 free(buf);
539 return;
540 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000541 *tmp = '\0';
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000542 if ((tmp = strchr(buf, '_')))
543 *tmp = '\0';
Eric Andersenf15d4da2001-03-06 00:48:59 +0000544
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000545 afname[0] = '\0';
546 if (aftrans_opt(buf))
547 strcpy(afname, buf);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000548
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000549 free(buf);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000550}
551
Eric Andersenf15d4da2001-03-06 00:48:59 +0000552/* Check our protocol family table for this family. */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000553static struct aftype *get_aftype(const char *name)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000554{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000555 struct aftype * const *afp;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000556
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000557#ifdef KEEP_UNUSED
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000558 if (!sVafinit)
559 afinit();
560#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000561
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000562 afp = aftypes;
563 while (*afp != NULL) {
564 if (!strcmp((*afp)->name, name))
565 return (*afp);
566 afp++;
567 }
568 if (strchr(name, ','))
Manuel Novoa III cad53642003-03-19 09:13:01 +0000569 bb_error_msg(_("Please don't supply more than one address family."));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000570 return (NULL);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000571}
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000572#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000573
574/* Check our protocol family table for this family. */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000575static struct aftype *get_afntype(int af)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000576{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000577 struct aftype * const *afp;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000578
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000579#ifdef KEEP_UNUSED
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000580 if (!sVafinit)
581 afinit();
582#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000583
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000584 afp = aftypes;
585 while (*afp != NULL) {
586 if ((*afp)->af == af)
587 return (*afp);
588 afp++;
589 }
590 return (NULL);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000591}
592
593/* Check our protocol family table for this family and return its socket */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000594static int get_socket_for_af(int af)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000595{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000596 struct aftype * const *afp;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000597
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000598#ifdef KEEP_UNUSED
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000599 if (!sVafinit)
600 afinit();
601#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000602
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000603 afp = aftypes;
604 while (*afp != NULL) {
605 if ((*afp)->af == af)
606 return (*afp)->fd;
607 afp++;
608 }
609 return -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000610}
611
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000612#ifdef KEEP_UNUSED
Eric Andersenf15d4da2001-03-06 00:48:59 +0000613/* type: 0=all, 1=getroute */
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000614static void print_aflist(int type)
615{
616 int count = 0;
617 char *txt;
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000618 struct aftype * const *afp;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000619
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000620#ifdef KEEP_UNUSED
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000621 if (!sVafinit)
622 afinit();
623#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000624
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000625 afp = aftypes;
626 while (*afp != NULL) {
627 if ((type == 1 && ((*afp)->rprint == NULL)) || ((*afp)->af == 0)) {
628 afp++;
629 continue;
630 }
631 if ((count % 3) == 0)
632 fprintf(stderr, count ? "\n " : " ");
633 txt = (*afp)->name;
634 if (!txt)
635 txt = "..";
636 fprintf(stderr, "%s (%s) ", txt, _((*afp)->title));
637 count++;
638 afp++;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000639 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000640 fprintf(stderr, "\n");
Eric Andersenf15d4da2001-03-06 00:48:59 +0000641}
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000642#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000643
644struct user_net_device_stats {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000645 unsigned long long rx_packets; /* total packets received */
646 unsigned long long tx_packets; /* total packets transmitted */
647 unsigned long long rx_bytes; /* total bytes received */
648 unsigned long long tx_bytes; /* total bytes transmitted */
649 unsigned long rx_errors; /* bad packets received */
650 unsigned long tx_errors; /* packet transmit problems */
651 unsigned long rx_dropped; /* no space in linux buffers */
652 unsigned long tx_dropped; /* no space available in linux */
653 unsigned long rx_multicast; /* multicast packets received */
654 unsigned long rx_compressed;
655 unsigned long tx_compressed;
656 unsigned long collisions;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000657
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000658 /* detailed rx_errors: */
659 unsigned long rx_length_errors;
660 unsigned long rx_over_errors; /* receiver ring buff overflow */
661 unsigned long rx_crc_errors; /* recved pkt with crc error */
662 unsigned long rx_frame_errors; /* recv'd frame alignment error */
663 unsigned long rx_fifo_errors; /* recv'r fifo overrun */
664 unsigned long rx_missed_errors; /* receiver missed packet */
665 /* detailed tx_errors */
666 unsigned long tx_aborted_errors;
667 unsigned long tx_carrier_errors;
668 unsigned long tx_fifo_errors;
669 unsigned long tx_heartbeat_errors;
670 unsigned long tx_window_errors;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000671};
672
673struct interface {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000674 struct interface *next, *prev;
675 char name[IFNAMSIZ]; /* interface name */
676 short type; /* if type */
677 short flags; /* various flags */
678 int metric; /* routing metric */
679 int mtu; /* MTU value */
680 int tx_queue_len; /* transmit queue length */
681 struct ifmap map; /* hardware setup */
682 struct sockaddr addr; /* IP address */
683 struct sockaddr dstaddr; /* P-P IP address */
684 struct sockaddr broadaddr; /* IP broadcast address */
685 struct sockaddr netmask; /* IP network mask */
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000686 int has_ip;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000687 char hwaddr[32]; /* HW address */
688 int statistics_valid;
689 struct user_net_device_stats stats; /* statistics */
690 int keepalive; /* keepalive value for SLIP */
691 int outfill; /* outfill value for SLIP */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000692};
693
694
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000695int interface_opt_a = 0; /* show all interfaces */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000696
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000697#ifdef KEEP_UNUSED
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000698static int opt_i = 0; /* show the statistics */
699static int opt_v = 0; /* debugging output flag */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000700
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000701static int addr_family = 0; /* currently selected AF */
702#endif /* KEEP_UNUSED */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000703
Eric Andersenf15d4da2001-03-06 00:48:59 +0000704static struct interface *int_list, *int_last;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000705static int skfd = -1; /* generic raw socket desc. */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000706
707
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000708static int sockets_open(int family)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000709{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000710 struct aftype * const *aft;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000711 int sfd = -1;
712 static int force = -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000713
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000714 if (force < 0) {
715 force = 0;
716 if (get_kernel_revision() < KRELEASE(2, 1, 0))
717 force = 1;
718 if (access("/proc/net", R_OK))
719 force = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000720 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000721 for (aft = aftypes; *aft; aft++) {
722 struct aftype *af = *aft;
723 int type = SOCK_DGRAM;
724
725 if (af->af == AF_UNSPEC)
726 continue;
727 if (family && family != af->af)
728 continue;
729 if (af->fd != -1) {
730 sfd = af->fd;
731 continue;
732 }
733 /* Check some /proc file first to not stress kmod */
734 if (!family && !force && af->flag_file) {
735 if (access(af->flag_file, R_OK))
736 continue;
737 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000738 af->fd = socket(af->af, type, 0);
739 if (af->fd >= 0)
740 sfd = af->fd;
741 }
Glenn L McGrath642f2892002-11-28 10:20:45 +0000742 if (sfd < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000743 bb_error_msg(_("No usable address families found."));
Glenn L McGrath642f2892002-11-28 10:20:45 +0000744 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000745 return sfd;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000746}
747
Rob Landley93983042005-05-03 21:30:26 +0000748#ifdef CONFIG_FEATURE_CLEAN_UP
749static void sockets_close(void)
750{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000751 struct aftype * const *aft;
Rob Landley93983042005-05-03 21:30:26 +0000752 for (aft = aftypes; *aft != NULL; aft++) {
753 struct aftype *af = *aft;
754 if( af->fd != -1 ) {
755 close(af->fd);
756 af->fd = -1;
757 }
758 }
759}
760#endif
761
Eric Andersenf15d4da2001-03-06 00:48:59 +0000762/* like strcmp(), but knows about numbers */
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000763static int nstrcmp(const char *a, const char *b)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000764{
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000765 const char *a_ptr = a;
766 const char *b_ptr = b;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000767
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000768 while (*a == *b) {
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000769 if (*a == '\0') {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000770 return 0;
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000771 }
772 if (!isdigit(*a) && isdigit(*(a+1))) {
773 a_ptr = a+1;
774 b_ptr = b+1;
775 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000776 a++;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000777 b++;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000778 }
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000779
780 if (isdigit(*a) && isdigit(*b)) {
781 return atoi(a_ptr) > atoi(b_ptr) ? 1 : -1;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000782 }
783 return *a - *b;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000784}
785
786static struct interface *add_interface(char *name)
787{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000788 struct interface *ife, **nextp, *new;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000789
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000790 for (ife = int_last; ife; ife = ife->prev) {
791 int n = nstrcmp(ife->name, name);
792
793 if (n == 0)
794 return ife;
795 if (n < 0)
796 break;
797 }
798 new(new);
799 safe_strncpy(new->name, name, IFNAMSIZ);
800 nextp = ife ? &ife->next : &int_list;
801 new->prev = ife;
802 new->next = *nextp;
803 if (new->next)
804 new->next->prev = new;
805 else
806 int_last = new;
807 *nextp = new;
808 return new;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000809}
810
811
812static int if_readconf(void)
813{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000814 int numreqs = 30;
815 struct ifconf ifc;
816 struct ifreq *ifr;
817 int n, err = -1;
818 int skfd2;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000819
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000820 /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
821 (as of 2.1.128) */
822 skfd2 = get_socket_for_af(AF_INET);
823 if (skfd2 < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000824 bb_perror_msg(("warning: no inet socket available"));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000825 /* Try to soldier on with whatever socket we can get hold of. */
826 skfd2 = sockets_open(0);
827 if (skfd2 < 0)
828 return -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000829 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000830
831 ifc.ifc_buf = NULL;
832 for (;;) {
833 ifc.ifc_len = sizeof(struct ifreq) * numreqs;
834 ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);
835
836 if (ioctl(skfd2, SIOCGIFCONF, &ifc) < 0) {
837 perror("SIOCGIFCONF");
838 goto out;
839 }
840 if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
841 /* assume it overflowed and try again */
842 numreqs += 10;
843 continue;
844 }
845 break;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000846 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000847
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000848 ifr = ifc.ifc_req;
849 for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
850 add_interface(ifr->ifr_name);
851 ifr++;
852 }
853 err = 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000854
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000855 out:
856 free(ifc.ifc_buf);
857 return err;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000858}
859
Eric Andersen14f5c8d2005-04-16 19:39:00 +0000860static char *get_name(char *name, char *p)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000861{
Eric Andersen9940e082004-08-12 16:52:00 +0000862 /* Extract <name>[:<alias>] from nul-terminated p where p matches
863 <name>[:<alias>]: after leading whitespace.
864 If match is not made, set name empty and return unchanged p */
865 int namestart=0, nameend=0, aliasend;
866 while (isspace(p[namestart]))
867 namestart++;
868 nameend=namestart;
869 while (p[nameend] && p[nameend]!=':' && !isspace(p[nameend]))
870 nameend++;
871 if (p[nameend]==':') {
872 aliasend=nameend+1;
873 while (p[aliasend] && isdigit(p[aliasend]))
874 aliasend++;
875 if (p[aliasend]==':') {
876 nameend=aliasend;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000877 }
Eric Andersen9940e082004-08-12 16:52:00 +0000878 if ((nameend-namestart)<IFNAMSIZ) {
879 memcpy(name,&p[namestart],nameend-namestart);
880 name[nameend-namestart]='\0';
881 p=&p[nameend];
882 } else {
883 /* Interface name too large */
884 name[0]='\0';
885 }
886 } else {
887 /* first ':' not found - return empty */
888 name[0]='\0';
Eric Andersenf15d4da2001-03-06 00:48:59 +0000889 }
Eric Andersen6fea7322004-08-26 21:45:21 +0000890 return p + 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000891}
892
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000893/* If scanf supports size qualifiers for %n conversions, then we can
894 * use a modified fmt that simply stores the position in the fields
895 * having no associated fields in the proc string. Of course, we need
896 * to zero them again when we're done. But that is smaller than the
897 * old approach of multiple scanf occurrences with large numbers of
898 * args. */
899
Bernhard Reutner-Fischera901b402006-01-19 14:51:17 +0000900/* static const char * const ss_fmt[] = { */
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000901/* "%lln%llu%lu%lu%lu%lu%ln%ln%lln%llu%lu%lu%lu%lu%lu", */
902/* "%llu%llu%lu%lu%lu%lu%ln%ln%llu%llu%lu%lu%lu%lu%lu", */
903/* "%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 +0000904/* }; */
905
906 /* Lie about the size of the int pointed to for %n. */
907#if INT_MAX == LONG_MAX
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000908static const char * const ss_fmt[] = {
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000909 "%n%llu%u%u%u%u%n%n%n%llu%u%u%u%u%u",
910 "%llu%llu%u%u%u%u%n%n%llu%llu%u%u%u%u%u",
911 "%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 +0000912};
913#else
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000914static const char * const ss_fmt[] = {
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000915 "%n%llu%lu%lu%lu%lu%n%n%n%llu%lu%lu%lu%lu%lu",
916 "%llu%llu%lu%lu%lu%lu%n%n%llu%llu%lu%lu%lu%lu%lu",
917 "%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 +0000918};
919
920#endif
921
922static void get_dev_fields(char *bp, struct interface *ife, int procnetdev_vsn)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000923{
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000924 memset(&ife->stats, 0, sizeof(struct user_net_device_stats));
925
926 sscanf(bp, ss_fmt[procnetdev_vsn],
927 &ife->stats.rx_bytes, /* missing for 0 */
928 &ife->stats.rx_packets,
929 &ife->stats.rx_errors,
930 &ife->stats.rx_dropped,
931 &ife->stats.rx_fifo_errors,
932 &ife->stats.rx_frame_errors,
933 &ife->stats.rx_compressed, /* missing for <= 1 */
934 &ife->stats.rx_multicast, /* missing for <= 1 */
935 &ife->stats.tx_bytes, /* missing for 0 */
936 &ife->stats.tx_packets,
937 &ife->stats.tx_errors,
938 &ife->stats.tx_dropped,
939 &ife->stats.tx_fifo_errors,
940 &ife->stats.collisions,
941 &ife->stats.tx_carrier_errors,
942 &ife->stats.tx_compressed /* missing for <= 1 */
943 );
944
945 if (procnetdev_vsn <= 1) {
946 if (procnetdev_vsn == 0) {
947 ife->stats.rx_bytes = 0;
948 ife->stats.tx_bytes = 0;
949 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000950 ife->stats.rx_multicast = 0;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000951 ife->stats.rx_compressed = 0;
952 ife->stats.tx_compressed = 0;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000953 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000954}
955
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000956static inline int procnetdev_version(char *buf)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000957{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000958 if (strstr(buf, "compressed"))
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000959 return 2;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000960 if (strstr(buf, "bytes"))
961 return 1;
962 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000963}
964
965static int if_readlist_proc(char *target)
966{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000967 static int proc_read;
968 FILE *fh;
969 char buf[512];
970 struct interface *ife;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000971 int err, procnetdev_vsn;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000972
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000973 if (proc_read)
974 return 0;
975 if (!target)
976 proc_read = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000977
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000978 fh = fopen(_PATH_PROCNET_DEV, "r");
979 if (!fh) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000980 bb_perror_msg(_("Warning: cannot open %s. Limited output."), _PATH_PROCNET_DEV);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000981 return if_readconf();
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000982 }
983 fgets(buf, sizeof buf, fh); /* eat line */
984 fgets(buf, sizeof buf, fh);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000985
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000986 procnetdev_vsn = procnetdev_version(buf);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000987
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000988 err = 0;
989 while (fgets(buf, sizeof buf, fh)) {
Eric Andersenf96675b2003-07-28 06:37:04 +0000990 char *s, name[128];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000991
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000992 s = get_name(name, buf);
993 ife = add_interface(name);
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000994 get_dev_fields(s, ife, procnetdev_vsn);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000995 ife->statistics_valid = 1;
996 if (target && !strcmp(target, name))
997 break;
998 }
999 if (ferror(fh)) {
1000 perror(_PATH_PROCNET_DEV);
1001 err = -1;
1002 proc_read = 0;
1003 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001004 fclose(fh);
1005 return err;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001006}
1007
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001008static int if_readlist(void)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001009{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001010 int err = if_readlist_proc(NULL);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001011
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001012 if (!err)
1013 err = if_readconf();
1014 return err;
1015}
1016
1017static int for_all_interfaces(int (*doit) (struct interface *, void *),
1018 void *cookie)
1019{
1020 struct interface *ife;
1021
1022 if (!int_list && (if_readlist() < 0))
1023 return -1;
1024 for (ife = int_list; ife; ife = ife->next) {
1025 int err = doit(ife, cookie);
1026
1027 if (err)
1028 return err;
1029 }
1030 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001031}
1032
Eric Andersenf15d4da2001-03-06 00:48:59 +00001033/* Fetch the interface configuration from the kernel. */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001034static int if_fetch(struct interface *ife)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001035{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001036 struct ifreq ifr;
1037 int fd;
1038 char *ifname = ife->name;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001039
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001040 strcpy(ifr.ifr_name, ifname);
1041 if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
1042 return (-1);
1043 ife->flags = ifr.ifr_flags;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001044
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001045 strcpy(ifr.ifr_name, ifname);
1046 if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
1047 memset(ife->hwaddr, 0, 32);
1048 else
1049 memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001050
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001051 ife->type = ifr.ifr_hwaddr.sa_family;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001052
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001053 strcpy(ifr.ifr_name, ifname);
1054 if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0)
1055 ife->metric = 0;
1056 else
1057 ife->metric = ifr.ifr_metric;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001058
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001059 strcpy(ifr.ifr_name, ifname);
1060 if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
1061 ife->mtu = 0;
1062 else
1063 ife->mtu = ifr.ifr_mtu;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001064
1065#ifdef HAVE_HWSLIP
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001066 if (ife->type == ARPHRD_SLIP || ife->type == ARPHRD_CSLIP ||
1067 ife->type == ARPHRD_SLIP6 || ife->type == ARPHRD_CSLIP6 ||
1068 ife->type == ARPHRD_ADAPT) {
Eric Andersenf15d4da2001-03-06 00:48:59 +00001069#ifdef SIOCGOUTFILL
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001070 strcpy(ifr.ifr_name, ifname);
1071 if (ioctl(skfd, SIOCGOUTFILL, &ifr) < 0)
1072 ife->outfill = 0;
1073 else
1074 ife->outfill = (unsigned int) ifr.ifr_data;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001075#endif
1076#ifdef SIOCGKEEPALIVE
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001077 strcpy(ifr.ifr_name, ifname);
1078 if (ioctl(skfd, SIOCGKEEPALIVE, &ifr) < 0)
1079 ife->keepalive = 0;
1080 else
1081 ife->keepalive = (unsigned int) ifr.ifr_data;
1082#endif
1083 }
1084#endif
1085
Rob Landley93983042005-05-03 21:30:26 +00001086#ifdef SIOCGIFMAP
Eric Andersenf15d4da2001-03-06 00:48:59 +00001087 strcpy(ifr.ifr_name, ifname);
Rob Landley93983042005-05-03 21:30:26 +00001088 if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0)
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001089 ife->map = ifr.ifr_map;
Rob Landley93983042005-05-03 21:30:26 +00001090 else
1091#endif
1092 memset(&ife->map, 0, sizeof(struct ifmap));
Eric Andersenf15d4da2001-03-06 00:48:59 +00001093
1094#ifdef HAVE_TXQUEUELEN
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001095 strcpy(ifr.ifr_name, ifname);
1096 if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0)
1097 ife->tx_queue_len = -1; /* unknown value */
1098 else
1099 ife->tx_queue_len = ifr.ifr_qlen;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001100#else
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001101 ife->tx_queue_len = -1; /* unknown value */
Eric Andersenf15d4da2001-03-06 00:48:59 +00001102#endif
1103
1104#if HAVE_AFINET
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001105 /* IPv4 address? */
1106 fd = get_socket_for_af(AF_INET);
1107 if (fd >= 0) {
1108 strcpy(ifr.ifr_name, ifname);
1109 ifr.ifr_addr.sa_family = AF_INET;
1110 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
1111 ife->has_ip = 1;
1112 ife->addr = ifr.ifr_addr;
1113 strcpy(ifr.ifr_name, ifname);
1114 if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0)
1115 memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
1116 else
1117 ife->dstaddr = ifr.ifr_dstaddr;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001118
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001119 strcpy(ifr.ifr_name, ifname);
1120 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
1121 memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
1122 else
1123 ife->broadaddr = ifr.ifr_broadaddr;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001124
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001125 strcpy(ifr.ifr_name, ifname);
1126 if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
1127 memset(&ife->netmask, 0, sizeof(struct sockaddr));
1128 else
1129 ife->netmask = ifr.ifr_netmask;
1130 } else
1131 memset(&ife->addr, 0, sizeof(struct sockaddr));
1132 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001133#endif
1134
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001135 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001136}
1137
1138
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001139static int do_if_fetch(struct interface *ife)
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001140{
1141 if (if_fetch(ife) < 0) {
1142 char *errmsg;
1143
1144 if (errno == ENODEV) {
1145 /* Give better error message for this case. */
1146 errmsg = _("Device not found");
1147 } else {
1148 errmsg = strerror(errno);
1149 }
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +00001150 bb_error_msg(_("%s: error fetching interface information: %s"),
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001151 ife->name, errmsg);
1152 return -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001153 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001154 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001155}
1156
1157/* This structure defines hardware protocols and their handlers. */
1158struct hwtype {
Bernhard Reutner-Fischera901b402006-01-19 14:51:17 +00001159 const char * const name;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001160 const char *title;
1161 int type;
1162 int alen;
1163 char *(*print) (unsigned char *);
1164 int (*input) (char *, struct sockaddr *);
1165 int (*activate) (int fd);
1166 int suppress_null_addr;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001167};
1168
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +00001169static const struct hwtype unspec_hwtype = {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001170 "unspec", "UNSPEC", -1, 0,
1171 UNSPEC_print, NULL, NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +00001172};
1173
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +00001174static const struct hwtype loop_hwtype = {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001175 "loop", "Local Loopback", ARPHRD_LOOPBACK, 0,
1176 NULL, NULL, NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +00001177};
1178
1179#if HAVE_HWETHER
1180#include <net/if_arp.h>
Eric Andersenab4e19a2003-01-14 08:54:08 +00001181
Mike Frysinger3b05b802005-03-04 01:10:56 +00001182#if (__GLIBC__ >=2 && __GLIBC_MINOR >= 1) || defined(_NEWLIB_VERSION)
Eric Andersenab4e19a2003-01-14 08:54:08 +00001183#include <net/ethernet.h>
1184#else
Eric Andersenf15d4da2001-03-06 00:48:59 +00001185#include <linux/if_ether.h>
Eric Andersenab4e19a2003-01-14 08:54:08 +00001186#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +00001187
Eric Andersenf15d4da2001-03-06 00:48:59 +00001188/* Display an Ethernet address in readable format. */
1189static char *pr_ether(unsigned char *ptr)
1190{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001191 static char buff[64];
Eric Andersenf15d4da2001-03-06 00:48:59 +00001192
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001193 snprintf(buff, sizeof(buff), "%02X:%02X:%02X:%02X:%02X:%02X",
1194 (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377),
1195 (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)
1196 );
1197 return (buff);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001198}
1199
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001200#ifdef KEEP_UNUSED
Eric Andersenf15d4da2001-03-06 00:48:59 +00001201/* Input an Ethernet address and convert to binary. */
1202static int in_ether(char *bufp, struct sockaddr *sap)
1203{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001204 unsigned char *ptr;
1205 char c, *orig;
1206 int i;
1207 unsigned val;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001208
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001209 sap->sa_family = ether_hwtype.type;
1210 ptr = sap->sa_data;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001211
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001212 i = 0;
1213 orig = bufp;
1214 while ((*bufp != '\0') && (i < ETH_ALEN)) {
1215 val = 0;
1216 c = *bufp++;
1217 if (isdigit(c))
1218 val = c - '0';
1219 else if (c >= 'a' && c <= 'f')
1220 val = c - 'a' + 10;
1221 else if (c >= 'A' && c <= 'F')
1222 val = c - 'A' + 10;
1223 else {
Eric Andersenf15d4da2001-03-06 00:48:59 +00001224#ifdef DEBUG
Manuel Novoa III cad53642003-03-19 09:13:01 +00001225 bb_error_msg(_("in_ether(%s): invalid ether address!\n"), orig);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001226#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001227 errno = EINVAL;
1228 return (-1);
1229 }
1230 val <<= 4;
1231 c = *bufp;
1232 if (isdigit(c))
1233 val |= c - '0';
1234 else if (c >= 'a' && c <= 'f')
1235 val |= c - 'a' + 10;
1236 else if (c >= 'A' && c <= 'F')
1237 val |= c - 'A' + 10;
1238 else if (c == ':' || c == 0)
1239 val >>= 4;
1240 else {
1241#ifdef DEBUG
Manuel Novoa III cad53642003-03-19 09:13:01 +00001242 bb_error_msg(_("in_ether(%s): invalid ether address!"), orig);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001243#endif
1244 errno = EINVAL;
1245 return (-1);
1246 }
1247 if (c != 0)
1248 bufp++;
1249 *ptr++ = (unsigned char) (val & 0377);
1250 i++;
1251
1252 /* We might get a semicolon here - not required. */
1253 if (*bufp == ':') {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001254#ifdef DEBUG
Glenn L McGrath642f2892002-11-28 10:20:45 +00001255 if (i == ETH_ALEN) {
Manuel Novoa III cad53642003-03-19 09:13:01 +00001256 bb_error_msg(_("in_ether(%s): trailing : ignored!"), orig);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001257 }
Glenn L McGrath642f2892002-11-28 10:20:45 +00001258#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001259 bufp++;
1260 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001261 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001262
Glenn L McGrath642f2892002-11-28 10:20:45 +00001263#ifdef DEBUG
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001264 /* That's it. Any trailing junk? */
1265 if ((i == ETH_ALEN) && (*bufp != '\0')) {
Manuel Novoa III cad53642003-03-19 09:13:01 +00001266 bb_error_msg(_("in_ether(%s): trailing junk!"), orig);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001267 errno = EINVAL;
1268 return (-1);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001269 }
Manuel Novoa III cad53642003-03-19 09:13:01 +00001270 bb_error_msg("in_ether(%s): %s", orig, pr_ether(sap->sa_data));
Eric Andersenf15d4da2001-03-06 00:48:59 +00001271#endif
1272
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001273 return (0);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001274}
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001275#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +00001276
1277
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +00001278static const struct hwtype ether_hwtype = {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001279 "ether", "Ethernet", ARPHRD_ETHER, ETH_ALEN,
1280 pr_ether, NULL /* UNUSED in_ether */ , NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +00001281};
1282
1283
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001284#endif /* HAVE_HWETHER */
Eric Andersenf15d4da2001-03-06 00:48:59 +00001285
1286
1287#if HAVE_HWPPP
1288
1289#include <net/if_arp.h>
1290
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001291#ifdef KEEP_UNUSED
Eric Andersenf15d4da2001-03-06 00:48:59 +00001292/* Start the PPP encapsulation on the file descriptor. */
1293static int do_ppp(int fd)
1294{
Manuel Novoa III cad53642003-03-19 09:13:01 +00001295 bb_error_msg(_("You cannot start PPP with this program."));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001296 return -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001297}
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001298#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +00001299
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +00001300static const struct hwtype ppp_hwtype = {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001301 "ppp", "Point-Point Protocol", ARPHRD_PPP, 0,
1302 NULL, NULL, NULL /* UNUSED do_ppp */ , 0
Eric Andersenf15d4da2001-03-06 00:48:59 +00001303};
1304
1305
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001306#endif /* HAVE_PPP */
Eric Andersenf15d4da2001-03-06 00:48:59 +00001307
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +00001308static const struct hwtype * const hwtypes[] = {
Eric Andersenf15d4da2001-03-06 00:48:59 +00001309
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001310 &loop_hwtype,
Eric Andersenf15d4da2001-03-06 00:48:59 +00001311
1312#if HAVE_HWSLIP
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001313 &slip_hwtype,
1314 &cslip_hwtype,
1315 &slip6_hwtype,
1316 &cslip6_hwtype,
1317 &adaptive_hwtype,
Eric Andersenf15d4da2001-03-06 00:48:59 +00001318#endif
1319#if HAVE_HWSTRIP
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001320 &strip_hwtype,
Eric Andersenf15d4da2001-03-06 00:48:59 +00001321#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +00001322#if HAVE_HWETHER
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001323 &ether_hwtype,
Eric Andersenf15d4da2001-03-06 00:48:59 +00001324#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +00001325#if HAVE_HWTUNNEL
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001326 &tunnel_hwtype,
Eric Andersenf15d4da2001-03-06 00:48:59 +00001327#endif
1328#if HAVE_HWPPP
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001329 &ppp_hwtype,
Eric Andersenf15d4da2001-03-06 00:48:59 +00001330#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001331 &unspec_hwtype,
1332 NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +00001333};
1334
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001335#ifdef KEEP_UNUSED
Eric Andersenf15d4da2001-03-06 00:48:59 +00001336static short sVhwinit = 0;
1337
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001338static void hwinit()
Eric Andersenf15d4da2001-03-06 00:48:59 +00001339{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001340 loop_hwtype.title = _("Local Loopback");
1341 unspec_hwtype.title = _("UNSPEC");
Eric Andersenf15d4da2001-03-06 00:48:59 +00001342#if HAVE_HWSLIP
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001343 slip_hwtype.title = _("Serial Line IP");
1344 cslip_hwtype.title = _("VJ Serial Line IP");
1345 slip6_hwtype.title = _("6-bit Serial Line IP");
1346 cslip6_hwtype.title = _("VJ 6-bit Serial Line IP");
1347 adaptive_hwtype.title = _("Adaptive Serial Line IP");
Eric Andersenf15d4da2001-03-06 00:48:59 +00001348#endif
1349#if HAVE_HWETHER
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001350 ether_hwtype.title = _("Ethernet");
Eric Andersenf15d4da2001-03-06 00:48:59 +00001351#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +00001352#if HAVE_HWTUNNEL
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001353 tunnel_hwtype.title = _("IPIP Tunnel");
Eric Andersenf15d4da2001-03-06 00:48:59 +00001354#endif
1355#if HAVE_HWPPP
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001356 ppp_hwtype.title = _("Point-to-Point Protocol");
Eric Andersenf15d4da2001-03-06 00:48:59 +00001357#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001358 sVhwinit = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001359}
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001360#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +00001361
1362#ifdef IFF_PORTSEL
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001363#if 0
1364static const char * const if_port_text[][4] = {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001365 /* Keep in step with <linux/netdevice.h> */
1366 {"unknown", NULL, NULL, NULL},
1367 {"10base2", "bnc", "coax", NULL},
1368 {"10baseT", "utp", "tpe", NULL},
1369 {"AUI", "thick", "db15", NULL},
1370 {"100baseT", NULL, NULL, NULL},
1371 {"100baseTX", NULL, NULL, NULL},
1372 {"100baseFX", NULL, NULL, NULL},
1373 {NULL, NULL, NULL, NULL},
Eric Andersenf15d4da2001-03-06 00:48:59 +00001374};
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001375#else
1376static const char * const if_port_text[] = {
1377 /* Keep in step with <linux/netdevice.h> */
1378 "unknown",
1379 "10base2",
1380 "10baseT",
1381 "AUI",
1382 "100baseT",
1383 "100baseTX",
1384 "100baseFX",
1385 NULL
1386};
1387#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +00001388#endif
1389
1390/* Check our hardware type table for this type. */
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +00001391static const struct hwtype *get_hwntype(int type)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001392{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +00001393 const struct hwtype * const *hwp;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001394
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001395#ifdef KEEP_UNUSED
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001396 if (!sVhwinit)
1397 hwinit();
1398#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +00001399
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001400 hwp = hwtypes;
1401 while (*hwp != NULL) {
1402 if ((*hwp)->type == type)
1403 return (*hwp);
1404 hwp++;
1405 }
1406 return (NULL);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001407}
1408
1409/* return 1 if address is all zeros */
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +00001410static int hw_null_address(const struct hwtype *hw, void *ap)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001411{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001412 unsigned int i;
1413 unsigned char *address = (unsigned char *) ap;
1414
1415 for (i = 0; i < hw->alen; i++)
1416 if (address[i])
1417 return 0;
1418 return 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001419}
1420
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001421static const char TRext[] = "\0\0\0Ki\0Mi\0Gi\0Ti";
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001422
1423static void print_bytes_scaled(unsigned long long ull, const char *end)
1424{
1425 unsigned long long int_part;
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001426 const char *ext;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001427 unsigned int frac_part;
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001428 int i;
1429
1430 frac_part = 0;
1431 ext = TRext;
1432 int_part = ull;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001433 i = 4;
1434 do {
1435#if 0
1436 /* This does correct rounding and is a little larger. But it
1437 * uses KiB as the smallest displayed unit. */
1438 if ((int_part < (1024*1024 - 51)) || !--i) {
1439 i = 0;
1440 int_part += 51; /* 1024*.05 = 51.2 */
1441 frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001442 }
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001443 int_part /= 1024;
1444 ext += 3; /* KiB, MiB, GiB, TiB */
1445#else
1446 if (int_part >= 1024) {
1447 frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
1448 int_part /= 1024;
1449 ext += 3; /* KiB, MiB, GiB, TiB */
1450 }
1451 --i;
1452#endif
1453 } while (i);
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001454
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001455 printf("X bytes:%llu (%llu.%u %sB)%s", ull, int_part, frac_part, ext, end);
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001456}
1457
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001458static const char * const ife_print_flags_strs[] = {
1459 "UP ",
1460 "BROADCAST ",
1461 "DEBUG ",
1462 "LOOPBACK ",
1463 "POINTOPOINT ",
1464 "NOTRAILERS ",
1465 "RUNNING ",
1466 "NOARP ",
1467 "PROMISC ",
1468 "ALLMULTI ",
1469 "SLAVE ",
1470 "MASTER ",
1471 "MULTICAST ",
1472#ifdef HAVE_DYNAMIC
1473 "DYNAMIC "
1474#endif
1475};
1476
1477static const unsigned short ife_print_flags_mask[] = {
1478 IFF_UP,
1479 IFF_BROADCAST,
1480 IFF_DEBUG,
1481 IFF_LOOPBACK,
1482 IFF_POINTOPOINT,
1483 IFF_NOTRAILERS,
1484 IFF_RUNNING,
1485 IFF_NOARP,
1486 IFF_PROMISC,
1487 IFF_ALLMULTI,
1488 IFF_SLAVE,
1489 IFF_MASTER,
1490 IFF_MULTICAST,
1491#ifdef HAVE_DYNAMIC
1492 IFF_DYNAMIC
1493#endif
1494 0
1495};
1496
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001497static void ife_print(struct interface *ptr)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001498{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001499 struct aftype *ap;
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +00001500 const struct hwtype *hw;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001501 int hf;
1502 int can_compress = 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001503
Eric Andersenf15d4da2001-03-06 00:48:59 +00001504#if HAVE_AFINET6
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001505 FILE *f;
1506 char addr6[40], devname[20];
1507 struct sockaddr_in6 sap;
1508 int plen, scope, dad_status, if_idx;
1509 char addr6p[8][5];
Eric Andersenf15d4da2001-03-06 00:48:59 +00001510#endif
1511
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001512 ap = get_afntype(ptr->addr.sa_family);
1513 if (ap == NULL)
1514 ap = get_afntype(0);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001515
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001516 hf = ptr->type;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001517
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001518 if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
1519 can_compress = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001520
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001521 hw = get_hwntype(hf);
1522 if (hw == NULL)
1523 hw = get_hwntype(-1);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001524
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001525 printf(_("%-9.9s Link encap:%s "), ptr->name, _(hw->title));
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001526 /* For some hardware types (eg Ash, ATM) we don't print the
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001527 hardware address if it's null. */
1528 if (hw->print != NULL && (!(hw_null_address(hw, ptr->hwaddr) &&
1529 hw->suppress_null_addr)))
Eric Andersen0cb6f352006-01-30 22:30:41 +00001530 printf(_("HWaddr %s "), hw->print((unsigned char *)ptr->hwaddr));
Eric Andersenf15d4da2001-03-06 00:48:59 +00001531#ifdef IFF_PORTSEL
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001532 if (ptr->flags & IFF_PORTSEL) {
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001533 printf(_("Media:%s"), if_port_text[ptr->map.port] /* [0] */);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001534 if (ptr->flags & IFF_AUTOMEDIA)
1535 printf(_("(auto)"));
1536 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001537#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001538 printf("\n");
Eric Andersenf15d4da2001-03-06 00:48:59 +00001539
1540#if HAVE_AFINET
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001541 if (ptr->has_ip) {
1542 printf(_(" %s addr:%s "), ap->name,
1543 ap->sprint(&ptr->addr, 1));
1544 if (ptr->flags & IFF_POINTOPOINT) {
1545 printf(_(" P-t-P:%s "), ap->sprint(&ptr->dstaddr, 1));
1546 }
1547 if (ptr->flags & IFF_BROADCAST) {
1548 printf(_(" Bcast:%s "), ap->sprint(&ptr->broadaddr, 1));
1549 }
1550 printf(_(" Mask:%s\n"), ap->sprint(&ptr->netmask, 1));
Eric Andersenf15d4da2001-03-06 00:48:59 +00001551 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001552#endif
1553
1554#if HAVE_AFINET6
Eric Andersenf15d4da2001-03-06 00:48:59 +00001555
Eric Andersen51b8bd62002-07-03 11:46:38 +00001556#define IPV6_ADDR_ANY 0x0000U
1557
1558#define IPV6_ADDR_UNICAST 0x0001U
1559#define IPV6_ADDR_MULTICAST 0x0002U
1560#define IPV6_ADDR_ANYCAST 0x0004U
1561
1562#define IPV6_ADDR_LOOPBACK 0x0010U
1563#define IPV6_ADDR_LINKLOCAL 0x0020U
1564#define IPV6_ADDR_SITELOCAL 0x0040U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001565
Eric Andersen51b8bd62002-07-03 11:46:38 +00001566#define IPV6_ADDR_COMPATv4 0x0080U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001567
Eric Andersen51b8bd62002-07-03 11:46:38 +00001568#define IPV6_ADDR_SCOPE_MASK 0x00f0U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001569
Eric Andersen51b8bd62002-07-03 11:46:38 +00001570#define IPV6_ADDR_MAPPED 0x1000U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001571#define IPV6_ADDR_RESERVED 0x2000U /* reserved address space */
1572
1573 if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
1574 while (fscanf
1575 (f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
1576 addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
1577 addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope,
1578 &dad_status, devname) != EOF) {
1579 if (!strcmp(devname, ptr->name)) {
1580 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
1581 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
1582 addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
1583 inet_pton(AF_INET6, addr6,
1584 (struct sockaddr *) &sap.sin6_addr);
1585 sap.sin6_family = AF_INET6;
1586 printf(_(" inet6 addr: %s/%d"),
1587 inet6_aftype.sprint((struct sockaddr *) &sap, 1),
1588 plen);
1589 printf(_(" Scope:"));
1590 switch (scope & IPV6_ADDR_SCOPE_MASK) {
1591 case 0:
1592 printf(_("Global"));
1593 break;
1594 case IPV6_ADDR_LINKLOCAL:
1595 printf(_("Link"));
1596 break;
1597 case IPV6_ADDR_SITELOCAL:
1598 printf(_("Site"));
1599 break;
1600 case IPV6_ADDR_COMPATv4:
1601 printf(_("Compat"));
1602 break;
1603 case IPV6_ADDR_LOOPBACK:
1604 printf(_("Host"));
1605 break;
1606 default:
1607 printf(_("Unknown"));
1608 }
1609 printf("\n");
1610 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001611 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001612 fclose(f);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001613 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001614#endif
1615
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001616 printf(" ");
1617 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001618
1619 if (ptr->flags == 0) {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001620 printf(_("[NO FLAGS] "));
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001621 } else {
1622 int i = 0;
1623 do {
1624 if (ptr->flags & ife_print_flags_mask[i]) {
1625 printf(_(ife_print_flags_strs[i]));
1626 }
1627 } while (ife_print_flags_mask[++i]);
1628 }
1629
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001630 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
1631 printf(_(" MTU:%d Metric:%d"), ptr->mtu, ptr->metric ? ptr->metric : 1);
1632#ifdef SIOCSKEEPALIVE
1633 if (ptr->outfill || ptr->keepalive)
1634 printf(_(" Outfill:%d Keepalive:%d"), ptr->outfill, ptr->keepalive);
1635#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +00001636 printf("\n");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001637
1638 /* If needed, display the interface statistics. */
1639
1640 if (ptr->statistics_valid) {
1641 /* XXX: statistics are currently only printed for the primary address,
1642 * not for the aliases, although strictly speaking they're shared
1643 * by all addresses.
1644 */
1645 printf(" ");
1646
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001647 printf("RX packets:%llu errors:%lu dropped:%lu overruns:%lu frame:%lu\n",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001648 ptr->stats.rx_packets, ptr->stats.rx_errors,
1649 ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors,
1650 ptr->stats.rx_frame_errors);
1651 if (can_compress)
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001652 printf(" compressed:%lu\n",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001653 ptr->stats.rx_compressed);
1654 printf(" ");
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001655 printf("TX packets:%llu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001656 ptr->stats.tx_packets, ptr->stats.tx_errors,
1657 ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
1658 ptr->stats.tx_carrier_errors);
Bernhard Reutner-Fischer214744d2006-03-30 13:38:19 +00001659 printf(" collisions:%lu ", ptr->stats.collisions);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001660 if (can_compress)
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001661 printf("compressed:%lu ", ptr->stats.tx_compressed);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001662 if (ptr->tx_queue_len != -1)
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001663 printf("txqueuelen:%d ", ptr->tx_queue_len);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001664 printf("\n R");
1665 print_bytes_scaled(ptr->stats.rx_bytes, " T");
1666 print_bytes_scaled(ptr->stats.tx_bytes, "\n");
1667
1668 }
1669
1670 if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
1671 ptr->map.base_addr)) {
1672 printf(" ");
1673 if (ptr->map.irq)
1674 printf(_("Interrupt:%d "), ptr->map.irq);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001675 if (ptr->map.base_addr >= 0x100) /* Only print devices using it for
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001676 I/O maps */
1677 printf(_("Base address:0x%lx "),
1678 (unsigned long) ptr->map.base_addr);
1679 if (ptr->map.mem_start) {
1680 printf(_("Memory:%lx-%lx "), ptr->map.mem_start,
1681 ptr->map.mem_end);
1682 }
1683 if (ptr->map.dma)
1684 printf(_("DMA chan:%x "), ptr->map.dma);
1685 printf("\n");
1686 }
1687 printf("\n");
Eric Andersenf15d4da2001-03-06 00:48:59 +00001688}
1689
1690
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001691static int do_if_print(struct interface *ife, void *cookie)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001692{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001693 int *opt_a = (int *) cookie;
1694 int res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001695
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001696 res = do_if_fetch(ife);
1697 if (res >= 0) {
1698 if ((ife->flags & IFF_UP) || *opt_a)
1699 ife_print(ife);
1700 }
1701 return res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001702}
1703
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001704static struct interface *lookup_interface(char *name)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001705{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001706 struct interface *ife = NULL;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001707
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001708 if (if_readlist_proc(name) < 0)
1709 return NULL;
1710 ife = add_interface(name);
1711 return ife;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001712}
1713
1714/* for ipv4 add/del modes */
1715static int if_print(char *ifname)
1716{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001717 int res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001718
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001719 if (!ifname) {
1720 res = for_all_interfaces(do_if_print, &interface_opt_a);
1721 } else {
1722 struct interface *ife;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001723
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001724 ife = lookup_interface(ifname);
1725 res = do_if_fetch(ife);
1726 if (res >= 0)
1727 ife_print(ife);
1728 }
1729 return res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001730}
1731
Mike Frysingerb5547fb2006-05-11 02:35:55 +00001732int display_interfaces(char *ifname);
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001733int display_interfaces(char *ifname)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001734{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001735 int status;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001736
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001737 /* Create a channel to the NET kernel. */
1738 if ((skfd = sockets_open(0)) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +00001739 bb_perror_msg_and_die("socket");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001740 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001741
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001742 /* Do we have to show the current setup? */
1743 status = if_print(ifname);
Rob Landley93983042005-05-03 21:30:26 +00001744#ifdef CONFIG_FEATURE_CLEAN_UP
1745 sockets_close();
1746#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001747 exit(status < 0);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001748}