blob: 8784522369a780f2a55c23b7c3c8191dfa11e104 [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 Andersenf15d4da2001-03-06 00:48:59 +000081
Eric Andersenf15d4da2001-03-06 00:48:59 +000082#ifdef HAVE_HWSLIP
Eric Andersenab4e19a2003-01-14 08:54:08 +000083#include <net/if_slip.h>
Eric Andersenf15d4da2001-03-06 00:48:59 +000084#endif
85
86#if HAVE_AFINET6
87
88#ifndef _LINUX_IN6_H
89/*
90 * This is in linux/include/net/ipv6.h.
91 */
92
93struct in6_ifreq {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +000094 struct in6_addr ifr6_addr;
Glenn L McGrathb54a7482003-08-29 11:34:08 +000095 uint32_t ifr6_prefixlen;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +000096 unsigned int ifr6_ifindex;
Eric Andersenf15d4da2001-03-06 00:48:59 +000097};
98
99#endif
100
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000101#endif /* HAVE_AFINET6 */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000102
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000103/* Defines for glibc2.0 users. */
104#ifndef SIOCSIFTXQLEN
105#define SIOCSIFTXQLEN 0x8943
106#define SIOCGIFTXQLEN 0x8942
107#endif
108
109/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
110#ifndef ifr_qlen
111#define ifr_qlen ifr_ifru.ifru_mtu
112#endif
113
114#ifndef HAVE_TXQUEUELEN
115#define HAVE_TXQUEUELEN 1
116#endif
117
118#ifndef IFF_DYNAMIC
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000119#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000120#endif
121
Eric Andersenf15d4da2001-03-06 00:48:59 +0000122/* This structure defines protocol families and their handlers. */
123struct aftype {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000124 const char *name;
125 const char *title;
126 int af;
127 int alen;
128 char *(*print) (unsigned char *);
129 char *(*sprint) (struct sockaddr *, int numeric);
130 int (*input) (int type, char *bufp, struct sockaddr *);
131 void (*herror) (char *text);
132 int (*rprint) (int options);
133 int (*rinput) (int typ, int ext, char **argv);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000134
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000135 /* may modify src */
136 int (*getmask) (char *src, struct sockaddr * mask, char *name);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000137
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000138 int fd;
139 char *flag_file;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000140};
141
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000142#ifdef KEEP_UNUSED
143
144static int flag_unx;
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000145static int flag_inet;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000146
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000147static struct aftrans_t {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000148 char *alias;
149 char *name;
150 int *flag;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000151} aftrans[] = {
152
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000153 {
154 "ip", "inet", &flag_inet},
Eric Andersen8b113f92001-06-01 21:47:15 +0000155#ifdef HAVE_AFINET6
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000156 {
157 "ip6", "inet6", &flag_inet6},
Eric Andersen8b113f92001-06-01 21:47:15 +0000158#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000159 {
160 "inet", "inet", &flag_inet},
Eric Andersen8b113f92001-06-01 21:47:15 +0000161#ifdef HAVE_AFINET6
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000162 {
163 "inet6", "inet6", &flag_inet6},
Eric Andersen8b113f92001-06-01 21:47:15 +0000164#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000165 {
166 "unix", "unix", &flag_unx}, {
167 "tcpip", "inet", &flag_inet},
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000168 {
169 0, 0, 0}
Eric Andersenf15d4da2001-03-06 00:48:59 +0000170};
171
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000172static char afname[256] = "";
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000173#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000174
175#if HAVE_AFUNIX
176
177/* Display a UNIX domain address. */
178static char *UNIX_print(unsigned char *ptr)
179{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000180 return (ptr);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000181}
182
183
184/* Display a UNIX domain address. */
185static char *UNIX_sprint(struct sockaddr *sap, int numeric)
186{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000187 static char buf[64];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000188
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000189 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
190 return safe_strncpy(buf, _("[NONE SET]"), sizeof(buf));
191 return (UNIX_print(sap->sa_data));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000192}
193
194
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000195static struct aftype unix_aftype = {
196 "unix", "UNIX Domain", AF_UNIX, 0,
197 UNIX_print, UNIX_sprint, NULL, NULL,
198 NULL, NULL, NULL,
199 -1,
200 "/proc/net/unix"
Eric Andersenf15d4da2001-03-06 00:48:59 +0000201};
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000202#endif /* HAVE_AFUNIX */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000203
204#if HAVE_AFINET
205
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000206#ifdef KEEP_UNUSED
Eric Andersenf15d4da2001-03-06 00:48:59 +0000207static void INET_reserror(char *text)
208{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000209 herror(text);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000210}
211
Eric Andersenf15d4da2001-03-06 00:48:59 +0000212/* Display an Internet socket address. */
213static char *INET_print(unsigned char *ptr)
214{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000215 return (inet_ntoa((*(struct in_addr *) ptr)));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000216}
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000217#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000218
219/* Display an Internet socket address. */
220static char *INET_sprint(struct sockaddr *sap, int numeric)
221{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000222 static char buff[128];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000223
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000224 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
225 return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000226
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000227 if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap,
228 numeric, 0xffffff00) != 0)
229 return (NULL);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000230
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000231 return (buff);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000232}
233
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000234#ifdef KEEP_UNUSED
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000235static char *INET_sprintmask(struct sockaddr *sap, int numeric,
236 unsigned int netmask)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000237{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000238 static char buff[128];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000239
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000240 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
241 return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff));
242 if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap,
243 numeric, netmask) != 0)
244 return (NULL);
245 return (buff);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000246}
247
Eric Andersenf15d4da2001-03-06 00:48:59 +0000248static int INET_getsock(char *bufp, struct sockaddr *sap)
249{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000250 char *sp = bufp, *bp;
251 unsigned int i;
252 unsigned val;
253 struct sockaddr_in *sin;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000254
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000255 sin = (struct sockaddr_in *) sap;
256 sin->sin_family = AF_INET;
257 sin->sin_port = 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000258
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000259 val = 0;
260 bp = (char *) &val;
261 for (i = 0; i < sizeof(sin->sin_addr.s_addr); i++) {
262 *sp = toupper(*sp);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000263
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000264 if ((*sp >= 'A') && (*sp <= 'F'))
265 bp[i] |= (int) (*sp - 'A') + 10;
266 else if ((*sp >= '0') && (*sp <= '9'))
267 bp[i] |= (int) (*sp - '0');
268 else
269 return (-1);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000270
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000271 bp[i] <<= 4;
272 sp++;
273 *sp = toupper(*sp);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000274
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000275 if ((*sp >= 'A') && (*sp <= 'F'))
276 bp[i] |= (int) (*sp - 'A') + 10;
277 else if ((*sp >= '0') && (*sp <= '9'))
278 bp[i] |= (int) (*sp - '0');
279 else
280 return (-1);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000281
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000282 sp++;
283 }
284 sin->sin_addr.s_addr = htonl(val);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000285
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000286 return (sp - bufp);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000287}
288
289static int INET_input(int type, char *bufp, struct sockaddr *sap)
290{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000291 switch (type) {
292 case 1:
293 return (INET_getsock(bufp, sap));
294 case 256:
295 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 1));
296 default:
297 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0));
298 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000299}
300
301static int INET_getnetmask(char *adr, struct sockaddr *m, char *name)
302{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000303 struct sockaddr_in *mask = (struct sockaddr_in *) m;
304 char *slash, *end;
305 int prefix;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000306
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000307 if ((slash = strchr(adr, '/')) == NULL)
308 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000309
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000310 *slash++ = '\0';
311 prefix = strtoul(slash, &end, 0);
312 if (*end != '\0')
313 return -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000314
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000315 if (name) {
316 sprintf(name, "/%d", prefix);
317 }
318 mask->sin_family = AF_INET;
319 mask->sin_addr.s_addr = htonl(~(0xffffffffU >> prefix));
320 return 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000321}
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000322#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000323
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000324static struct aftype inet_aftype = {
325 "inet", "DARPA Internet", AF_INET, sizeof(unsigned long),
326 NULL /* UNUSED INET_print */ , INET_sprint,
327 NULL /* UNUSED INET_input */ , NULL /* UNUSED INET_reserror */ ,
328 NULL /*INET_rprint */ , NULL /*INET_rinput */ ,
329 NULL /* UNUSED INET_getnetmask */ ,
330 -1,
331 NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +0000332};
333
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000334#endif /* HAVE_AFINET */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000335
Eric Andersen51b8bd62002-07-03 11:46:38 +0000336#if HAVE_AFINET6
337
338#ifdef KEEP_UNUSED
339static void INET6_reserror(char *text)
340{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000341 herror(text);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000342}
343
344/* Display an Internet socket address. */
345static char *INET6_print(unsigned char *ptr)
346{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000347 static char name[80];
Eric Andersen51b8bd62002-07-03 11:46:38 +0000348
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000349 inet_ntop(AF_INET6, (struct in6_addr *) ptr, name, 80);
350 return name;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000351}
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000352#endif /* KEEP_UNUSED */
Eric Andersen51b8bd62002-07-03 11:46:38 +0000353
354/* Display an Internet socket address. */
355/* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */
356static char *INET6_sprint(struct sockaddr *sap, int numeric)
357{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000358 static char buff[128];
Eric Andersen51b8bd62002-07-03 11:46:38 +0000359
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000360 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
361 return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff));
362 if (INET6_rresolve
363 (buff, sizeof(buff), (struct sockaddr_in6 *) sap, numeric) != 0)
364 return safe_strncpy(buff, _("[UNKNOWN]"), sizeof(buff));
365 return (buff);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000366}
367
368#ifdef KEEP_UNUSED
369static int INET6_getsock(char *bufp, struct sockaddr *sap)
370{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000371 struct sockaddr_in6 *sin6;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000372
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000373 sin6 = (struct sockaddr_in6 *) sap;
374 sin6->sin6_family = AF_INET6;
375 sin6->sin6_port = 0;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000376
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000377 if (inet_pton(AF_INET6, bufp, sin6->sin6_addr.s6_addr) <= 0)
378 return (-1);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000379
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000380 return 16; /* ?;) */
Eric Andersen51b8bd62002-07-03 11:46:38 +0000381}
382
383static int INET6_input(int type, char *bufp, struct sockaddr *sap)
384{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000385 switch (type) {
386 case 1:
387 return (INET6_getsock(bufp, sap));
388 default:
389 return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap));
390 }
Eric Andersen51b8bd62002-07-03 11:46:38 +0000391}
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000392#endif /* KEEP_UNUSED */
Eric Andersen51b8bd62002-07-03 11:46:38 +0000393
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000394static struct aftype inet6_aftype = {
395 "inet6", "IPv6", AF_INET6, sizeof(struct in6_addr),
396 NULL /* UNUSED INET6_print */ , INET6_sprint,
397 NULL /* UNUSED INET6_input */ , NULL /* UNUSED INET6_reserror */ ,
398 NULL /*INET6_rprint */ , NULL /*INET6_rinput */ ,
399 NULL /* UNUSED INET6_getnetmask */ ,
400 -1,
401 NULL
Eric Andersen51b8bd62002-07-03 11:46:38 +0000402};
403
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000404#endif /* HAVE_AFINET6 */
Eric Andersen51b8bd62002-07-03 11:46:38 +0000405
Eric Andersenf15d4da2001-03-06 00:48:59 +0000406/* Display an UNSPEC address. */
407static char *UNSPEC_print(unsigned char *ptr)
408{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000409 static char buff[sizeof(struct sockaddr) * 3 + 1];
410 char *pos;
411 unsigned int i;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000412
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000413 pos = buff;
414 for (i = 0; i < sizeof(struct sockaddr); i++) {
415 /* careful -- not every libc's sprintf returns # bytes written */
416 sprintf(pos, "%02X-", (*ptr++ & 0377));
417 pos += 3;
418 }
419 /* Erase trailing "-". Works as long as sizeof(struct sockaddr) != 0 */
420 *--pos = '\0';
421 return (buff);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000422}
423
424/* Display an UNSPEC socket address. */
425static char *UNSPEC_sprint(struct sockaddr *sap, int numeric)
426{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000427 static char buf[64];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000428
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000429 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
430 return safe_strncpy(buf, _("[NONE SET]"), sizeof(buf));
Eric Andersen0cb6f352006-01-30 22:30:41 +0000431 return (UNSPEC_print((unsigned char *)sap->sa_data));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000432}
433
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000434static struct aftype unspec_aftype = {
435 "unspec", "UNSPEC", AF_UNSPEC, 0,
436 UNSPEC_print, UNSPEC_sprint, NULL, NULL,
437 NULL,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000438};
439
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000440static struct aftype * const aftypes[] = {
Eric Andersenf15d4da2001-03-06 00:48:59 +0000441#if HAVE_AFUNIX
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000442 &unix_aftype,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000443#endif
444#if HAVE_AFINET
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000445 &inet_aftype,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000446#endif
447#if HAVE_AFINET6
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000448 &inet6_aftype,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000449#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000450 &unspec_aftype,
451 NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +0000452};
453
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000454#ifdef KEEP_UNUSED
455static short sVafinit = 0;
456
457static void afinit()
Eric Andersenf15d4da2001-03-06 00:48:59 +0000458{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000459 unspec_aftype.title = _("UNSPEC");
Eric Andersenf15d4da2001-03-06 00:48:59 +0000460#if HAVE_AFUNIX
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000461 unix_aftype.title = _("UNIX Domain");
Eric Andersenf15d4da2001-03-06 00:48:59 +0000462#endif
463#if HAVE_AFINET
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000464 inet_aftype.title = _("DARPA Internet");
Eric Andersenf15d4da2001-03-06 00:48:59 +0000465#endif
466#if HAVE_AFINET6
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000467 inet6_aftype.title = _("IPv6");
Eric Andersenf15d4da2001-03-06 00:48:59 +0000468#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000469 sVafinit = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000470}
471
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000472static int aftrans_opt(const char *arg)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000473{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000474 struct aftrans_t *paft;
475 char *tmp1, *tmp2;
476 char buf[256];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000477
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000478 safe_strncpy(buf, arg, sizeof(buf));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000479
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000480 tmp1 = buf;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000481
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000482 while (tmp1) {
Eric Andersenf15d4da2001-03-06 00:48:59 +0000483
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000484 tmp2 = strchr(tmp1, ',');
Eric Andersenf15d4da2001-03-06 00:48:59 +0000485
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000486 if (tmp2)
487 *(tmp2++) = '\0';
Eric Andersenf15d4da2001-03-06 00:48:59 +0000488
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000489 paft = aftrans;
490 for (paft = aftrans; paft->alias; paft++) {
491 if (strcmp(tmp1, paft->alias))
492 continue;
493 if (strlen(paft->name) + strlen(afname) + 1 >= sizeof(afname)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000494 bb_error_msg(_("Too many address family arguments."));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000495 return (0);
496 }
497 if (paft->flag)
498 (*paft->flag)++;
499 if (afname[0])
500 strcat(afname, ",");
501 strcat(afname, paft->name);
502 break;
503 }
504 if (!paft->alias) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000505 bb_error_msg(_("Unknown address family `%s'."), tmp1);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000506 return (1);
507 }
508 tmp1 = tmp2;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000509 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000510
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000511 return (0);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000512}
513
514/* set the default AF list from the program name or a constant value */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000515static void aftrans_def(char *tool, char *argv0, char *dflt)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000516{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000517 char *tmp;
518 char *buf;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000519
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000520 strcpy(afname, dflt);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000521
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000522 if (!(tmp = strrchr(argv0, '/')))
523 tmp = argv0; /* no slash?! */
524 else
525 tmp++;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000526
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000527 if (!(buf = strdup(tmp)))
528 return;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000529
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000530 if (strlen(tool) >= strlen(tmp)) {
531 free(buf);
532 return;
533 }
534 tmp = buf + (strlen(tmp) - strlen(tool));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000535
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000536 if (strcmp(tmp, tool) != 0) {
537 free(buf);
538 return;
539 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000540 *tmp = '\0';
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000541 if ((tmp = strchr(buf, '_')))
542 *tmp = '\0';
Eric Andersenf15d4da2001-03-06 00:48:59 +0000543
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000544 afname[0] = '\0';
545 if (aftrans_opt(buf))
546 strcpy(afname, buf);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000547
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000548 free(buf);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000549}
550
Eric Andersenf15d4da2001-03-06 00:48:59 +0000551/* Check our protocol family table for this family. */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000552static struct aftype *get_aftype(const char *name)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000553{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000554 struct aftype * const *afp;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000555
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000556#ifdef KEEP_UNUSED
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000557 if (!sVafinit)
558 afinit();
559#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000560
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000561 afp = aftypes;
562 while (*afp != NULL) {
563 if (!strcmp((*afp)->name, name))
564 return (*afp);
565 afp++;
566 }
567 if (strchr(name, ','))
Manuel Novoa III cad53642003-03-19 09:13:01 +0000568 bb_error_msg(_("Please don't supply more than one address family."));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000569 return (NULL);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000570}
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000571#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000572
573/* Check our protocol family table for this family. */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000574static struct aftype *get_afntype(int af)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000575{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000576 struct aftype * const *afp;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000577
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000578#ifdef KEEP_UNUSED
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000579 if (!sVafinit)
580 afinit();
581#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000582
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000583 afp = aftypes;
584 while (*afp != NULL) {
585 if ((*afp)->af == af)
586 return (*afp);
587 afp++;
588 }
589 return (NULL);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000590}
591
592/* Check our protocol family table for this family and return its socket */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000593static int get_socket_for_af(int af)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000594{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000595 struct aftype * const *afp;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000596
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000597#ifdef KEEP_UNUSED
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000598 if (!sVafinit)
599 afinit();
600#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000601
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000602 afp = aftypes;
603 while (*afp != NULL) {
604 if ((*afp)->af == af)
605 return (*afp)->fd;
606 afp++;
607 }
608 return -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000609}
610
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000611#ifdef KEEP_UNUSED
Eric Andersenf15d4da2001-03-06 00:48:59 +0000612/* type: 0=all, 1=getroute */
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000613static void print_aflist(int type)
614{
615 int count = 0;
616 char *txt;
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000617 struct aftype * const *afp;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000618
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000619#ifdef KEEP_UNUSED
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000620 if (!sVafinit)
621 afinit();
622#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000623
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000624 afp = aftypes;
625 while (*afp != NULL) {
626 if ((type == 1 && ((*afp)->rprint == NULL)) || ((*afp)->af == 0)) {
627 afp++;
628 continue;
629 }
630 if ((count % 3) == 0)
631 fprintf(stderr, count ? "\n " : " ");
632 txt = (*afp)->name;
633 if (!txt)
634 txt = "..";
635 fprintf(stderr, "%s (%s) ", txt, _((*afp)->title));
636 count++;
637 afp++;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000638 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000639 fprintf(stderr, "\n");
Eric Andersenf15d4da2001-03-06 00:48:59 +0000640}
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000641#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000642
643struct user_net_device_stats {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000644 unsigned long long rx_packets; /* total packets received */
645 unsigned long long tx_packets; /* total packets transmitted */
646 unsigned long long rx_bytes; /* total bytes received */
647 unsigned long long tx_bytes; /* total bytes transmitted */
648 unsigned long rx_errors; /* bad packets received */
649 unsigned long tx_errors; /* packet transmit problems */
650 unsigned long rx_dropped; /* no space in linux buffers */
651 unsigned long tx_dropped; /* no space available in linux */
652 unsigned long rx_multicast; /* multicast packets received */
653 unsigned long rx_compressed;
654 unsigned long tx_compressed;
655 unsigned long collisions;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000656
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000657 /* detailed rx_errors: */
658 unsigned long rx_length_errors;
659 unsigned long rx_over_errors; /* receiver ring buff overflow */
660 unsigned long rx_crc_errors; /* recved pkt with crc error */
661 unsigned long rx_frame_errors; /* recv'd frame alignment error */
662 unsigned long rx_fifo_errors; /* recv'r fifo overrun */
663 unsigned long rx_missed_errors; /* receiver missed packet */
664 /* detailed tx_errors */
665 unsigned long tx_aborted_errors;
666 unsigned long tx_carrier_errors;
667 unsigned long tx_fifo_errors;
668 unsigned long tx_heartbeat_errors;
669 unsigned long tx_window_errors;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000670};
671
672struct interface {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000673 struct interface *next, *prev;
674 char name[IFNAMSIZ]; /* interface name */
675 short type; /* if type */
676 short flags; /* various flags */
677 int metric; /* routing metric */
678 int mtu; /* MTU value */
679 int tx_queue_len; /* transmit queue length */
680 struct ifmap map; /* hardware setup */
681 struct sockaddr addr; /* IP address */
682 struct sockaddr dstaddr; /* P-P IP address */
683 struct sockaddr broadaddr; /* IP broadcast address */
684 struct sockaddr netmask; /* IP network mask */
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000685 int has_ip;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000686 char hwaddr[32]; /* HW address */
687 int statistics_valid;
688 struct user_net_device_stats stats; /* statistics */
689 int keepalive; /* keepalive value for SLIP */
690 int outfill; /* outfill value for SLIP */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000691};
692
693
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000694int interface_opt_a = 0; /* show all interfaces */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000695
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000696#ifdef KEEP_UNUSED
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000697static int opt_i = 0; /* show the statistics */
698static int opt_v = 0; /* debugging output flag */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000699
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000700static int addr_family = 0; /* currently selected AF */
701#endif /* KEEP_UNUSED */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000702
Eric Andersenf15d4da2001-03-06 00:48:59 +0000703static struct interface *int_list, *int_last;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000704static int skfd = -1; /* generic raw socket desc. */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000705
706
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000707static int sockets_open(int family)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000708{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000709 struct aftype * const *aft;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000710 int sfd = -1;
711 static int force = -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000712
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000713 if (force < 0) {
714 force = 0;
Bernhard Reutner-Fischere2e56c72006-05-19 11:54:02 +0000715 if (get_linux_version_code() < KERNEL_VERSION(2,1,0))
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000716 force = 1;
717 if (access("/proc/net", R_OK))
718 force = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000719 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000720 for (aft = aftypes; *aft; aft++) {
721 struct aftype *af = *aft;
722 int type = SOCK_DGRAM;
723
724 if (af->af == AF_UNSPEC)
725 continue;
726 if (family && family != af->af)
727 continue;
728 if (af->fd != -1) {
729 sfd = af->fd;
730 continue;
731 }
732 /* Check some /proc file first to not stress kmod */
733 if (!family && !force && af->flag_file) {
734 if (access(af->flag_file, R_OK))
735 continue;
736 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000737 af->fd = socket(af->af, type, 0);
738 if (af->fd >= 0)
739 sfd = af->fd;
740 }
Glenn L McGrath642f2892002-11-28 10:20:45 +0000741 if (sfd < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000742 bb_error_msg(_("No usable address families found."));
Glenn L McGrath642f2892002-11-28 10:20:45 +0000743 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000744 return sfd;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000745}
746
Rob Landley93983042005-05-03 21:30:26 +0000747#ifdef CONFIG_FEATURE_CLEAN_UP
748static void sockets_close(void)
749{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000750 struct aftype * const *aft;
Rob Landley93983042005-05-03 21:30:26 +0000751 for (aft = aftypes; *aft != NULL; aft++) {
752 struct aftype *af = *aft;
753 if( af->fd != -1 ) {
754 close(af->fd);
755 af->fd = -1;
756 }
757 }
758}
759#endif
760
Eric Andersenf15d4da2001-03-06 00:48:59 +0000761/* like strcmp(), but knows about numbers */
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000762static int nstrcmp(const char *a, const char *b)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000763{
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000764 const char *a_ptr = a;
765 const char *b_ptr = b;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000766
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000767 while (*a == *b) {
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000768 if (*a == '\0') {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000769 return 0;
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000770 }
771 if (!isdigit(*a) && isdigit(*(a+1))) {
772 a_ptr = a+1;
773 b_ptr = b+1;
774 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000775 a++;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000776 b++;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000777 }
Glenn L McGrath2e99d432004-07-23 01:49:46 +0000778
779 if (isdigit(*a) && isdigit(*b)) {
780 return atoi(a_ptr) > atoi(b_ptr) ? 1 : -1;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000781 }
782 return *a - *b;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000783}
784
785static struct interface *add_interface(char *name)
786{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000787 struct interface *ife, **nextp, *new;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000788
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000789 for (ife = int_last; ife; ife = ife->prev) {
790 int n = nstrcmp(ife->name, name);
791
792 if (n == 0)
793 return ife;
794 if (n < 0)
795 break;
796 }
797 new(new);
798 safe_strncpy(new->name, name, IFNAMSIZ);
799 nextp = ife ? &ife->next : &int_list;
800 new->prev = ife;
801 new->next = *nextp;
802 if (new->next)
803 new->next->prev = new;
804 else
805 int_last = new;
806 *nextp = new;
807 return new;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000808}
809
810
811static int if_readconf(void)
812{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000813 int numreqs = 30;
814 struct ifconf ifc;
815 struct ifreq *ifr;
816 int n, err = -1;
817 int skfd2;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000818
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000819 /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
820 (as of 2.1.128) */
821 skfd2 = get_socket_for_af(AF_INET);
822 if (skfd2 < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000823 bb_perror_msg(("warning: no inet socket available"));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000824 /* Try to soldier on with whatever socket we can get hold of. */
825 skfd2 = sockets_open(0);
826 if (skfd2 < 0)
827 return -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000828 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000829
830 ifc.ifc_buf = NULL;
831 for (;;) {
832 ifc.ifc_len = sizeof(struct ifreq) * numreqs;
833 ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);
834
835 if (ioctl(skfd2, SIOCGIFCONF, &ifc) < 0) {
836 perror("SIOCGIFCONF");
837 goto out;
838 }
839 if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
840 /* assume it overflowed and try again */
841 numreqs += 10;
842 continue;
843 }
844 break;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000845 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000846
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000847 ifr = ifc.ifc_req;
848 for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
849 add_interface(ifr->ifr_name);
850 ifr++;
851 }
852 err = 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000853
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000854 out:
855 free(ifc.ifc_buf);
856 return err;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000857}
858
Eric Andersen14f5c8d2005-04-16 19:39:00 +0000859static char *get_name(char *name, char *p)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000860{
Eric Andersen9940e082004-08-12 16:52:00 +0000861 /* Extract <name>[:<alias>] from nul-terminated p where p matches
862 <name>[:<alias>]: after leading whitespace.
863 If match is not made, set name empty and return unchanged p */
864 int namestart=0, nameend=0, aliasend;
865 while (isspace(p[namestart]))
866 namestart++;
867 nameend=namestart;
868 while (p[nameend] && p[nameend]!=':' && !isspace(p[nameend]))
869 nameend++;
870 if (p[nameend]==':') {
871 aliasend=nameend+1;
872 while (p[aliasend] && isdigit(p[aliasend]))
873 aliasend++;
874 if (p[aliasend]==':') {
875 nameend=aliasend;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000876 }
Eric Andersen9940e082004-08-12 16:52:00 +0000877 if ((nameend-namestart)<IFNAMSIZ) {
878 memcpy(name,&p[namestart],nameend-namestart);
879 name[nameend-namestart]='\0';
880 p=&p[nameend];
881 } else {
882 /* Interface name too large */
883 name[0]='\0';
884 }
885 } else {
886 /* first ':' not found - return empty */
887 name[0]='\0';
Eric Andersenf15d4da2001-03-06 00:48:59 +0000888 }
Eric Andersen6fea7322004-08-26 21:45:21 +0000889 return p + 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000890}
891
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000892/* If scanf supports size qualifiers for %n conversions, then we can
893 * use a modified fmt that simply stores the position in the fields
894 * having no associated fields in the proc string. Of course, we need
895 * to zero them again when we're done. But that is smaller than the
896 * old approach of multiple scanf occurrences with large numbers of
897 * args. */
898
Bernhard Reutner-Fischera901b402006-01-19 14:51:17 +0000899/* static const char * const ss_fmt[] = { */
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000900/* "%lln%llu%lu%lu%lu%lu%ln%ln%lln%llu%lu%lu%lu%lu%lu", */
901/* "%llu%llu%lu%lu%lu%lu%ln%ln%llu%llu%lu%lu%lu%lu%lu", */
902/* "%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 +0000903/* }; */
904
905 /* Lie about the size of the int pointed to for %n. */
906#if INT_MAX == LONG_MAX
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000907static const char * const ss_fmt[] = {
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000908 "%n%llu%u%u%u%u%n%n%n%llu%u%u%u%u%u",
909 "%llu%llu%u%u%u%u%n%n%llu%llu%u%u%u%u%u",
910 "%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 +0000911};
912#else
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +0000913static const char * const ss_fmt[] = {
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +0000914 "%n%llu%lu%lu%lu%lu%n%n%n%llu%lu%lu%lu%lu%lu",
915 "%llu%llu%lu%lu%lu%lu%n%n%llu%llu%lu%lu%lu%lu%lu",
916 "%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 +0000917};
918
919#endif
920
921static void get_dev_fields(char *bp, struct interface *ife, int procnetdev_vsn)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000922{
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000923 memset(&ife->stats, 0, sizeof(struct user_net_device_stats));
924
925 sscanf(bp, ss_fmt[procnetdev_vsn],
926 &ife->stats.rx_bytes, /* missing for 0 */
927 &ife->stats.rx_packets,
928 &ife->stats.rx_errors,
929 &ife->stats.rx_dropped,
930 &ife->stats.rx_fifo_errors,
931 &ife->stats.rx_frame_errors,
932 &ife->stats.rx_compressed, /* missing for <= 1 */
933 &ife->stats.rx_multicast, /* missing for <= 1 */
934 &ife->stats.tx_bytes, /* missing for 0 */
935 &ife->stats.tx_packets,
936 &ife->stats.tx_errors,
937 &ife->stats.tx_dropped,
938 &ife->stats.tx_fifo_errors,
939 &ife->stats.collisions,
940 &ife->stats.tx_carrier_errors,
941 &ife->stats.tx_compressed /* missing for <= 1 */
942 );
943
944 if (procnetdev_vsn <= 1) {
945 if (procnetdev_vsn == 0) {
946 ife->stats.rx_bytes = 0;
947 ife->stats.tx_bytes = 0;
948 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000949 ife->stats.rx_multicast = 0;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000950 ife->stats.rx_compressed = 0;
951 ife->stats.tx_compressed = 0;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000952 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000953}
954
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000955static inline int procnetdev_version(char *buf)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000956{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000957 if (strstr(buf, "compressed"))
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000958 return 2;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000959 if (strstr(buf, "bytes"))
960 return 1;
961 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000962}
963
964static int if_readlist_proc(char *target)
965{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000966 static int proc_read;
967 FILE *fh;
968 char buf[512];
969 struct interface *ife;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000970 int err, procnetdev_vsn;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000971
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000972 if (proc_read)
973 return 0;
974 if (!target)
975 proc_read = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000976
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000977 fh = fopen(_PATH_PROCNET_DEV, "r");
978 if (!fh) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000979 bb_perror_msg(_("Warning: cannot open %s. Limited output."), _PATH_PROCNET_DEV);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000980 return if_readconf();
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000981 }
982 fgets(buf, sizeof buf, fh); /* eat line */
983 fgets(buf, sizeof buf, fh);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000984
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000985 procnetdev_vsn = procnetdev_version(buf);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000986
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000987 err = 0;
988 while (fgets(buf, sizeof buf, fh)) {
Eric Andersenf96675b2003-07-28 06:37:04 +0000989 char *s, name[128];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000990
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000991 s = get_name(name, buf);
992 ife = add_interface(name);
Manuel Novoa III b1d5b742003-08-02 00:04:18 +0000993 get_dev_fields(s, ife, procnetdev_vsn);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +0000994 ife->statistics_valid = 1;
995 if (target && !strcmp(target, name))
996 break;
997 }
998 if (ferror(fh)) {
999 perror(_PATH_PROCNET_DEV);
1000 err = -1;
1001 proc_read = 0;
1002 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001003 fclose(fh);
1004 return err;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001005}
1006
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001007static int if_readlist(void)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001008{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001009 int err = if_readlist_proc(NULL);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001010
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001011 if (!err)
1012 err = if_readconf();
1013 return err;
1014}
1015
1016static int for_all_interfaces(int (*doit) (struct interface *, void *),
1017 void *cookie)
1018{
1019 struct interface *ife;
1020
1021 if (!int_list && (if_readlist() < 0))
1022 return -1;
1023 for (ife = int_list; ife; ife = ife->next) {
1024 int err = doit(ife, cookie);
1025
1026 if (err)
1027 return err;
1028 }
1029 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001030}
1031
Eric Andersenf15d4da2001-03-06 00:48:59 +00001032/* Fetch the interface configuration from the kernel. */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001033static int if_fetch(struct interface *ife)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001034{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001035 struct ifreq ifr;
1036 int fd;
1037 char *ifname = ife->name;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001038
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001039 strcpy(ifr.ifr_name, ifname);
1040 if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
1041 return (-1);
1042 ife->flags = ifr.ifr_flags;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001043
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001044 strcpy(ifr.ifr_name, ifname);
1045 if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
1046 memset(ife->hwaddr, 0, 32);
1047 else
1048 memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001049
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001050 ife->type = ifr.ifr_hwaddr.sa_family;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001051
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001052 strcpy(ifr.ifr_name, ifname);
1053 if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0)
1054 ife->metric = 0;
1055 else
1056 ife->metric = ifr.ifr_metric;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001057
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001058 strcpy(ifr.ifr_name, ifname);
1059 if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
1060 ife->mtu = 0;
1061 else
1062 ife->mtu = ifr.ifr_mtu;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001063
1064#ifdef HAVE_HWSLIP
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001065 if (ife->type == ARPHRD_SLIP || ife->type == ARPHRD_CSLIP ||
1066 ife->type == ARPHRD_SLIP6 || ife->type == ARPHRD_CSLIP6 ||
1067 ife->type == ARPHRD_ADAPT) {
Eric Andersenf15d4da2001-03-06 00:48:59 +00001068#ifdef SIOCGOUTFILL
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001069 strcpy(ifr.ifr_name, ifname);
1070 if (ioctl(skfd, SIOCGOUTFILL, &ifr) < 0)
1071 ife->outfill = 0;
1072 else
1073 ife->outfill = (unsigned int) ifr.ifr_data;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001074#endif
1075#ifdef SIOCGKEEPALIVE
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001076 strcpy(ifr.ifr_name, ifname);
1077 if (ioctl(skfd, SIOCGKEEPALIVE, &ifr) < 0)
1078 ife->keepalive = 0;
1079 else
1080 ife->keepalive = (unsigned int) ifr.ifr_data;
1081#endif
1082 }
1083#endif
1084
Rob Landley93983042005-05-03 21:30:26 +00001085#ifdef SIOCGIFMAP
Eric Andersenf15d4da2001-03-06 00:48:59 +00001086 strcpy(ifr.ifr_name, ifname);
Rob Landley93983042005-05-03 21:30:26 +00001087 if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0)
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001088 ife->map = ifr.ifr_map;
Rob Landley93983042005-05-03 21:30:26 +00001089 else
1090#endif
1091 memset(&ife->map, 0, sizeof(struct ifmap));
Eric Andersenf15d4da2001-03-06 00:48:59 +00001092
1093#ifdef HAVE_TXQUEUELEN
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001094 strcpy(ifr.ifr_name, ifname);
1095 if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0)
1096 ife->tx_queue_len = -1; /* unknown value */
1097 else
1098 ife->tx_queue_len = ifr.ifr_qlen;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001099#else
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001100 ife->tx_queue_len = -1; /* unknown value */
Eric Andersenf15d4da2001-03-06 00:48:59 +00001101#endif
1102
1103#if HAVE_AFINET
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001104 /* IPv4 address? */
1105 fd = get_socket_for_af(AF_INET);
1106 if (fd >= 0) {
1107 strcpy(ifr.ifr_name, ifname);
1108 ifr.ifr_addr.sa_family = AF_INET;
1109 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
1110 ife->has_ip = 1;
1111 ife->addr = ifr.ifr_addr;
1112 strcpy(ifr.ifr_name, ifname);
1113 if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0)
1114 memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
1115 else
1116 ife->dstaddr = ifr.ifr_dstaddr;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001117
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001118 strcpy(ifr.ifr_name, ifname);
1119 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
1120 memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
1121 else
1122 ife->broadaddr = ifr.ifr_broadaddr;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001123
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001124 strcpy(ifr.ifr_name, ifname);
1125 if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
1126 memset(&ife->netmask, 0, sizeof(struct sockaddr));
1127 else
1128 ife->netmask = ifr.ifr_netmask;
1129 } else
1130 memset(&ife->addr, 0, sizeof(struct sockaddr));
1131 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001132#endif
1133
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001134 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001135}
1136
1137
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001138static int do_if_fetch(struct interface *ife)
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001139{
1140 if (if_fetch(ife) < 0) {
1141 char *errmsg;
1142
1143 if (errno == ENODEV) {
1144 /* Give better error message for this case. */
1145 errmsg = _("Device not found");
1146 } else {
1147 errmsg = strerror(errno);
1148 }
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +00001149 bb_error_msg(_("%s: error fetching interface information: %s"),
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001150 ife->name, errmsg);
1151 return -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001152 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001153 return 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001154}
1155
1156/* This structure defines hardware protocols and their handlers. */
1157struct hwtype {
Bernhard Reutner-Fischera901b402006-01-19 14:51:17 +00001158 const char * const name;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001159 const char *title;
1160 int type;
1161 int alen;
1162 char *(*print) (unsigned char *);
1163 int (*input) (char *, struct sockaddr *);
1164 int (*activate) (int fd);
1165 int suppress_null_addr;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001166};
1167
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +00001168static const struct hwtype unspec_hwtype = {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001169 "unspec", "UNSPEC", -1, 0,
1170 UNSPEC_print, NULL, NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +00001171};
1172
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +00001173static const struct hwtype loop_hwtype = {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001174 "loop", "Local Loopback", ARPHRD_LOOPBACK, 0,
1175 NULL, NULL, NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +00001176};
1177
1178#if HAVE_HWETHER
1179#include <net/if_arp.h>
Eric Andersenab4e19a2003-01-14 08:54:08 +00001180
Mike Frysinger3b05b802005-03-04 01:10:56 +00001181#if (__GLIBC__ >=2 && __GLIBC_MINOR >= 1) || defined(_NEWLIB_VERSION)
Eric Andersenab4e19a2003-01-14 08:54:08 +00001182#include <net/ethernet.h>
1183#else
Eric Andersenf15d4da2001-03-06 00:48:59 +00001184#include <linux/if_ether.h>
Eric Andersenab4e19a2003-01-14 08:54:08 +00001185#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +00001186
Eric Andersenf15d4da2001-03-06 00:48:59 +00001187/* Display an Ethernet address in readable format. */
1188static char *pr_ether(unsigned char *ptr)
1189{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001190 static char buff[64];
Eric Andersenf15d4da2001-03-06 00:48:59 +00001191
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001192 snprintf(buff, sizeof(buff), "%02X:%02X:%02X:%02X:%02X:%02X",
1193 (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377),
1194 (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)
1195 );
1196 return (buff);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001197}
1198
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001199#ifdef KEEP_UNUSED
Eric Andersenf15d4da2001-03-06 00:48:59 +00001200/* Input an Ethernet address and convert to binary. */
1201static int in_ether(char *bufp, struct sockaddr *sap)
1202{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001203 unsigned char *ptr;
1204 char c, *orig;
1205 int i;
1206 unsigned val;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001207
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001208 sap->sa_family = ether_hwtype.type;
1209 ptr = sap->sa_data;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001210
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001211 i = 0;
1212 orig = bufp;
1213 while ((*bufp != '\0') && (i < ETH_ALEN)) {
1214 val = 0;
1215 c = *bufp++;
1216 if (isdigit(c))
1217 val = c - '0';
1218 else if (c >= 'a' && c <= 'f')
1219 val = c - 'a' + 10;
1220 else if (c >= 'A' && c <= 'F')
1221 val = c - 'A' + 10;
1222 else {
Eric Andersenf15d4da2001-03-06 00:48:59 +00001223#ifdef DEBUG
Manuel Novoa III cad53642003-03-19 09:13:01 +00001224 bb_error_msg(_("in_ether(%s): invalid ether address!\n"), orig);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001225#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001226 errno = EINVAL;
1227 return (-1);
1228 }
1229 val <<= 4;
1230 c = *bufp;
1231 if (isdigit(c))
1232 val |= c - '0';
1233 else if (c >= 'a' && c <= 'f')
1234 val |= c - 'a' + 10;
1235 else if (c >= 'A' && c <= 'F')
1236 val |= c - 'A' + 10;
1237 else if (c == ':' || c == 0)
1238 val >>= 4;
1239 else {
1240#ifdef DEBUG
Manuel Novoa III cad53642003-03-19 09:13:01 +00001241 bb_error_msg(_("in_ether(%s): invalid ether address!"), orig);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001242#endif
1243 errno = EINVAL;
1244 return (-1);
1245 }
1246 if (c != 0)
1247 bufp++;
1248 *ptr++ = (unsigned char) (val & 0377);
1249 i++;
1250
1251 /* We might get a semicolon here - not required. */
1252 if (*bufp == ':') {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001253#ifdef DEBUG
Glenn L McGrath642f2892002-11-28 10:20:45 +00001254 if (i == ETH_ALEN) {
Manuel Novoa III cad53642003-03-19 09:13:01 +00001255 bb_error_msg(_("in_ether(%s): trailing : ignored!"), orig);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001256 }
Glenn L McGrath642f2892002-11-28 10:20:45 +00001257#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001258 bufp++;
1259 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001260 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001261
Glenn L McGrath642f2892002-11-28 10:20:45 +00001262#ifdef DEBUG
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001263 /* That's it. Any trailing junk? */
1264 if ((i == ETH_ALEN) && (*bufp != '\0')) {
Manuel Novoa III cad53642003-03-19 09:13:01 +00001265 bb_error_msg(_("in_ether(%s): trailing junk!"), orig);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001266 errno = EINVAL;
1267 return (-1);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001268 }
Manuel Novoa III cad53642003-03-19 09:13:01 +00001269 bb_error_msg("in_ether(%s): %s", orig, pr_ether(sap->sa_data));
Eric Andersenf15d4da2001-03-06 00:48:59 +00001270#endif
1271
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001272 return (0);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001273}
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001274#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +00001275
1276
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +00001277static const struct hwtype ether_hwtype = {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001278 "ether", "Ethernet", ARPHRD_ETHER, ETH_ALEN,
1279 pr_ether, NULL /* UNUSED in_ether */ , NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +00001280};
1281
1282
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001283#endif /* HAVE_HWETHER */
Eric Andersenf15d4da2001-03-06 00:48:59 +00001284
1285
1286#if HAVE_HWPPP
1287
1288#include <net/if_arp.h>
1289
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001290#ifdef KEEP_UNUSED
Eric Andersenf15d4da2001-03-06 00:48:59 +00001291/* Start the PPP encapsulation on the file descriptor. */
1292static int do_ppp(int fd)
1293{
Manuel Novoa III cad53642003-03-19 09:13:01 +00001294 bb_error_msg(_("You cannot start PPP with this program."));
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001295 return -1;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001296}
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001297#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +00001298
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +00001299static const struct hwtype ppp_hwtype = {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001300 "ppp", "Point-Point Protocol", ARPHRD_PPP, 0,
1301 NULL, NULL, NULL /* UNUSED do_ppp */ , 0
Eric Andersenf15d4da2001-03-06 00:48:59 +00001302};
1303
1304
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001305#endif /* HAVE_PPP */
Eric Andersenf15d4da2001-03-06 00:48:59 +00001306
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +00001307static const struct hwtype * const hwtypes[] = {
Eric Andersenf15d4da2001-03-06 00:48:59 +00001308
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001309 &loop_hwtype,
Eric Andersenf15d4da2001-03-06 00:48:59 +00001310
1311#if HAVE_HWSLIP
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001312 &slip_hwtype,
1313 &cslip_hwtype,
1314 &slip6_hwtype,
1315 &cslip6_hwtype,
1316 &adaptive_hwtype,
Eric Andersenf15d4da2001-03-06 00:48:59 +00001317#endif
1318#if HAVE_HWSTRIP
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001319 &strip_hwtype,
Eric Andersenf15d4da2001-03-06 00:48:59 +00001320#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +00001321#if HAVE_HWETHER
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001322 &ether_hwtype,
Eric Andersenf15d4da2001-03-06 00:48:59 +00001323#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +00001324#if HAVE_HWTUNNEL
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001325 &tunnel_hwtype,
Eric Andersenf15d4da2001-03-06 00:48:59 +00001326#endif
1327#if HAVE_HWPPP
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001328 &ppp_hwtype,
Eric Andersenf15d4da2001-03-06 00:48:59 +00001329#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001330 &unspec_hwtype,
1331 NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +00001332};
1333
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001334#ifdef KEEP_UNUSED
Eric Andersenf15d4da2001-03-06 00:48:59 +00001335static short sVhwinit = 0;
1336
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001337static void hwinit()
Eric Andersenf15d4da2001-03-06 00:48:59 +00001338{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001339 loop_hwtype.title = _("Local Loopback");
1340 unspec_hwtype.title = _("UNSPEC");
Eric Andersenf15d4da2001-03-06 00:48:59 +00001341#if HAVE_HWSLIP
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001342 slip_hwtype.title = _("Serial Line IP");
1343 cslip_hwtype.title = _("VJ Serial Line IP");
1344 slip6_hwtype.title = _("6-bit Serial Line IP");
1345 cslip6_hwtype.title = _("VJ 6-bit Serial Line IP");
1346 adaptive_hwtype.title = _("Adaptive Serial Line IP");
Eric Andersenf15d4da2001-03-06 00:48:59 +00001347#endif
1348#if HAVE_HWETHER
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001349 ether_hwtype.title = _("Ethernet");
Eric Andersenf15d4da2001-03-06 00:48:59 +00001350#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +00001351#if HAVE_HWTUNNEL
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001352 tunnel_hwtype.title = _("IPIP Tunnel");
Eric Andersenf15d4da2001-03-06 00:48:59 +00001353#endif
1354#if HAVE_HWPPP
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001355 ppp_hwtype.title = _("Point-to-Point Protocol");
Eric Andersenf15d4da2001-03-06 00:48:59 +00001356#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001357 sVhwinit = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001358}
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001359#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +00001360
1361#ifdef IFF_PORTSEL
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001362#if 0
1363static const char * const if_port_text[][4] = {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001364 /* Keep in step with <linux/netdevice.h> */
1365 {"unknown", NULL, NULL, NULL},
1366 {"10base2", "bnc", "coax", NULL},
1367 {"10baseT", "utp", "tpe", NULL},
1368 {"AUI", "thick", "db15", NULL},
1369 {"100baseT", NULL, NULL, NULL},
1370 {"100baseTX", NULL, NULL, NULL},
1371 {"100baseFX", NULL, NULL, NULL},
1372 {NULL, NULL, NULL, NULL},
Eric Andersenf15d4da2001-03-06 00:48:59 +00001373};
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001374#else
1375static const char * const if_port_text[] = {
1376 /* Keep in step with <linux/netdevice.h> */
1377 "unknown",
1378 "10base2",
1379 "10baseT",
1380 "AUI",
1381 "100baseT",
1382 "100baseTX",
1383 "100baseFX",
1384 NULL
1385};
1386#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +00001387#endif
1388
1389/* Check our hardware type table for this type. */
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +00001390static const struct hwtype *get_hwntype(int type)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001391{
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +00001392 const struct hwtype * const *hwp;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001393
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001394#ifdef KEEP_UNUSED
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001395 if (!sVhwinit)
1396 hwinit();
1397#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +00001398
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001399 hwp = hwtypes;
1400 while (*hwp != NULL) {
1401 if ((*hwp)->type == type)
1402 return (*hwp);
1403 hwp++;
1404 }
1405 return (NULL);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001406}
1407
1408/* return 1 if address is all zeros */
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +00001409static int hw_null_address(const struct hwtype *hw, void *ap)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001410{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001411 unsigned int i;
1412 unsigned char *address = (unsigned char *) ap;
1413
1414 for (i = 0; i < hw->alen; i++)
1415 if (address[i])
1416 return 0;
1417 return 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001418}
1419
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001420static const char TRext[] = "\0\0\0Ki\0Mi\0Gi\0Ti";
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001421
1422static void print_bytes_scaled(unsigned long long ull, const char *end)
1423{
1424 unsigned long long int_part;
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001425 const char *ext;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001426 unsigned int frac_part;
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001427 int i;
1428
1429 frac_part = 0;
1430 ext = TRext;
1431 int_part = ull;
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001432 i = 4;
1433 do {
1434#if 0
1435 /* This does correct rounding and is a little larger. But it
1436 * uses KiB as the smallest displayed unit. */
1437 if ((int_part < (1024*1024 - 51)) || !--i) {
1438 i = 0;
1439 int_part += 51; /* 1024*.05 = 51.2 */
1440 frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001441 }
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001442 int_part /= 1024;
1443 ext += 3; /* KiB, MiB, GiB, TiB */
1444#else
1445 if (int_part >= 1024) {
1446 frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
1447 int_part /= 1024;
1448 ext += 3; /* KiB, MiB, GiB, TiB */
1449 }
1450 --i;
1451#endif
1452 } while (i);
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001453
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001454 printf("X bytes:%llu (%llu.%u %sB)%s", ull, int_part, frac_part, ext, end);
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001455}
1456
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001457static const char * const ife_print_flags_strs[] = {
1458 "UP ",
1459 "BROADCAST ",
1460 "DEBUG ",
1461 "LOOPBACK ",
1462 "POINTOPOINT ",
1463 "NOTRAILERS ",
1464 "RUNNING ",
1465 "NOARP ",
1466 "PROMISC ",
1467 "ALLMULTI ",
1468 "SLAVE ",
1469 "MASTER ",
1470 "MULTICAST ",
1471#ifdef HAVE_DYNAMIC
1472 "DYNAMIC "
1473#endif
1474};
1475
1476static const unsigned short ife_print_flags_mask[] = {
1477 IFF_UP,
1478 IFF_BROADCAST,
1479 IFF_DEBUG,
1480 IFF_LOOPBACK,
1481 IFF_POINTOPOINT,
1482 IFF_NOTRAILERS,
1483 IFF_RUNNING,
1484 IFF_NOARP,
1485 IFF_PROMISC,
1486 IFF_ALLMULTI,
1487 IFF_SLAVE,
1488 IFF_MASTER,
1489 IFF_MULTICAST,
1490#ifdef HAVE_DYNAMIC
1491 IFF_DYNAMIC
1492#endif
1493 0
1494};
1495
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001496static void ife_print(struct interface *ptr)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001497{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001498 struct aftype *ap;
"Vladimir N. Oleynik"0fa9ded2005-10-20 09:48:28 +00001499 const struct hwtype *hw;
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001500 int hf;
1501 int can_compress = 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001502
Eric Andersenf15d4da2001-03-06 00:48:59 +00001503#if HAVE_AFINET6
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001504 FILE *f;
1505 char addr6[40], devname[20];
1506 struct sockaddr_in6 sap;
1507 int plen, scope, dad_status, if_idx;
1508 char addr6p[8][5];
Eric Andersenf15d4da2001-03-06 00:48:59 +00001509#endif
1510
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001511 ap = get_afntype(ptr->addr.sa_family);
1512 if (ap == NULL)
1513 ap = get_afntype(0);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001514
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001515 hf = ptr->type;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001516
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001517 if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
1518 can_compress = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001519
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001520 hw = get_hwntype(hf);
1521 if (hw == NULL)
1522 hw = get_hwntype(-1);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001523
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001524 printf(_("%-9.9s Link encap:%s "), ptr->name, _(hw->title));
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001525 /* For some hardware types (eg Ash, ATM) we don't print the
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001526 hardware address if it's null. */
1527 if (hw->print != NULL && (!(hw_null_address(hw, ptr->hwaddr) &&
1528 hw->suppress_null_addr)))
Eric Andersen0cb6f352006-01-30 22:30:41 +00001529 printf(_("HWaddr %s "), hw->print((unsigned char *)ptr->hwaddr));
Eric Andersenf15d4da2001-03-06 00:48:59 +00001530#ifdef IFF_PORTSEL
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001531 if (ptr->flags & IFF_PORTSEL) {
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001532 printf(_("Media:%s"), if_port_text[ptr->map.port] /* [0] */);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001533 if (ptr->flags & IFF_AUTOMEDIA)
1534 printf(_("(auto)"));
1535 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001536#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001537 printf("\n");
Eric Andersenf15d4da2001-03-06 00:48:59 +00001538
1539#if HAVE_AFINET
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001540 if (ptr->has_ip) {
1541 printf(_(" %s addr:%s "), ap->name,
1542 ap->sprint(&ptr->addr, 1));
1543 if (ptr->flags & IFF_POINTOPOINT) {
1544 printf(_(" P-t-P:%s "), ap->sprint(&ptr->dstaddr, 1));
1545 }
1546 if (ptr->flags & IFF_BROADCAST) {
1547 printf(_(" Bcast:%s "), ap->sprint(&ptr->broadaddr, 1));
1548 }
1549 printf(_(" Mask:%s\n"), ap->sprint(&ptr->netmask, 1));
Eric Andersenf15d4da2001-03-06 00:48:59 +00001550 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001551#endif
1552
1553#if HAVE_AFINET6
Eric Andersenf15d4da2001-03-06 00:48:59 +00001554
Eric Andersen51b8bd62002-07-03 11:46:38 +00001555#define IPV6_ADDR_ANY 0x0000U
1556
1557#define IPV6_ADDR_UNICAST 0x0001U
1558#define IPV6_ADDR_MULTICAST 0x0002U
1559#define IPV6_ADDR_ANYCAST 0x0004U
1560
1561#define IPV6_ADDR_LOOPBACK 0x0010U
1562#define IPV6_ADDR_LINKLOCAL 0x0020U
1563#define IPV6_ADDR_SITELOCAL 0x0040U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001564
Eric Andersen51b8bd62002-07-03 11:46:38 +00001565#define IPV6_ADDR_COMPATv4 0x0080U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001566
Eric Andersen51b8bd62002-07-03 11:46:38 +00001567#define IPV6_ADDR_SCOPE_MASK 0x00f0U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001568
Eric Andersen51b8bd62002-07-03 11:46:38 +00001569#define IPV6_ADDR_MAPPED 0x1000U
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001570#define IPV6_ADDR_RESERVED 0x2000U /* reserved address space */
1571
1572 if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
1573 while (fscanf
1574 (f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
1575 addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
1576 addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope,
1577 &dad_status, devname) != EOF) {
1578 if (!strcmp(devname, ptr->name)) {
1579 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
1580 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
1581 addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
1582 inet_pton(AF_INET6, addr6,
1583 (struct sockaddr *) &sap.sin6_addr);
1584 sap.sin6_family = AF_INET6;
1585 printf(_(" inet6 addr: %s/%d"),
1586 inet6_aftype.sprint((struct sockaddr *) &sap, 1),
1587 plen);
1588 printf(_(" Scope:"));
1589 switch (scope & IPV6_ADDR_SCOPE_MASK) {
1590 case 0:
1591 printf(_("Global"));
1592 break;
1593 case IPV6_ADDR_LINKLOCAL:
1594 printf(_("Link"));
1595 break;
1596 case IPV6_ADDR_SITELOCAL:
1597 printf(_("Site"));
1598 break;
1599 case IPV6_ADDR_COMPATv4:
1600 printf(_("Compat"));
1601 break;
1602 case IPV6_ADDR_LOOPBACK:
1603 printf(_("Host"));
1604 break;
1605 default:
1606 printf(_("Unknown"));
1607 }
1608 printf("\n");
1609 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001610 }
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001611 fclose(f);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001612 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001613#endif
1614
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001615 printf(" ");
1616 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001617
1618 if (ptr->flags == 0) {
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001619 printf(_("[NO FLAGS] "));
Manuel Novoa III b1d5b742003-08-02 00:04:18 +00001620 } else {
1621 int i = 0;
1622 do {
1623 if (ptr->flags & ife_print_flags_mask[i]) {
1624 printf(_(ife_print_flags_strs[i]));
1625 }
1626 } while (ife_print_flags_mask[++i]);
1627 }
1628
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001629 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
1630 printf(_(" MTU:%d Metric:%d"), ptr->mtu, ptr->metric ? ptr->metric : 1);
1631#ifdef SIOCSKEEPALIVE
1632 if (ptr->outfill || ptr->keepalive)
1633 printf(_(" Outfill:%d Keepalive:%d"), ptr->outfill, ptr->keepalive);
1634#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +00001635 printf("\n");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001636
1637 /* If needed, display the interface statistics. */
1638
1639 if (ptr->statistics_valid) {
1640 /* XXX: statistics are currently only printed for the primary address,
1641 * not for the aliases, although strictly speaking they're shared
1642 * by all addresses.
1643 */
1644 printf(" ");
1645
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001646 printf("RX packets:%llu errors:%lu dropped:%lu overruns:%lu frame:%lu\n",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001647 ptr->stats.rx_packets, ptr->stats.rx_errors,
1648 ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors,
1649 ptr->stats.rx_frame_errors);
1650 if (can_compress)
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001651 printf(" compressed:%lu\n",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001652 ptr->stats.rx_compressed);
1653 printf(" ");
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001654 printf("TX packets:%llu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n",
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001655 ptr->stats.tx_packets, ptr->stats.tx_errors,
1656 ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
1657 ptr->stats.tx_carrier_errors);
Bernhard Reutner-Fischer214744d2006-03-30 13:38:19 +00001658 printf(" collisions:%lu ", ptr->stats.collisions);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001659 if (can_compress)
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001660 printf("compressed:%lu ", ptr->stats.tx_compressed);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001661 if (ptr->tx_queue_len != -1)
Bernhard Reutner-Fischerd409c3a2006-03-29 22:34:47 +00001662 printf("txqueuelen:%d ", ptr->tx_queue_len);
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001663 printf("\n R");
1664 print_bytes_scaled(ptr->stats.rx_bytes, " T");
1665 print_bytes_scaled(ptr->stats.tx_bytes, "\n");
1666
1667 }
1668
1669 if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
1670 ptr->map.base_addr)) {
1671 printf(" ");
1672 if (ptr->map.irq)
1673 printf(_("Interrupt:%d "), ptr->map.irq);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001674 if (ptr->map.base_addr >= 0x100) /* Only print devices using it for
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001675 I/O maps */
1676 printf(_("Base address:0x%lx "),
1677 (unsigned long) ptr->map.base_addr);
1678 if (ptr->map.mem_start) {
1679 printf(_("Memory:%lx-%lx "), ptr->map.mem_start,
1680 ptr->map.mem_end);
1681 }
1682 if (ptr->map.dma)
1683 printf(_("DMA chan:%x "), ptr->map.dma);
1684 printf("\n");
1685 }
1686 printf("\n");
Eric Andersenf15d4da2001-03-06 00:48:59 +00001687}
1688
1689
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001690static int do_if_print(struct interface *ife, void *cookie)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001691{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001692 int *opt_a = (int *) cookie;
1693 int res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001694
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001695 res = do_if_fetch(ife);
1696 if (res >= 0) {
1697 if ((ife->flags & IFF_UP) || *opt_a)
1698 ife_print(ife);
1699 }
1700 return res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001701}
1702
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001703static struct interface *lookup_interface(char *name)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001704{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001705 struct interface *ife = NULL;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001706
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001707 if (if_readlist_proc(name) < 0)
1708 return NULL;
1709 ife = add_interface(name);
1710 return ife;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001711}
1712
1713/* for ipv4 add/del modes */
1714static int if_print(char *ifname)
1715{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001716 int res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001717
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001718 if (!ifname) {
1719 res = for_all_interfaces(do_if_print, &interface_opt_a);
1720 } else {
1721 struct interface *ife;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001722
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001723 ife = lookup_interface(ifname);
1724 res = do_if_fetch(ife);
1725 if (res >= 0)
1726 ife_print(ife);
1727 }
1728 return res;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001729}
1730
Mike Frysingerb5547fb2006-05-11 02:35:55 +00001731int display_interfaces(char *ifname);
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001732int display_interfaces(char *ifname)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001733{
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001734 int status;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001735
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001736 /* Create a channel to the NET kernel. */
1737 if ((skfd = sockets_open(0)) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +00001738 bb_perror_msg_and_die("socket");
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001739 }
Eric Andersenf15d4da2001-03-06 00:48:59 +00001740
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001741 /* Do we have to show the current setup? */
1742 status = if_print(ifname);
Rob Landley93983042005-05-03 21:30:26 +00001743#ifdef CONFIG_FEATURE_CLEAN_UP
1744 sockets_close();
1745#endif
Glenn L McGrath1ed9dd92002-08-22 19:35:36 +00001746 exit(status < 0);
Eric Andersenf15d4da2001-03-06 00:48:59 +00001747}