blob: 484597c5f34131a825e703f019b20591bbb69186 [file] [log] [blame]
Eric Andersenf15d4da2001-03-06 00:48:59 +00001/*
2 * ifconfig This file contains an implementation of the command
3 * that either displays or sets the characteristics of
4 * one or more of the system's networking interfaces.
5 *
Eric Andersen20aab262001-07-19 22:28:02 +00006 * Version: $Id: interface.c,v 1.4 2001/07/19 22:28:02 andersen Exp $
Eric Andersenf15d4da2001-03-06 00:48:59 +00007 *
8 * Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
9 * and others. Copyright 1993 MicroWalt Corporation
10 *
11 * This program is free software; you can redistribute it
12 * and/or modify it under the terms of the GNU General
13 * Public License as published by the Free Software
14 * Foundation; either version 2 of the License, or (at
15 * your option) any later version.
16 *
17 * Patched to support 'add' and 'del' keywords for INET(4) addresses
18 * by Mrs. Brisby <mrs.brisby@nimh.org>
19 *
20 * {1.34} - 19980630 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
21 * - gettext instead of catgets for i18n
22 * 10/1998 - Andi Kleen. Use interface list primitives.
23 * 20001008 - Bernd Eckenfels, Patch from RH for setting mtu
24 * (default AF was wrong)
25 * stolen from net-tools-1.59 and stripped down for busybox by
26 * Erik Andersen <andersee@debian.org>
27 */
28
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +000029/*
30 * Heavily modified by Manuel Novoa III Mar 12, 2001
31 *
32 * Pruned unused code using KEEP_UNUSED define.
33 * Added print_bytes_scaled function to reduce code size.
34 * Added some (potentially) missing defines.
35 * Improved display support for -a and for a named interface.
36 */
37
38/* #define KEEP_UNUSED */
39
Eric Andersenf15d4da2001-03-06 00:48:59 +000040/*
41 *
42 * Protocol Families.
43 *
44 */
45#define HAVE_AFINET 1
46#undef HAVE_AFINET6
47#undef HAVE_AFIPX
48#undef HAVE_AFATALK
49#undef HAVE_AFNETROM
50#undef HAVE_AFX25
51#undef HAVE_AFECONET
Eric Andersen8b113f92001-06-01 21:47:15 +000052#undef HAVE_AFASH
Eric Andersenf15d4da2001-03-06 00:48:59 +000053
54/*
55 *
56 * Device Hardware types.
57 *
58 */
59#define HAVE_HWETHER 1
60#define HAVE_HWPPP 1
61#undef HAVE_HWSLIP
62
63
64#include <features.h>
65#include <sys/types.h>
66#include <sys/socket.h>
67#include <sys/ioctl.h>
68#include <netinet/in.h>
69#include <net/if.h>
70#include <net/if_arp.h>
71#include <stdio.h>
72#include <errno.h>
73#include <fcntl.h>
74#include <ctype.h>
75#include <stdlib.h>
76#include <string.h>
77#include <unistd.h>
78#include <netdb.h>
79#include <netinet/in.h>
80#include <arpa/inet.h>
Eric Andersen20aab262001-07-19 22:28:02 +000081#if 0
Eric Andersenf15d4da2001-03-06 00:48:59 +000082#include <arpa/nameser.h>
Eric Andersen20aab262001-07-19 22:28:02 +000083#endif
Glenn L McGrath6b8c5502001-05-05 03:19:12 +000084#include "libbb.h"
Eric Andersenf15d4da2001-03-06 00:48:59 +000085
86#define _(x) x
87#define _PATH_PROCNET_DEV "/proc/net/dev"
88#define new(p) ((p) = xcalloc(1,sizeof(*(p))))
Eric Andersen8b113f92001-06-01 21:47:15 +000089#define KRELEASE(maj,min,patch) ((maj) * 65536 + (min)*256 + (patch))
Eric Andersenf15d4da2001-03-06 00:48:59 +000090
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +000091static int procnetdev_vsn = 1;
Eric Andersenf15d4da2001-03-06 00:48:59 +000092
93
94/* Ugh. But libc5 doesn't provide POSIX types. */
95#include <asm/types.h>
96
97
98#ifdef HAVE_HWSLIP
99#include <linux/if_slip.h>
100#endif
101
102#if HAVE_AFINET6
103
104#ifndef _LINUX_IN6_H
105/*
106 * This is in linux/include/net/ipv6.h.
107 */
108
109struct in6_ifreq {
110 struct in6_addr ifr6_addr;
111 __u32 ifr6_prefixlen;
112 unsigned int ifr6_ifindex;
113};
114
115#endif
116
117#endif /* HAVE_AFINET6 */
118
119#if HAVE_AFIPX
Eric Andersenb6b519b2001-04-09 23:52:18 +0000120#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000121#include <netipx/ipx.h>
122#else
123#include "ipx.h"
124#endif
125#endif
126#if 0
127#include "net-support.h"
128#include "pathnames.h"
129#include "version.h"
130#include "../intl.h"
131#include "interface.h"
132#include "sockets.h"
133#include "util.h"
134#endif
135
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000136/* Defines for glibc2.0 users. */
137#ifndef SIOCSIFTXQLEN
138#define SIOCSIFTXQLEN 0x8943
139#define SIOCGIFTXQLEN 0x8942
140#endif
141
142/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
143#ifndef ifr_qlen
144#define ifr_qlen ifr_ifru.ifru_mtu
145#endif
146
147#ifndef HAVE_TXQUEUELEN
148#define HAVE_TXQUEUELEN 1
149#endif
150
151#ifndef IFF_DYNAMIC
152#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */
153#endif
154
Eric Andersenf15d4da2001-03-06 00:48:59 +0000155/* This structure defines protocol families and their handlers. */
156struct aftype {
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000157 const char *name;
158 const char *title;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000159 int af;
160 int alen;
161 char *(*print) (unsigned char *);
162 char *(*sprint) (struct sockaddr *, int numeric);
163 int (*input) (int type, char *bufp, struct sockaddr *);
164 void (*herror) (char *text);
165 int (*rprint) (int options);
166 int (*rinput) (int typ, int ext, char **argv);
167
168 /* may modify src */
169 int (*getmask) (char *src, struct sockaddr * mask, char *name);
170
171 int fd;
172 char *flag_file;
173};
174
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000175static struct aftype *aftypes[];
176
177#ifdef KEEP_UNUSED
178
179static int flag_unx;
Eric Andersen8b113f92001-06-01 21:47:15 +0000180#ifdef HAVE_AFIPX
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000181static int flag_ipx;
Eric Andersen8b113f92001-06-01 21:47:15 +0000182#endif
183#ifdef HAVE_AFX25
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000184static int flag_ax25;
Eric Andersen8b113f92001-06-01 21:47:15 +0000185#endif
186#ifdef HAVE_AFATALK
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000187static int flag_ddp;
Eric Andersen8b113f92001-06-01 21:47:15 +0000188#endif
189#ifdef HAVE_AFNETROM
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000190static int flag_netrom;
Eric Andersen8b113f92001-06-01 21:47:15 +0000191#endif
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000192static int flag_inet;
Eric Andersen8b113f92001-06-01 21:47:15 +0000193#ifdef HAVE_AFINET6
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000194static int flag_inet6;
Eric Andersen8b113f92001-06-01 21:47:15 +0000195#endif
196#ifdef HAVE_AFECONET
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000197static int flag_econet;
Eric Andersen8b113f92001-06-01 21:47:15 +0000198#endif
199#ifdef HAVE_AFX25
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000200static int flag_x25 = 0;
Eric Andersen8b113f92001-06-01 21:47:15 +0000201#endif
202#ifdef HAVE_AFASH
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000203static int flag_ash;
Eric Andersen8b113f92001-06-01 21:47:15 +0000204#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +0000205
206
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000207static struct aftrans_t {
Eric Andersenf15d4da2001-03-06 00:48:59 +0000208 char *alias;
209 char *name;
210 int *flag;
211} aftrans[] = {
212
Eric Andersen8b113f92001-06-01 21:47:15 +0000213#ifdef HAVE_AFX25
Eric Andersenf15d4da2001-03-06 00:48:59 +0000214 {
215 "ax25", "ax25", &flag_ax25
216 },
Eric Andersen8b113f92001-06-01 21:47:15 +0000217#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +0000218 {
219 "ip", "inet", &flag_inet
220 },
Eric Andersen8b113f92001-06-01 21:47:15 +0000221#ifdef HAVE_AFINET6
Eric Andersenf15d4da2001-03-06 00:48:59 +0000222 {
223 "ip6", "inet6", &flag_inet6
224 },
Eric Andersen8b113f92001-06-01 21:47:15 +0000225#endif
226#ifdef HAVE_AFIPX
Eric Andersenf15d4da2001-03-06 00:48:59 +0000227 {
228 "ipx", "ipx", &flag_ipx
229 },
Eric Andersen8b113f92001-06-01 21:47:15 +0000230#endif
231#ifdef HAVE_AFATALK
Eric Andersenf15d4da2001-03-06 00:48:59 +0000232 {
233 "appletalk", "ddp", &flag_ddp
234 },
Eric Andersen8b113f92001-06-01 21:47:15 +0000235#endif
236#ifdef HAVE_AFNETROM
Eric Andersenf15d4da2001-03-06 00:48:59 +0000237 {
238 "netrom", "netrom", &flag_netrom
239 },
Eric Andersen8b113f92001-06-01 21:47:15 +0000240#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +0000241 {
242 "inet", "inet", &flag_inet
243 },
Eric Andersen8b113f92001-06-01 21:47:15 +0000244#ifdef HAVE_AFINET6
Eric Andersenf15d4da2001-03-06 00:48:59 +0000245 {
246 "inet6", "inet6", &flag_inet6
247 },
Eric Andersen8b113f92001-06-01 21:47:15 +0000248#endif
249#ifdef HAVE_AFATALK
Eric Andersenf15d4da2001-03-06 00:48:59 +0000250 {
251 "ddp", "ddp", &flag_ddp
252 },
Eric Andersen8b113f92001-06-01 21:47:15 +0000253#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +0000254 {
255 "unix", "unix", &flag_unx
256 },
257 {
258 "tcpip", "inet", &flag_inet
259 },
Eric Andersen8b113f92001-06-01 21:47:15 +0000260#ifdef HAVE_AFECONET
Eric Andersenf15d4da2001-03-06 00:48:59 +0000261 {
262 "econet", "ec", &flag_econet
263 },
Eric Andersen8b113f92001-06-01 21:47:15 +0000264#endif
265#ifdef HAVE_AFX25
Eric Andersenf15d4da2001-03-06 00:48:59 +0000266 {
267 "x25", "x25", &flag_x25
268 },
Eric Andersen8b113f92001-06-01 21:47:15 +0000269#endif
270#ifdef HAVE_AFASH
Eric Andersenf15d4da2001-03-06 00:48:59 +0000271 {
272 "ash", "ash", &flag_ash
273 },
Eric Andersen8b113f92001-06-01 21:47:15 +0000274#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +0000275 {
276 0, 0, 0
277 }
278};
279
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000280static char afname[256] = "";
281#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000282
283#if HAVE_AFUNIX
284
285/* Display a UNIX domain address. */
286static char *UNIX_print(unsigned char *ptr)
287{
288 return (ptr);
289}
290
291
292/* Display a UNIX domain address. */
293static char *UNIX_sprint(struct sockaddr *sap, int numeric)
294{
295 static char buf[64];
296
297 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
298 return safe_strncpy(buf, _("[NONE SET]"), sizeof(buf));
299 return (UNIX_print(sap->sa_data));
300}
301
302
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000303static struct aftype unix_aftype =
Eric Andersenf15d4da2001-03-06 00:48:59 +0000304{
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000305 "unix", "UNIX Domain", AF_UNIX, 0,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000306 UNIX_print, UNIX_sprint, NULL, NULL,
307 NULL, NULL, NULL,
308 -1,
309 "/proc/net/unix"
310};
311#endif /* HAVE_AFUNIX */
312
313#if HAVE_AFINET
314
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000315#if 0
Eric Andersenf15d4da2001-03-06 00:48:59 +0000316extern int h_errno; /* some netdb.h versions don't export this */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000317#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +0000318
319/* cache */
320struct addr {
321 struct sockaddr_in addr;
322 char *name;
323 int host;
324 struct addr *next;
325};
326
327static struct addr *INET_nn = NULL; /* addr-to-name cache */
328
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000329#ifdef KEEP_UNUSED
Eric Andersenf15d4da2001-03-06 00:48:59 +0000330static int INET_resolve(char *name, struct sockaddr_in *sin, int hostfirst)
331{
332 struct hostent *hp;
333 struct netent *np;
334
335 /* Grmpf. -FvK */
336 sin->sin_family = AF_INET;
337 sin->sin_port = 0;
338
339 /* Default is special, meaning 0.0.0.0. */
340 if (!strcmp(name, "default")) {
341 sin->sin_addr.s_addr = INADDR_ANY;
342 return (1);
343 }
344 /* Look to see if it's a dotted quad. */
345 if (inet_aton(name, &sin->sin_addr)) {
346 return 0;
347 }
348 /* If we expect this to be a hostname, try hostname database first */
349#ifdef DEBUG
350 if (hostfirst) fprintf (stderr, "gethostbyname (%s)\n", name);
351#endif
352 if (hostfirst &&
353 (hp = gethostbyname(name)) != (struct hostent *) NULL) {
354 memcpy((char *) &sin->sin_addr, (char *) hp->h_addr_list[0],
355 sizeof(struct in_addr));
356 return 0;
357 }
358 /* Try the NETWORKS database to see if this is a known network. */
359#ifdef DEBUG
360 fprintf (stderr, "getnetbyname (%s)\n", name);
361#endif
362 if ((np = getnetbyname(name)) != (struct netent *) NULL) {
363 sin->sin_addr.s_addr = htonl(np->n_net);
364 return 1;
365 }
366 if (hostfirst) {
367 /* Don't try again */
368 errno = h_errno;
369 return -1;
370 }
371#ifdef DEBUG
372 res_init();
373 _res.options |= RES_DEBUG;
374#endif
375
376#ifdef DEBUG
377 fprintf (stderr, "gethostbyname (%s)\n", name);
378#endif
379 if ((hp = gethostbyname(name)) == (struct hostent *) NULL) {
380 errno = h_errno;
381 return -1;
382 }
383 memcpy((char *) &sin->sin_addr, (char *) hp->h_addr_list[0],
384 sizeof(struct in_addr));
385
386 return 0;
387}
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000388#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000389
390/* numeric: & 0x8000: default instead of *,
391 * & 0x4000: host instead of net,
392 * & 0x0fff: don't resolve
393 */
Eric Andersen46cd74b2001-04-19 16:55:27 +0000394static int INET_rresolve(char *name, size_t len, struct sockaddr_in *s_in,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000395 int numeric, unsigned int netmask)
396{
397 struct hostent *ent;
398 struct netent *np;
399 struct addr *pn;
400 unsigned long ad, host_ad;
401 int host = 0;
402
403 /* Grmpf. -FvK */
Eric Andersen46cd74b2001-04-19 16:55:27 +0000404 if (s_in->sin_family != AF_INET) {
Eric Andersenf15d4da2001-03-06 00:48:59 +0000405#ifdef DEBUG
Eric Andersen46cd74b2001-04-19 16:55:27 +0000406 fprintf(stderr, _("rresolve: unsupport address family %d !\n"), s_in->sin_family);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000407#endif
408 errno = EAFNOSUPPORT;
409 return (-1);
410 }
Eric Andersen46cd74b2001-04-19 16:55:27 +0000411 ad = (unsigned long) s_in->sin_addr.s_addr;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000412#ifdef DEBUG
413 fprintf (stderr, "rresolve: %08lx, mask %08x, num %08x \n", ad, netmask, numeric);
414#endif
415 if (ad == INADDR_ANY) {
416 if ((numeric & 0x0FFF) == 0) {
417 if (numeric & 0x8000)
418 safe_strncpy(name, "default", len);
419 else
420 safe_strncpy(name, "*", len);
421 return (0);
422 }
423 }
424 if (numeric & 0x0FFF) {
Eric Andersen46cd74b2001-04-19 16:55:27 +0000425 safe_strncpy(name, inet_ntoa(s_in->sin_addr), len);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000426 return (0);
427 }
428
429 if ((ad & (~netmask)) != 0 || (numeric & 0x4000))
430 host = 1;
431#if 0
432 INET_nn = NULL;
433#endif
434 pn = INET_nn;
435 while (pn != NULL) {
436 if (pn->addr.sin_addr.s_addr == ad && pn->host == host) {
437 safe_strncpy(name, pn->name, len);
438#ifdef DEBUG
439 fprintf (stderr, "rresolve: found %s %08lx in cache\n", (host? "host": "net"), ad);
440#endif
441 return (0);
442 }
443 pn = pn->next;
444 }
445
446 host_ad = ntohl(ad);
447 np = NULL;
448 ent = NULL;
449 if (host) {
450#ifdef DEBUG
451 fprintf (stderr, "gethostbyaddr (%08lx)\n", ad);
452#endif
453 ent = gethostbyaddr((char *) &ad, 4, AF_INET);
454 if (ent != NULL)
455 safe_strncpy(name, ent->h_name, len);
456 } else {
457#ifdef DEBUG
458 fprintf (stderr, "getnetbyaddr (%08lx)\n", host_ad);
459#endif
Eric Andersen20aab262001-07-19 22:28:02 +0000460#if 0
Eric Andersenf15d4da2001-03-06 00:48:59 +0000461 np = getnetbyaddr(host_ad, AF_INET);
462 if (np != NULL)
463 safe_strncpy(name, np->n_name, len);
Eric Andersen20aab262001-07-19 22:28:02 +0000464#endif
Eric Andersenf15d4da2001-03-06 00:48:59 +0000465 }
466 if ((ent == NULL) && (np == NULL))
Eric Andersen46cd74b2001-04-19 16:55:27 +0000467 safe_strncpy(name, inet_ntoa(s_in->sin_addr), len);
Eric Andersen0f430e32001-03-06 20:54:43 +0000468 pn = (struct addr *) xmalloc(sizeof(struct addr));
Eric Andersen46cd74b2001-04-19 16:55:27 +0000469 pn->addr = *s_in;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000470 pn->next = INET_nn;
471 pn->host = host;
Eric Andersen0f430e32001-03-06 20:54:43 +0000472 pn->name = (char *) xmalloc(strlen(name) + 1);
Eric Andersenf15d4da2001-03-06 00:48:59 +0000473 strcpy(pn->name, name);
474 INET_nn = pn;
475
476 return (0);
477}
478
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000479#ifdef KEEP_UNUSED
Eric Andersenf15d4da2001-03-06 00:48:59 +0000480static void INET_reserror(char *text)
481{
482 herror(text);
483}
484
Eric Andersenf15d4da2001-03-06 00:48:59 +0000485/* Display an Internet socket address. */
486static char *INET_print(unsigned char *ptr)
487{
488 return (inet_ntoa((*(struct in_addr *) ptr)));
489}
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000490#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000491
492/* Display an Internet socket address. */
493static char *INET_sprint(struct sockaddr *sap, int numeric)
494{
495 static char buff[128];
496
497 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
498 return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff));
499
500 if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap,
501 numeric, 0xffffff00) != 0)
502 return (NULL);
503
504 return (buff);
505}
506
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000507#ifdef KEEP_UNUSED
508static char *INET_sprintmask(struct sockaddr *sap, int numeric,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000509 unsigned int netmask)
510{
511 static char buff[128];
512
513 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
514 return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff));
515 if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap,
516 numeric, netmask) != 0)
517 return (NULL);
518 return (buff);
519}
520
Eric Andersenf15d4da2001-03-06 00:48:59 +0000521static int INET_getsock(char *bufp, struct sockaddr *sap)
522{
523 char *sp = bufp, *bp;
524 unsigned int i;
525 unsigned val;
526 struct sockaddr_in *sin;
527
528 sin = (struct sockaddr_in *) sap;
529 sin->sin_family = AF_INET;
530 sin->sin_port = 0;
531
532 val = 0;
533 bp = (char *) &val;
534 for (i = 0; i < sizeof(sin->sin_addr.s_addr); i++) {
535 *sp = toupper(*sp);
536
537 if ((*sp >= 'A') && (*sp <= 'F'))
538 bp[i] |= (int) (*sp - 'A') + 10;
539 else if ((*sp >= '0') && (*sp <= '9'))
540 bp[i] |= (int) (*sp - '0');
541 else
542 return (-1);
543
544 bp[i] <<= 4;
545 sp++;
546 *sp = toupper(*sp);
547
548 if ((*sp >= 'A') && (*sp <= 'F'))
549 bp[i] |= (int) (*sp - 'A') + 10;
550 else if ((*sp >= '0') && (*sp <= '9'))
551 bp[i] |= (int) (*sp - '0');
552 else
553 return (-1);
554
555 sp++;
556 }
557 sin->sin_addr.s_addr = htonl(val);
558
559 return (sp - bufp);
560}
561
562static int INET_input(int type, char *bufp, struct sockaddr *sap)
563{
564 switch (type) {
565 case 1:
566 return (INET_getsock(bufp, sap));
567 case 256:
568 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 1));
569 default:
570 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0));
571 }
572}
573
574static int INET_getnetmask(char *adr, struct sockaddr *m, char *name)
575{
576 struct sockaddr_in *mask = (struct sockaddr_in *) m;
577 char *slash, *end;
578 int prefix;
579
580 if ((slash = strchr(adr, '/')) == NULL)
581 return 0;
582
583 *slash++ = '\0';
584 prefix = strtoul(slash, &end, 0);
585 if (*end != '\0')
586 return -1;
587
588 if (name) {
589 sprintf(name, "/%d", prefix);
590 }
591 mask->sin_family = AF_INET;
592 mask->sin_addr.s_addr = htonl(~(0xffffffffU >> prefix));
593 return 1;
594}
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000595#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000596
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000597static struct aftype inet_aftype =
Eric Andersenf15d4da2001-03-06 00:48:59 +0000598{
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000599 "inet", "DARPA Internet", AF_INET, sizeof(unsigned long),
600 NULL /* UNUSED INET_print */, INET_sprint,
601 NULL /* UNUSED INET_input */, NULL /* UNUSED INET_reserror */,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000602 NULL /*INET_rprint */ , NULL /*INET_rinput */ ,
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000603 NULL /* UNUSED INET_getnetmask */,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000604 -1,
605 NULL
606};
607
608#endif /* HAVE_AFINET */
609
610/* Display an UNSPEC address. */
611static char *UNSPEC_print(unsigned char *ptr)
612{
Eric Andersen46cd74b2001-04-19 16:55:27 +0000613 static char buff[sizeof(struct sockaddr)*3+1];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000614 char *pos;
615 unsigned int i;
616
617 pos = buff;
618 for (i = 0; i < sizeof(struct sockaddr); i++) {
Eric Andersen46cd74b2001-04-19 16:55:27 +0000619 /* careful -- not every libc's sprintf returns # bytes written */
620 sprintf(pos, "%02X-", (*ptr++ & 0377));
621 pos += 3;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000622 }
Eric Andersen46cd74b2001-04-19 16:55:27 +0000623 /* Erase trailing "-". Works as long as sizeof(struct sockaddr) != 0 */
624 *--pos = '\0';
Eric Andersenf15d4da2001-03-06 00:48:59 +0000625 return (buff);
626}
627
628/* Display an UNSPEC socket address. */
629static char *UNSPEC_sprint(struct sockaddr *sap, int numeric)
630{
631 static char buf[64];
632
633 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
634 return safe_strncpy(buf, _("[NONE SET]"), sizeof(buf));
635 return (UNSPEC_print(sap->sa_data));
636}
637
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000638static struct aftype unspec_aftype =
Eric Andersenf15d4da2001-03-06 00:48:59 +0000639{
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000640 "unspec", "UNSPEC", AF_UNSPEC, 0,
Eric Andersenf15d4da2001-03-06 00:48:59 +0000641 UNSPEC_print, UNSPEC_sprint, NULL, NULL,
642 NULL,
643};
644
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000645static struct aftype *aftypes[] =
Eric Andersenf15d4da2001-03-06 00:48:59 +0000646{
647#if HAVE_AFUNIX
648 &unix_aftype,
649#endif
650#if HAVE_AFINET
651 &inet_aftype,
652#endif
653#if HAVE_AFINET6
654 &inet6_aftype,
655#endif
656#if HAVE_AFAX25
657 &ax25_aftype,
658#endif
659#if HAVE_AFNETROM
660 &netrom_aftype,
661#endif
662#if HAVE_AFROSE
663 &rose_aftype,
664#endif
665#if HAVE_AFIPX
666 &ipx_aftype,
667#endif
668#if HAVE_AFATALK
669 &ddp_aftype,
670#endif
671#if HAVE_AFECONET
672 &ec_aftype,
673#endif
674#if HAVE_AFASH
675 &ash_aftype,
676#endif
677#if HAVE_AFX25
678 &x25_aftype,
679#endif
680 &unspec_aftype,
681 NULL
682};
683
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000684#ifdef KEEP_UNUSED
685static short sVafinit = 0;
686
687static void afinit()
Eric Andersenf15d4da2001-03-06 00:48:59 +0000688{
689 unspec_aftype.title = _("UNSPEC");
690#if HAVE_AFUNIX
691 unix_aftype.title = _("UNIX Domain");
692#endif
693#if HAVE_AFINET
694 inet_aftype.title = _("DARPA Internet");
695#endif
696#if HAVE_AFINET6
697 inet6_aftype.title = _("IPv6");
698#endif
699#if HAVE_AFAX25
700 ax25_aftype.title = _("AMPR AX.25");
701#endif
702#if HAVE_AFNETROM
703 netrom_aftype.title = _("AMPR NET/ROM");
704#endif
705#if HAVE_AFIPX
706 ipx_aftype.title = _("Novell IPX");
707#endif
708#if HAVE_AFATALK
709 ddp_aftype.title = _("Appletalk DDP");
710#endif
711#if HAVE_AFECONET
712 ec_aftype.title = _("Econet");
713#endif
714#if HAVE_AFX25
715 x25_aftype.title = _("CCITT X.25");
716#endif
717#if HAVE_AFROSE
718 rose_aftype.title = _("AMPR ROSE");
719#endif
720#if HAVE_AFASH
721 ash_aftype.title = _("Ash");
722#endif
723 sVafinit = 1;
724}
725
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000726static int aftrans_opt(const char *arg)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000727{
728 struct aftrans_t *paft;
729 char *tmp1, *tmp2;
730 char buf[256];
731
732 safe_strncpy(buf, arg, sizeof(buf));
733
734 tmp1 = buf;
735
736 while (tmp1) {
737
Eric Andersen8b113f92001-06-01 21:47:15 +0000738 tmp2 = strchr(tmp1, ',');
Eric Andersenf15d4da2001-03-06 00:48:59 +0000739
740 if (tmp2)
741 *(tmp2++) = '\0';
742
743 paft = aftrans;
744 for (paft = aftrans; paft->alias; paft++) {
745 if (strcmp(tmp1, paft->alias))
746 continue;
747 if (strlen(paft->name) + strlen(afname) + 1 >= sizeof(afname)) {
748 fprintf(stderr, _("Too much address family arguments.\n"));
749 return (0);
750 }
751 if (paft->flag)
752 (*paft->flag)++;
753 if (afname[0])
754 strcat(afname, ",");
755 strcat(afname, paft->name);
756 break;
757 }
758 if (!paft->alias) {
759 fprintf(stderr, _("Unknown address family `%s'.\n"), tmp1);
760 return (1);
761 }
762 tmp1 = tmp2;
763 }
764
765 return (0);
766}
767
768/* set the default AF list from the program name or a constant value */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000769static void aftrans_def(char *tool, char *argv0, char *dflt)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000770{
771 char *tmp;
772 char *buf;
773
774 strcpy(afname, dflt);
775
776 if (!(tmp = strrchr(argv0, '/')))
777 tmp = argv0; /* no slash?! */
778 else
779 tmp++;
780
781 if (!(buf = strdup(tmp)))
782 return;
783
784 if (strlen(tool) >= strlen(tmp)) {
785 free(buf);
786 return;
787 }
788 tmp = buf + (strlen(tmp) - strlen(tool));
789
790 if (strcmp(tmp, tool) != 0) {
791 free(buf);
792 return;
793 }
794 *tmp = '\0';
795 if ((tmp = strchr(buf, '_')))
796 *tmp = '\0';
797
798 afname[0] = '\0';
799 if (aftrans_opt(buf))
800 strcpy(afname, buf);
801
802 free(buf);
803}
804
Eric Andersenf15d4da2001-03-06 00:48:59 +0000805/* Check our protocol family table for this family. */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000806static struct aftype *get_aftype(const char *name)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000807{
808 struct aftype **afp;
809
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000810#ifdef KEEP_UNUSED
Eric Andersenf15d4da2001-03-06 00:48:59 +0000811 if (!sVafinit)
812 afinit();
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000813#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000814
815 afp = aftypes;
816 while (*afp != NULL) {
817 if (!strcmp((*afp)->name, name))
818 return (*afp);
819 afp++;
820 }
Eric Andersen8b113f92001-06-01 21:47:15 +0000821 if (strchr(name, ','))
Eric Andersenf15d4da2001-03-06 00:48:59 +0000822 fprintf(stderr, _("Please don't supply more than one address family.\n"));
823 return (NULL);
824}
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000825#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000826
827/* Check our protocol family table for this family. */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000828static struct aftype *get_afntype(int af)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000829{
830 struct aftype **afp;
831
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000832#ifdef KEEP_UNUSED
Eric Andersenf15d4da2001-03-06 00:48:59 +0000833 if (!sVafinit)
834 afinit();
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000835#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000836
837 afp = aftypes;
838 while (*afp != NULL) {
839 if ((*afp)->af == af)
840 return (*afp);
841 afp++;
842 }
843 return (NULL);
844}
845
846/* Check our protocol family table for this family and return its socket */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000847static int get_socket_for_af(int af)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000848{
849 struct aftype **afp;
850
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000851#ifdef KEEP_UNUSED
Eric Andersenf15d4da2001-03-06 00:48:59 +0000852 if (!sVafinit)
853 afinit();
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000854#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000855
856 afp = aftypes;
857 while (*afp != NULL) {
858 if ((*afp)->af == af)
859 return (*afp)->fd;
860 afp++;
861 }
862 return -1;
863}
864
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000865#ifdef KEEP_UNUSED
Eric Andersenf15d4da2001-03-06 00:48:59 +0000866/* type: 0=all, 1=getroute */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000867static void print_aflist(int type) {
Eric Andersenf15d4da2001-03-06 00:48:59 +0000868 int count = 0;
869 char * txt;
870 struct aftype **afp;
871
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000872#ifdef KEEP_UNUSED
Eric Andersenf15d4da2001-03-06 00:48:59 +0000873 if (!sVafinit)
874 afinit();
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000875#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000876
877 afp = aftypes;
878 while (*afp != NULL) {
879 if ((type == 1 && ((*afp)->rprint == NULL)) || ((*afp)->af == 0)) {
880 afp++; continue;
881 }
882 if ((count % 3) == 0) fprintf(stderr,count?"\n ":" ");
883 txt = (*afp)->name; if (!txt) txt = "..";
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000884 fprintf(stderr,"%s (%s) ",txt,_((*afp)->title));
Eric Andersenf15d4da2001-03-06 00:48:59 +0000885 count++;
886 afp++;
887 }
888 fprintf(stderr,"\n");
889}
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000890#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000891
892struct user_net_device_stats {
893 unsigned long long rx_packets; /* total packets received */
894 unsigned long long tx_packets; /* total packets transmitted */
895 unsigned long long rx_bytes; /* total bytes received */
896 unsigned long long tx_bytes; /* total bytes transmitted */
897 unsigned long rx_errors; /* bad packets received */
898 unsigned long tx_errors; /* packet transmit problems */
899 unsigned long rx_dropped; /* no space in linux buffers */
900 unsigned long tx_dropped; /* no space available in linux */
901 unsigned long rx_multicast; /* multicast packets received */
902 unsigned long rx_compressed;
903 unsigned long tx_compressed;
904 unsigned long collisions;
905
906 /* detailed rx_errors: */
907 unsigned long rx_length_errors;
908 unsigned long rx_over_errors; /* receiver ring buff overflow */
909 unsigned long rx_crc_errors; /* recved pkt with crc error */
910 unsigned long rx_frame_errors; /* recv'd frame alignment error */
911 unsigned long rx_fifo_errors; /* recv'r fifo overrun */
912 unsigned long rx_missed_errors; /* receiver missed packet */
913 /* detailed tx_errors */
914 unsigned long tx_aborted_errors;
915 unsigned long tx_carrier_errors;
916 unsigned long tx_fifo_errors;
917 unsigned long tx_heartbeat_errors;
918 unsigned long tx_window_errors;
919};
920
921struct interface {
922 struct interface *next, *prev;
923 char name[IFNAMSIZ]; /* interface name */
924 short type; /* if type */
925 short flags; /* various flags */
926 int metric; /* routing metric */
927 int mtu; /* MTU value */
928 int tx_queue_len; /* transmit queue length */
929 struct ifmap map; /* hardware setup */
930 struct sockaddr addr; /* IP address */
931 struct sockaddr dstaddr; /* P-P IP address */
932 struct sockaddr broadaddr; /* IP broadcast address */
933 struct sockaddr netmask; /* IP network mask */
934 struct sockaddr ipxaddr_bb; /* IPX network address */
935 struct sockaddr ipxaddr_sn; /* IPX network address */
936 struct sockaddr ipxaddr_e3; /* IPX network address */
937 struct sockaddr ipxaddr_e2; /* IPX network address */
938 struct sockaddr ddpaddr; /* Appletalk DDP address */
939 struct sockaddr ecaddr; /* Econet address */
940 int has_ip;
941 int has_ipx_bb;
942 int has_ipx_sn;
943 int has_ipx_e3;
944 int has_ipx_e2;
945 int has_ax25;
946 int has_ddp;
947 int has_econet;
948 char hwaddr[32]; /* HW address */
949 int statistics_valid;
950 struct user_net_device_stats stats; /* statistics */
951 int keepalive; /* keepalive value for SLIP */
952 int outfill; /* outfill value for SLIP */
953};
954
955
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000956int interface_opt_a = 0; /* show all interfaces */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000957
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000958#ifdef KEEP_UNUSED
959static int opt_i = 0; /* show the statistics */
960static int opt_v = 0; /* debugging output flag */
961
962static int addr_family = 0; /* currently selected AF */
963#endif /* KEEP_UNUSED */
964
Eric Andersenf15d4da2001-03-06 00:48:59 +0000965static struct interface *int_list, *int_last;
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000966static int skfd = -1; /* generic raw socket desc. */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000967
968
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +0000969static int sockets_open(int family)
Eric Andersenf15d4da2001-03-06 00:48:59 +0000970{
971 struct aftype **aft;
972 int sfd = -1;
973 static int force = -1;
974
975 if (force < 0) {
976 force = 0;
977 if (get_kernel_revision() < KRELEASE(2, 1, 0))
978 force = 1;
979 if (access("/proc/net", R_OK))
980 force = 1;
981 }
982 for (aft = aftypes; *aft; aft++) {
983 struct aftype *af = *aft;
984 int type = SOCK_DGRAM;
985 if (af->af == AF_UNSPEC)
986 continue;
987 if (family && family != af->af)
988 continue;
989 if (af->fd != -1) {
990 sfd = af->fd;
991 continue;
992 }
993 /* Check some /proc file first to not stress kmod */
994 if (!family && !force && af->flag_file) {
995 if (access(af->flag_file, R_OK))
996 continue;
997 }
998#if HAVE_AFNETROM
999 if (af->af == AF_NETROM)
1000 type = SOCK_SEQPACKET;
1001#endif
1002#if HAVE_AFX25
1003 if (af->af == AF_X25)
1004 type = SOCK_SEQPACKET;
1005#endif
1006 af->fd = socket(af->af, type, 0);
1007 if (af->fd >= 0)
1008 sfd = af->fd;
1009 }
1010 if (sfd < 0)
1011 fprintf(stderr, _("No usable address families found.\n"));
1012 return sfd;
1013}
1014
1015/* like strcmp(), but knows about numbers */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001016static int nstrcmp(const char *astr, const char *b)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001017{
1018 const char *a = astr;
1019
1020 while (*a == *b) {
1021 if (*a == '\0')
1022 return 0;
1023 a++;
1024 b++;
1025 }
1026 if (isdigit(*a)) {
1027 if (!isdigit(*b))
1028 return -1;
1029 while (a > astr) {
1030 a--;
1031 if (!isdigit(*a)) {
1032 a++;
1033 break;
1034 }
1035 if (!isdigit(*b))
1036 return -1;
1037 b--;
1038 }
1039 return atoi(a) > atoi(b) ? 1 : -1;
1040 }
1041 return *a - *b;
1042}
1043
1044static struct interface *add_interface(char *name)
1045{
1046 struct interface *ife, **nextp, *new;
1047
1048 for (ife = int_last; ife; ife = ife->prev) {
1049 int n = nstrcmp(ife->name, name);
1050 if (n == 0)
1051 return ife;
1052 if (n < 0)
1053 break;
1054 }
1055 new(new);
1056 safe_strncpy(new->name, name, IFNAMSIZ);
1057 nextp = ife ? &ife->next : &int_list;
1058 new->prev = ife;
1059 new->next = *nextp;
1060 if (new->next)
1061 new->next->prev = new;
1062 else
1063 int_last = new;
1064 *nextp = new;
1065 return new;
1066}
1067
1068
1069static int if_readconf(void)
1070{
1071 int numreqs = 30;
1072 struct ifconf ifc;
1073 struct ifreq *ifr;
1074 int n, err = -1;
Eric Andersen46cd74b2001-04-19 16:55:27 +00001075 int skfd2;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001076
1077 /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
1078 (as of 2.1.128) */
Eric Andersen46cd74b2001-04-19 16:55:27 +00001079 skfd2 = get_socket_for_af(AF_INET);
1080 if (skfd2 < 0) {
Eric Andersenf15d4da2001-03-06 00:48:59 +00001081 fprintf(stderr, _("warning: no inet socket available: %s\n"),
1082 strerror(errno));
1083 /* Try to soldier on with whatever socket we can get hold of. */
Eric Andersen46cd74b2001-04-19 16:55:27 +00001084 skfd2 = sockets_open(0);
1085 if (skfd2 < 0)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001086 return -1;
1087 }
1088
1089 ifc.ifc_buf = NULL;
1090 for (;;) {
1091 ifc.ifc_len = sizeof(struct ifreq) * numreqs;
1092 ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);
1093
Eric Andersen46cd74b2001-04-19 16:55:27 +00001094 if (ioctl(skfd2, SIOCGIFCONF, &ifc) < 0) {
Eric Andersenf15d4da2001-03-06 00:48:59 +00001095 perror("SIOCGIFCONF");
1096 goto out;
1097 }
1098 if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
1099 /* assume it overflowed and try again */
1100 numreqs += 10;
1101 continue;
1102 }
1103 break;
1104 }
1105
1106 ifr = ifc.ifc_req;
1107 for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
1108 add_interface(ifr->ifr_name);
1109 ifr++;
1110 }
1111 err = 0;
1112
1113out:
1114 free(ifc.ifc_buf);
1115 return err;
1116}
1117
1118static char *get_name(char *name, char *p)
1119{
1120 while (isspace(*p))
1121 p++;
1122 while (*p) {
1123 if (isspace(*p))
1124 break;
1125 if (*p == ':') { /* could be an alias */
1126 char *dot = p, *dotname = name;
1127 *name++ = *p++;
1128 while (isdigit(*p))
1129 *name++ = *p++;
1130 if (*p != ':') { /* it wasn't, backup */
1131 p = dot;
1132 name = dotname;
1133 }
1134 if (*p == '\0')
1135 return NULL;
1136 p++;
1137 break;
1138 }
1139 *name++ = *p++;
1140 }
1141 *name++ = '\0';
1142 return p;
1143}
1144
1145static int get_dev_fields(char *bp, struct interface *ife)
1146{
1147 switch (procnetdev_vsn) {
1148 case 3:
1149 sscanf(bp,
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001150 "%Lu %Lu %lu %lu %lu %lu %lu %lu %Lu %Lu %lu %lu %lu %lu %lu %lu",
Eric Andersenf15d4da2001-03-06 00:48:59 +00001151 &ife->stats.rx_bytes,
1152 &ife->stats.rx_packets,
1153 &ife->stats.rx_errors,
1154 &ife->stats.rx_dropped,
1155 &ife->stats.rx_fifo_errors,
1156 &ife->stats.rx_frame_errors,
1157 &ife->stats.rx_compressed,
1158 &ife->stats.rx_multicast,
1159
1160 &ife->stats.tx_bytes,
1161 &ife->stats.tx_packets,
1162 &ife->stats.tx_errors,
1163 &ife->stats.tx_dropped,
1164 &ife->stats.tx_fifo_errors,
1165 &ife->stats.collisions,
1166 &ife->stats.tx_carrier_errors,
1167 &ife->stats.tx_compressed);
1168 break;
1169 case 2:
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001170 sscanf(bp, "%Lu %Lu %lu %lu %lu %lu %Lu %Lu %lu %lu %lu %lu %lu",
Eric Andersenf15d4da2001-03-06 00:48:59 +00001171 &ife->stats.rx_bytes,
1172 &ife->stats.rx_packets,
1173 &ife->stats.rx_errors,
1174 &ife->stats.rx_dropped,
1175 &ife->stats.rx_fifo_errors,
1176 &ife->stats.rx_frame_errors,
1177
1178 &ife->stats.tx_bytes,
1179 &ife->stats.tx_packets,
1180 &ife->stats.tx_errors,
1181 &ife->stats.tx_dropped,
1182 &ife->stats.tx_fifo_errors,
1183 &ife->stats.collisions,
1184 &ife->stats.tx_carrier_errors);
1185 ife->stats.rx_multicast = 0;
1186 break;
1187 case 1:
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001188 sscanf(bp, "%Lu %lu %lu %lu %lu %Lu %lu %lu %lu %lu %lu",
Eric Andersenf15d4da2001-03-06 00:48:59 +00001189 &ife->stats.rx_packets,
1190 &ife->stats.rx_errors,
1191 &ife->stats.rx_dropped,
1192 &ife->stats.rx_fifo_errors,
1193 &ife->stats.rx_frame_errors,
1194
1195 &ife->stats.tx_packets,
1196 &ife->stats.tx_errors,
1197 &ife->stats.tx_dropped,
1198 &ife->stats.tx_fifo_errors,
1199 &ife->stats.collisions,
1200 &ife->stats.tx_carrier_errors);
1201 ife->stats.rx_bytes = 0;
1202 ife->stats.tx_bytes = 0;
1203 ife->stats.rx_multicast = 0;
1204 break;
1205 }
1206 return 0;
1207}
1208
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001209static inline int procnetdev_version(char *buf)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001210{
1211 if (strstr(buf, "compressed"))
1212 return 3;
1213 if (strstr(buf, "bytes"))
1214 return 2;
1215 return 1;
1216}
1217
1218static int if_readlist_proc(char *target)
1219{
1220 static int proc_read;
1221 FILE *fh;
1222 char buf[512];
1223 struct interface *ife;
1224 int err;
1225
1226 if (proc_read)
1227 return 0;
1228 if (!target)
1229 proc_read = 1;
1230
1231 fh = fopen(_PATH_PROCNET_DEV, "r");
1232 if (!fh) {
1233 fprintf(stderr, _("Warning: cannot open %s (%s). Limited output.\n"),
1234 _PATH_PROCNET_DEV, strerror(errno));
1235 return if_readconf();
1236 }
1237 fgets(buf, sizeof buf, fh); /* eat line */
1238 fgets(buf, sizeof buf, fh);
1239
1240#if 0 /* pretty, but can't cope with missing fields */
1241 fmt = proc_gen_fmt(_PATH_PROCNET_DEV, 1, fh,
1242 "face", "", /* parsed separately */
1243 "bytes", "%lu",
1244 "packets", "%lu",
1245 "errs", "%lu",
1246 "drop", "%lu",
1247 "fifo", "%lu",
1248 "frame", "%lu",
1249 "compressed", "%lu",
1250 "multicast", "%lu",
1251 "bytes", "%lu",
1252 "packets", "%lu",
1253 "errs", "%lu",
1254 "drop", "%lu",
1255 "fifo", "%lu",
1256 "colls", "%lu",
1257 "carrier", "%lu",
1258 "compressed", "%lu",
1259 NULL);
1260 if (!fmt)
1261 return -1;
1262#else
1263 procnetdev_vsn = procnetdev_version(buf);
1264#endif
1265
1266 err = 0;
1267 while (fgets(buf, sizeof buf, fh)) {
1268 char *s, name[IFNAMSIZ];
1269 s = get_name(name, buf);
1270 ife = add_interface(name);
1271 get_dev_fields(s, ife);
1272 ife->statistics_valid = 1;
1273 if (target && !strcmp(target,name))
1274 break;
1275 }
1276 if (ferror(fh)) {
1277 perror(_PATH_PROCNET_DEV);
1278 err = -1;
1279 proc_read = 0;
1280 }
1281
1282#if 0
1283 free(fmt);
1284#endif
1285 fclose(fh);
1286 return err;
1287}
1288
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001289static int if_readlist(void)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001290{
1291 int err = if_readlist_proc(NULL);
1292 if (!err)
1293 err = if_readconf();
1294 return err;
1295}
1296
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001297static int for_all_interfaces(int (*doit) (struct interface *, void *), void *cookie)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001298{
1299 struct interface *ife;
1300
1301 if (!int_list && (if_readlist() < 0))
1302 return -1;
1303 for (ife = int_list; ife; ife = ife->next) {
1304 int err = doit(ife, cookie);
1305 if (err)
1306 return err;
1307 }
1308 return 0;
1309}
1310
1311/* Support for fetching an IPX address */
1312
1313#if HAVE_AFIPX
1314static int ipx_getaddr(int sock, int ft, struct ifreq *ifr)
1315{
1316 ((struct sockaddr_ipx *) &ifr->ifr_addr)->sipx_type = ft;
1317 return ioctl(sock, SIOCGIFADDR, ifr);
1318}
1319#endif
1320
1321
1322/* Fetch the interface configuration from the kernel. */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001323static int if_fetch(struct interface *ife)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001324{
1325 struct ifreq ifr;
1326 int fd;
1327 char *ifname = ife->name;
1328
1329 strcpy(ifr.ifr_name, ifname);
1330 if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
1331 return (-1);
1332 ife->flags = ifr.ifr_flags;
1333
1334 strcpy(ifr.ifr_name, ifname);
1335 if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
1336 memset(ife->hwaddr, 0, 32);
1337 else
1338 memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
1339
1340 ife->type = ifr.ifr_hwaddr.sa_family;
1341
1342 strcpy(ifr.ifr_name, ifname);
1343 if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0)
1344 ife->metric = 0;
1345 else
1346 ife->metric = ifr.ifr_metric;
1347
1348 strcpy(ifr.ifr_name, ifname);
1349 if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
1350 ife->mtu = 0;
1351 else
1352 ife->mtu = ifr.ifr_mtu;
1353
1354#ifdef HAVE_HWSLIP
1355 if (ife->type == ARPHRD_SLIP || ife->type == ARPHRD_CSLIP ||
1356 ife->type == ARPHRD_SLIP6 || ife->type == ARPHRD_CSLIP6 ||
1357 ife->type == ARPHRD_ADAPT) {
1358#ifdef SIOCGOUTFILL
1359 strcpy(ifr.ifr_name, ifname);
1360 if (ioctl(skfd, SIOCGOUTFILL, &ifr) < 0)
1361 ife->outfill = 0;
1362 else
1363 ife->outfill = (unsigned int) ifr.ifr_data;
1364#endif
1365#ifdef SIOCGKEEPALIVE
1366 strcpy(ifr.ifr_name, ifname);
1367 if (ioctl(skfd, SIOCGKEEPALIVE, &ifr) < 0)
1368 ife->keepalive = 0;
1369 else
1370 ife->keepalive = (unsigned int) ifr.ifr_data;
1371#endif
1372 }
1373#endif
1374
1375 strcpy(ifr.ifr_name, ifname);
1376 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
1377 memset(&ife->map, 0, sizeof(struct ifmap));
1378 else
1379 memcpy(&ife->map, &ifr.ifr_map, sizeof(struct ifmap));
1380
1381 strcpy(ifr.ifr_name, ifname);
1382 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
1383 memset(&ife->map, 0, sizeof(struct ifmap));
1384 else
1385 ife->map = ifr.ifr_map;
1386
1387#ifdef HAVE_TXQUEUELEN
1388 strcpy(ifr.ifr_name, ifname);
1389 if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0)
1390 ife->tx_queue_len = -1; /* unknown value */
1391 else
1392 ife->tx_queue_len = ifr.ifr_qlen;
1393#else
1394 ife->tx_queue_len = -1; /* unknown value */
1395#endif
1396
1397#if HAVE_AFINET
1398 /* IPv4 address? */
1399 fd = get_socket_for_af(AF_INET);
1400 if (fd >= 0) {
1401 strcpy(ifr.ifr_name, ifname);
1402 ifr.ifr_addr.sa_family = AF_INET;
1403 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
1404 ife->has_ip = 1;
1405 ife->addr = ifr.ifr_addr;
1406 strcpy(ifr.ifr_name, ifname);
1407 if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0)
1408 memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
1409 else
1410 ife->dstaddr = ifr.ifr_dstaddr;
1411
1412 strcpy(ifr.ifr_name, ifname);
1413 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
1414 memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
1415 else
1416 ife->broadaddr = ifr.ifr_broadaddr;
1417
1418 strcpy(ifr.ifr_name, ifname);
1419 if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
1420 memset(&ife->netmask, 0, sizeof(struct sockaddr));
1421 else
1422 ife->netmask = ifr.ifr_netmask;
1423 } else
1424 memset(&ife->addr, 0, sizeof(struct sockaddr));
1425 }
1426#endif
1427
1428#if HAVE_AFATALK
1429 /* DDP address maybe ? */
1430 fd = get_socket_for_af(AF_APPLETALK);
1431 if (fd >= 0) {
1432 strcpy(ifr.ifr_name, ifname);
1433 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
1434 ife->ddpaddr = ifr.ifr_addr;
1435 ife->has_ddp = 1;
1436 }
1437 }
1438#endif
1439
1440#if HAVE_AFIPX
1441 /* Look for IPX addresses with all framing types */
1442 fd = get_socket_for_af(AF_IPX);
1443 if (fd >= 0) {
1444 strcpy(ifr.ifr_name, ifname);
1445 if (!ipx_getaddr(fd, IPX_FRAME_ETHERII, &ifr)) {
1446 ife->has_ipx_bb = 1;
1447 ife->ipxaddr_bb = ifr.ifr_addr;
1448 }
1449 strcpy(ifr.ifr_name, ifname);
1450 if (!ipx_getaddr(fd, IPX_FRAME_SNAP, &ifr)) {
1451 ife->has_ipx_sn = 1;
1452 ife->ipxaddr_sn = ifr.ifr_addr;
1453 }
1454 strcpy(ifr.ifr_name, ifname);
1455 if (!ipx_getaddr(fd, IPX_FRAME_8023, &ifr)) {
1456 ife->has_ipx_e3 = 1;
1457 ife->ipxaddr_e3 = ifr.ifr_addr;
1458 }
1459 strcpy(ifr.ifr_name, ifname);
1460 if (!ipx_getaddr(fd, IPX_FRAME_8022, &ifr)) {
1461 ife->has_ipx_e2 = 1;
1462 ife->ipxaddr_e2 = ifr.ifr_addr;
1463 }
1464 }
1465#endif
1466
1467#if HAVE_AFECONET
1468 /* Econet address maybe? */
1469 fd = get_socket_for_af(AF_ECONET);
1470 if (fd >= 0) {
1471 strcpy(ifr.ifr_name, ifname);
1472 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
1473 ife->ecaddr = ifr.ifr_addr;
1474 ife->has_econet = 1;
1475 }
1476 }
1477#endif
1478
1479 return 0;
1480}
1481
1482
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001483static int do_if_fetch(struct interface *ife)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001484{
1485 if (if_fetch(ife) < 0) {
1486 char *errmsg;
1487 if (errno == ENODEV) {
1488 /* Give better error message for this case. */
1489 errmsg = _("Device not found");
1490 } else {
1491 errmsg = strerror(errno);
1492 }
1493 fprintf(stderr, _("%s: error fetching interface information: %s\n"),
1494 ife->name, errmsg);
1495 return -1;
1496 }
1497 return 0;
1498}
1499
1500/* This structure defines hardware protocols and their handlers. */
1501struct hwtype {
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001502 const char *name;
1503 const char *title;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001504 int type;
1505 int alen;
1506 char *(*print) (unsigned char *);
1507 int (*input) (char *, struct sockaddr *);
1508 int (*activate) (int fd);
1509 int suppress_null_addr;
1510};
1511
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001512static struct hwtype unspec_hwtype =
Eric Andersenf15d4da2001-03-06 00:48:59 +00001513{
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001514 "unspec", "UNSPEC", -1, 0,
Eric Andersen46cd74b2001-04-19 16:55:27 +00001515 UNSPEC_print, NULL, NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +00001516};
1517
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001518static struct hwtype loop_hwtype =
Eric Andersenf15d4da2001-03-06 00:48:59 +00001519{
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001520 "loop", "Local Loopback", ARPHRD_LOOPBACK, 0,
Eric Andersenf15d4da2001-03-06 00:48:59 +00001521 NULL, NULL, NULL
1522};
1523
1524#if HAVE_HWETHER
1525#include <net/if_arp.h>
1526#include <linux/if_ether.h>
1527
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001528static struct hwtype ether_hwtype;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001529
1530/* Display an Ethernet address in readable format. */
1531static char *pr_ether(unsigned char *ptr)
1532{
1533 static char buff[64];
1534
1535 snprintf(buff, sizeof(buff), "%02X:%02X:%02X:%02X:%02X:%02X",
1536 (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377),
1537 (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)
1538 );
1539 return (buff);
1540}
1541
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001542#ifdef KEEP_UNUSED
Eric Andersenf15d4da2001-03-06 00:48:59 +00001543/* Input an Ethernet address and convert to binary. */
1544static int in_ether(char *bufp, struct sockaddr *sap)
1545{
1546 unsigned char *ptr;
1547 char c, *orig;
1548 int i;
1549 unsigned val;
1550
1551 sap->sa_family = ether_hwtype.type;
1552 ptr = sap->sa_data;
1553
1554 i = 0;
1555 orig = bufp;
1556 while ((*bufp != '\0') && (i < ETH_ALEN)) {
1557 val = 0;
1558 c = *bufp++;
1559 if (isdigit(c))
1560 val = c - '0';
1561 else if (c >= 'a' && c <= 'f')
1562 val = c - 'a' + 10;
1563 else if (c >= 'A' && c <= 'F')
1564 val = c - 'A' + 10;
1565 else {
1566#ifdef DEBUG
1567 fprintf(stderr, _("in_ether(%s): invalid ether address!\n"), orig);
1568#endif
1569 errno = EINVAL;
1570 return (-1);
1571 }
1572 val <<= 4;
1573 c = *bufp;
1574 if (isdigit(c))
1575 val |= c - '0';
1576 else if (c >= 'a' && c <= 'f')
1577 val |= c - 'a' + 10;
1578 else if (c >= 'A' && c <= 'F')
1579 val |= c - 'A' + 10;
1580 else if (c == ':' || c == 0)
1581 val >>= 4;
1582 else {
1583#ifdef DEBUG
1584 fprintf(stderr, _("in_ether(%s): invalid ether address!\n"), orig);
1585#endif
1586 errno = EINVAL;
1587 return (-1);
1588 }
1589 if (c != 0)
1590 bufp++;
1591 *ptr++ = (unsigned char) (val & 0377);
1592 i++;
1593
1594 /* We might get a semicolon here - not required. */
1595 if (*bufp == ':') {
1596 if (i == ETH_ALEN) {
1597#ifdef DEBUG
1598 fprintf(stderr, _("in_ether(%s): trailing : ignored!\n"),
1599 orig)
1600#endif
1601 ; /* nothing */
1602 }
1603 bufp++;
1604 }
1605 }
1606
1607 /* That's it. Any trailing junk? */
1608 if ((i == ETH_ALEN) && (*bufp != '\0')) {
1609#ifdef DEBUG
1610 fprintf(stderr, _("in_ether(%s): trailing junk!\n"), orig);
1611 errno = EINVAL;
1612 return (-1);
1613#endif
1614 }
1615#ifdef DEBUG
1616 fprintf(stderr, "in_ether(%s): %s\n", orig, pr_ether(sap->sa_data));
1617#endif
1618
1619 return (0);
1620}
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001621#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +00001622
1623
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001624static struct hwtype ether_hwtype =
Eric Andersenf15d4da2001-03-06 00:48:59 +00001625{
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001626 "ether", "Ethernet", ARPHRD_ETHER, ETH_ALEN,
1627 pr_ether, NULL /* UNUSED in_ether */, NULL
Eric Andersenf15d4da2001-03-06 00:48:59 +00001628};
1629
1630
1631#endif /* HAVE_HWETHER */
1632
1633
1634#if HAVE_HWPPP
1635
1636#include <net/if_arp.h>
1637
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001638#ifdef KEEP_UNUSED
Eric Andersenf15d4da2001-03-06 00:48:59 +00001639/* Start the PPP encapsulation on the file descriptor. */
1640static int do_ppp(int fd)
1641{
1642 fprintf(stderr, _("You cannot start PPP with this program.\n"));
1643 return -1;
1644}
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001645#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +00001646
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001647static struct hwtype ppp_hwtype =
Eric Andersenf15d4da2001-03-06 00:48:59 +00001648{
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001649 "ppp", "Point-Point Protocol", ARPHRD_PPP, 0,
1650 NULL, NULL, NULL /* UNUSED do_ppp */, 0
Eric Andersenf15d4da2001-03-06 00:48:59 +00001651};
1652
1653
1654#endif /* HAVE_PPP */
1655
1656static struct hwtype *hwtypes[] =
1657{
1658
1659 &loop_hwtype,
1660
1661#if HAVE_HWSLIP
1662 &slip_hwtype,
1663 &cslip_hwtype,
1664 &slip6_hwtype,
1665 &cslip6_hwtype,
1666 &adaptive_hwtype,
1667#endif
1668#if HAVE_HWSTRIP
1669 &strip_hwtype,
1670#endif
1671#if HAVE_HWASH
1672 &ash_hwtype,
1673#endif
1674#if HAVE_HWETHER
1675 &ether_hwtype,
1676#endif
1677#if HAVE_HWTR
1678 &tr_hwtype,
1679#ifdef ARPHRD_IEEE802_TR
1680 &tr_hwtype1,
1681#endif
1682#endif
1683#if HAVE_HWAX25
1684 &ax25_hwtype,
1685#endif
1686#if HAVE_HWNETROM
1687 &netrom_hwtype,
1688#endif
1689#if HAVE_HWROSE
1690 &rose_hwtype,
1691#endif
1692#if HAVE_HWTUNNEL
1693 &tunnel_hwtype,
1694#endif
1695#if HAVE_HWPPP
1696 &ppp_hwtype,
1697#endif
1698#if HAVE_HWHDLCLAPB
1699 &hdlc_hwtype,
1700 &lapb_hwtype,
1701#endif
1702#if HAVE_HWARC
1703 &arcnet_hwtype,
1704#endif
1705#if HAVE_HWFR
1706 &dlci_hwtype,
1707 &frad_hwtype,
1708#endif
1709#if HAVE_HWSIT
1710 &sit_hwtype,
1711#endif
1712#if HAVE_HWFDDI
1713 &fddi_hwtype,
1714#endif
1715#if HAVE_HWHIPPI
1716 &hippi_hwtype,
1717#endif
1718#if HAVE_HWIRDA
1719 &irda_hwtype,
1720#endif
1721#if HAVE_HWEC
1722 &ec_hwtype,
1723#endif
1724#if HAVE_HWX25
1725 &x25_hwtype,
1726#endif
1727 &unspec_hwtype,
1728 NULL
1729};
1730
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001731#ifdef KEEP_UNUSED
Eric Andersenf15d4da2001-03-06 00:48:59 +00001732static short sVhwinit = 0;
1733
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001734static void hwinit()
Eric Andersenf15d4da2001-03-06 00:48:59 +00001735{
1736 loop_hwtype.title = _("Local Loopback");
1737 unspec_hwtype.title = _("UNSPEC");
1738#if HAVE_HWSLIP
1739 slip_hwtype.title = _("Serial Line IP");
1740 cslip_hwtype.title = _("VJ Serial Line IP");
1741 slip6_hwtype.title = _("6-bit Serial Line IP");
1742 cslip6_hwtype.title = _("VJ 6-bit Serial Line IP");
1743 adaptive_hwtype.title = _("Adaptive Serial Line IP");
1744#endif
1745#if HAVE_HWETHER
1746 ether_hwtype.title = _("Ethernet");
1747#endif
1748#if HAVE_HWASH
1749 ash_hwtype.title = _("Ash");
1750#endif
1751#if HAVE_HWFDDI
1752 fddi_hwtype.title = _("Fiber Distributed Data Interface");
1753#endif
1754#if HAVE_HWHIPPI
1755 hippi_hwtype.title = _("HIPPI");
1756#endif
1757#if HAVE_HWAX25
1758 ax25_hwtype.title = _("AMPR AX.25");
1759#endif
1760#if HAVE_HWROSE
1761 rose_hwtype.title = _("AMPR ROSE");
1762#endif
1763#if HAVE_HWNETROM
1764 netrom_hwtype.title = _("AMPR NET/ROM");
1765#endif
1766#if HAVE_HWX25
1767 x25_hwtype.title = _("generic X.25");
1768#endif
1769#if HAVE_HWTUNNEL
1770 tunnel_hwtype.title = _("IPIP Tunnel");
1771#endif
1772#if HAVE_HWPPP
1773 ppp_hwtype.title = _("Point-to-Point Protocol");
1774#endif
1775#if HAVE_HWHDLCLAPB
1776 hdlc_hwtype.title = _("(Cisco)-HDLC");
1777 lapb_hwtype.title = _("LAPB");
1778#endif
1779#if HAVE_HWARC
1780 arcnet_hwtype.title = _("ARCnet");
1781#endif
1782#if HAVE_HWFR
1783 dlci_hwtype.title = _("Frame Relay DLCI");
1784 frad_hwtype.title = _("Frame Relay Access Device");
1785#endif
1786#if HAVE_HWSIT
1787 sit_hwtype.title = _("IPv6-in-IPv4");
1788#endif
1789#if HAVE_HWIRDA
1790 irda_hwtype.title = _("IrLAP");
1791#endif
1792#if HAVE_HWTR
1793 tr_hwtype.title = _("16/4 Mbps Token Ring");
1794#ifdef ARPHRD_IEEE802_TR
1795 tr_hwtype1.title = _("16/4 Mbps Token Ring (New)") ;
1796#endif
1797#endif
1798#if HAVE_HWEC
1799 ec_hwtype.title = _("Econet");
1800#endif
1801 sVhwinit = 1;
1802}
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001803#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +00001804
1805#ifdef IFF_PORTSEL
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001806static const char *if_port_text[][4] =
Eric Andersenf15d4da2001-03-06 00:48:59 +00001807{
1808 /* Keep in step with <linux/netdevice.h> */
1809 {"unknown", NULL, NULL, NULL},
1810 {"10base2", "bnc", "coax", NULL},
1811 {"10baseT", "utp", "tpe", NULL},
1812 {"AUI", "thick", "db15", NULL},
1813 {"100baseT", NULL, NULL, NULL},
1814 {"100baseTX", NULL, NULL, NULL},
1815 {"100baseFX", NULL, NULL, NULL},
1816 {NULL, NULL, NULL, NULL},
1817};
1818#endif
1819
1820/* Check our hardware type table for this type. */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001821static struct hwtype *get_hwntype(int type)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001822{
1823 struct hwtype **hwp;
1824
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001825#ifdef KEEP_UNUSED
Eric Andersenf15d4da2001-03-06 00:48:59 +00001826 if (!sVhwinit)
1827 hwinit();
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001828#endif /* KEEP_UNUSED */
Eric Andersenf15d4da2001-03-06 00:48:59 +00001829
1830 hwp = hwtypes;
1831 while (*hwp != NULL) {
1832 if ((*hwp)->type == type)
1833 return (*hwp);
1834 hwp++;
1835 }
1836 return (NULL);
1837}
1838
1839/* return 1 if address is all zeros */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001840static int hw_null_address(struct hwtype *hw, void *ap)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001841{
1842 unsigned int i;
1843 unsigned char *address = (unsigned char *)ap;
1844 for (i = 0; i < hw->alen; i++)
1845 if (address[i])
1846 return 0;
1847 return 1;
1848}
1849
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001850static const char TRext[] = "\0\0k\0M";
1851
1852static void print_bytes_scaled(unsigned long long ull, const char *end)
1853{
1854 unsigned long long int_part;
1855 unsigned long frac_part;
1856 const char *ext;
1857 int i;
1858
1859 frac_part = 0;
1860 ext = TRext;
1861 int_part = ull;
1862 for (i=0 ; i<2 ; i++) {
1863 if (int_part >= 1024) {
1864 frac_part = ((int_part % 1024) * 10) / 1024;
1865 int_part /= 1024;
1866 ext += 2; /* Kb, Mb */
1867 }
1868 }
1869
1870 printf("X bytes:%Lu (%Lu.%lu %sb)%s", ull, int_part, frac_part, ext, end);
1871}
1872
1873static void ife_print(struct interface *ptr)
Eric Andersenf15d4da2001-03-06 00:48:59 +00001874{
1875 struct aftype *ap;
1876 struct hwtype *hw;
1877 int hf;
1878 int can_compress = 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +00001879
1880#if HAVE_AFIPX
1881 static struct aftype *ipxtype = NULL;
1882#endif
1883#if HAVE_AFECONET
1884 static struct aftype *ectype = NULL;
1885#endif
1886#if HAVE_AFATALK
1887 static struct aftype *ddptype = NULL;
1888#endif
1889#if HAVE_AFINET6
1890 FILE *f;
1891 char addr6[40], devname[20];
1892 struct sockaddr_in6 sap;
1893 int plen, scope, dad_status, if_idx;
1894 extern struct aftype inet6_aftype;
1895 char addr6p[8][5];
1896#endif
1897
1898 ap = get_afntype(ptr->addr.sa_family);
1899 if (ap == NULL)
1900 ap = get_afntype(0);
1901
1902 hf = ptr->type;
1903
1904 if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
1905 can_compress = 1;
1906
1907 hw = get_hwntype(hf);
1908 if (hw == NULL)
1909 hw = get_hwntype(-1);
1910
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00001911 printf(_("%-9.9s Link encap:%s "), ptr->name, _(hw->title));
Eric Andersenf15d4da2001-03-06 00:48:59 +00001912 /* For some hardware types (eg Ash, ATM) we don't print the
1913 hardware address if it's null. */
1914 if (hw->print != NULL && (! (hw_null_address(hw, ptr->hwaddr) &&
1915 hw->suppress_null_addr)))
1916 printf(_("HWaddr %s "), hw->print(ptr->hwaddr));
1917#ifdef IFF_PORTSEL
1918 if (ptr->flags & IFF_PORTSEL) {
1919 printf(_("Media:%s"), if_port_text[ptr->map.port][0]);
1920 if (ptr->flags & IFF_AUTOMEDIA)
1921 printf(_("(auto)"));
1922 }
1923#endif
1924 printf("\n");
1925
1926#if HAVE_AFINET
1927 if (ptr->has_ip) {
1928 printf(_(" %s addr:%s "), ap->name,
1929 ap->sprint(&ptr->addr, 1));
1930 if (ptr->flags & IFF_POINTOPOINT) {
1931 printf(_(" P-t-P:%s "), ap->sprint(&ptr->dstaddr, 1));
1932 }
1933 if (ptr->flags & IFF_BROADCAST) {
1934 printf(_(" Bcast:%s "), ap->sprint(&ptr->broadaddr, 1));
1935 }
1936 printf(_(" Mask:%s\n"), ap->sprint(&ptr->netmask, 1));
1937 }
1938#endif
1939
1940#if HAVE_AFINET6
1941 /* FIXME: should be integrated into interface.c. */
1942
1943 if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
1944 while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
1945 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
1946 addr6p[4], addr6p[5], addr6p[6], addr6p[7],
1947 &if_idx, &plen, &scope, &dad_status, devname) != EOF) {
1948 if (!strcmp(devname, ptr->name)) {
1949 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
1950 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
1951 addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
1952 inet6_aftype.input(1, addr6, (struct sockaddr *) &sap);
1953 printf(_(" inet6 addr: %s/%d"),
1954 inet6_aftype.sprint((struct sockaddr *) &sap, 1), plen);
1955 printf(_(" Scope:"));
1956 switch (scope) {
1957 case 0:
1958 printf(_("Global"));
1959 break;
1960 case IPV6_ADDR_LINKLOCAL:
1961 printf(_("Link"));
1962 break;
1963 case IPV6_ADDR_SITELOCAL:
1964 printf(_("Site"));
1965 break;
1966 case IPV6_ADDR_COMPATv4:
1967 printf(_("Compat"));
1968 break;
1969 case IPV6_ADDR_LOOPBACK:
1970 printf(_("Host"));
1971 break;
1972 default:
1973 printf(_("Unknown"));
1974 }
1975 printf("\n");
1976 }
1977 }
1978 fclose(f);
1979 }
1980#endif
1981
1982#if HAVE_AFIPX
1983 if (ipxtype == NULL)
1984 ipxtype = get_afntype(AF_IPX);
1985
1986 if (ipxtype != NULL) {
1987 if (ptr->has_ipx_bb)
1988 printf(_(" IPX/Ethernet II addr:%s\n"),
1989 ipxtype->sprint(&ptr->ipxaddr_bb, 1));
1990 if (ptr->has_ipx_sn)
1991 printf(_(" IPX/Ethernet SNAP addr:%s\n"),
1992 ipxtype->sprint(&ptr->ipxaddr_sn, 1));
1993 if (ptr->has_ipx_e2)
1994 printf(_(" IPX/Ethernet 802.2 addr:%s\n"),
1995 ipxtype->sprint(&ptr->ipxaddr_e2, 1));
1996 if (ptr->has_ipx_e3)
1997 printf(_(" IPX/Ethernet 802.3 addr:%s\n"),
1998 ipxtype->sprint(&ptr->ipxaddr_e3, 1));
1999 }
2000#endif
2001
2002#if HAVE_AFATALK
2003 if (ddptype == NULL)
2004 ddptype = get_afntype(AF_APPLETALK);
2005 if (ddptype != NULL) {
2006 if (ptr->has_ddp)
2007 printf(_(" EtherTalk Phase 2 addr:%s\n"), ddptype->sprint(&ptr->ddpaddr, 1));
2008 }
2009#endif
2010
2011#if HAVE_AFECONET
2012 if (ectype == NULL)
2013 ectype = get_afntype(AF_ECONET);
2014 if (ectype != NULL) {
2015 if (ptr->has_econet)
2016 printf(_(" econet addr:%s\n"), ectype->sprint(&ptr->ecaddr, 1));
2017 }
2018#endif
2019
2020 printf(" ");
2021 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
2022 if (ptr->flags == 0)
2023 printf(_("[NO FLAGS] "));
2024 if (ptr->flags & IFF_UP)
2025 printf(_("UP "));
2026 if (ptr->flags & IFF_BROADCAST)
2027 printf(_("BROADCAST "));
2028 if (ptr->flags & IFF_DEBUG)
2029 printf(_("DEBUG "));
2030 if (ptr->flags & IFF_LOOPBACK)
2031 printf(_("LOOPBACK "));
2032 if (ptr->flags & IFF_POINTOPOINT)
2033 printf(_("POINTOPOINT "));
2034 if (ptr->flags & IFF_NOTRAILERS)
2035 printf(_("NOTRAILERS "));
2036 if (ptr->flags & IFF_RUNNING)
2037 printf(_("RUNNING "));
2038 if (ptr->flags & IFF_NOARP)
2039 printf(_("NOARP "));
2040 if (ptr->flags & IFF_PROMISC)
2041 printf(_("PROMISC "));
2042 if (ptr->flags & IFF_ALLMULTI)
2043 printf(_("ALLMULTI "));
2044 if (ptr->flags & IFF_SLAVE)
2045 printf(_("SLAVE "));
2046 if (ptr->flags & IFF_MASTER)
2047 printf(_("MASTER "));
2048 if (ptr->flags & IFF_MULTICAST)
2049 printf(_("MULTICAST "));
2050#ifdef HAVE_DYNAMIC
2051 if (ptr->flags & IFF_DYNAMIC)
2052 printf(_("DYNAMIC "));
2053#endif
2054 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
2055 printf(_(" MTU:%d Metric:%d"),
2056 ptr->mtu, ptr->metric ? ptr->metric : 1);
2057#ifdef SIOCSKEEPALIVE
2058 if (ptr->outfill || ptr->keepalive)
2059 printf(_(" Outfill:%d Keepalive:%d"),
2060 ptr->outfill, ptr->keepalive);
2061#endif
2062 printf("\n");
2063
2064 /* If needed, display the interface statistics. */
2065
2066 if (ptr->statistics_valid) {
2067 /* XXX: statistics are currently only printed for the primary address,
2068 * not for the aliases, although strictly speaking they're shared
2069 * by all addresses.
2070 */
2071 printf(" ");
2072
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00002073 printf(_("RX packets:%Lu errors:%lu dropped:%lu overruns:%lu frame:%lu\n"),
Eric Andersenf15d4da2001-03-06 00:48:59 +00002074 ptr->stats.rx_packets, ptr->stats.rx_errors,
2075 ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors,
2076 ptr->stats.rx_frame_errors);
2077 if (can_compress)
2078 printf(_(" compressed:%lu\n"), ptr->stats.rx_compressed);
Eric Andersenf15d4da2001-03-06 00:48:59 +00002079 printf(" ");
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00002080 printf(_("TX packets:%Lu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n"),
Eric Andersenf15d4da2001-03-06 00:48:59 +00002081 ptr->stats.tx_packets, ptr->stats.tx_errors,
2082 ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
2083 ptr->stats.tx_carrier_errors);
2084 printf(_(" collisions:%lu "), ptr->stats.collisions);
2085 if (can_compress)
2086 printf(_("compressed:%lu "), ptr->stats.tx_compressed);
2087 if (ptr->tx_queue_len != -1)
2088 printf(_("txqueuelen:%d "), ptr->tx_queue_len);
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00002089 printf("\n R");
2090 print_bytes_scaled(ptr->stats.rx_bytes, " T");
Manuel Novoa III 0e0883e2001-03-15 15:37:48 +00002091 print_bytes_scaled(ptr->stats.tx_bytes, "\n");
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00002092
Eric Andersenf15d4da2001-03-06 00:48:59 +00002093 }
2094
2095 if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
2096 ptr->map.base_addr)) {
2097 printf(" ");
2098 if (ptr->map.irq)
2099 printf(_("Interrupt:%d "), ptr->map.irq);
2100 if (ptr->map.base_addr >= 0x100) /* Only print devices using it for
2101 I/O maps */
2102 printf(_("Base address:0x%x "), ptr->map.base_addr);
2103 if (ptr->map.mem_start) {
2104 printf(_("Memory:%lx-%lx "), ptr->map.mem_start, ptr->map.mem_end);
2105 }
2106 if (ptr->map.dma)
2107 printf(_("DMA chan:%x "), ptr->map.dma);
2108 printf("\n");
2109 }
2110 printf("\n");
2111}
2112
2113
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00002114static int do_if_print(struct interface *ife, void *cookie)
Eric Andersenf15d4da2001-03-06 00:48:59 +00002115{
2116 int *opt_a = (int *) cookie;
2117 int res;
2118
2119 res = do_if_fetch(ife);
2120 if (res >= 0) {
2121 if ((ife->flags & IFF_UP) || *opt_a)
2122 ife_print(ife);
2123 }
2124 return res;
2125}
2126
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00002127static struct interface *lookup_interface(char *name)
Eric Andersenf15d4da2001-03-06 00:48:59 +00002128{
2129 struct interface *ife = NULL;
2130
2131 if (if_readlist_proc(name) < 0)
2132 return NULL;
2133 ife = add_interface(name);
2134 return ife;
2135}
2136
2137/* for ipv4 add/del modes */
2138static int if_print(char *ifname)
2139{
2140 int res;
2141
2142 if (!ifname) {
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00002143 res = for_all_interfaces(do_if_print, &interface_opt_a);
Eric Andersenf15d4da2001-03-06 00:48:59 +00002144 } else {
2145 struct interface *ife;
2146
2147 ife = lookup_interface(ifname);
2148 res = do_if_fetch(ife);
2149 if (res >= 0)
2150 ife_print(ife);
2151 }
2152 return res;
2153}
2154
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00002155int display_interfaces(char *ifname)
Eric Andersenf15d4da2001-03-06 00:48:59 +00002156{
2157 int status;
2158
2159 /* Create a channel to the NET kernel. */
2160 if ((skfd = sockets_open(0)) < 0) {
Manuel Novoa III 78f57462001-03-10 02:00:54 +00002161 perror_msg_and_die("socket");
Eric Andersenf15d4da2001-03-06 00:48:59 +00002162 }
2163
2164 /* Do we have to show the current setup? */
Manuel Novoa III 68ea1d02001-03-12 09:57:59 +00002165 status = if_print(ifname);
Eric Andersenf15d4da2001-03-06 00:48:59 +00002166 close(skfd);
2167 exit(status < 0);
2168}