interface.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * stolen from net-tools-1.59 and stripped down for busybox by
  4. * Erik Andersen <andersen@codepoet.org>
  5. *
  6. * Heavily modified by Manuel Novoa III Mar 12, 2001
  7. *
  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. *
  14. * 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. *
  18. *
  19. * Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
  20. * and others. Copyright 1993 MicroWalt Corporation
  21. *
  22. * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  23. *
  24. * Patched to support 'add' and 'del' keywords for INET(4) addresses
  25. * by Mrs. Brisby <mrs.brisby@nimh.org>
  26. *
  27. * {1.34} - 19980630 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  28. * - gettext instead of catgets for i18n
  29. * 10/1998 - Andi Kleen. Use interface list primitives.
  30. * 20001008 - Bernd Eckenfels, Patch from RH for setting mtu
  31. * (default AF was wrong)
  32. */
  33. #include <net/if.h>
  34. #include <net/if_arp.h>
  35. #include "inet_common.h"
  36. #include "libbb.h"
  37. #if ENABLE_FEATURE_IPV6
  38. # define HAVE_AFINET6 1
  39. #else
  40. # undef HAVE_AFINET6
  41. #endif
  42. #define _PATH_PROCNET_DEV "/proc/net/dev"
  43. #define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"
  44. #ifdef HAVE_AFINET6
  45. #ifndef _LINUX_IN6_H
  46. /*
  47. * This is in linux/include/net/ipv6.h.
  48. */
  49. struct in6_ifreq {
  50. struct in6_addr ifr6_addr;
  51. uint32_t ifr6_prefixlen;
  52. unsigned int ifr6_ifindex;
  53. };
  54. #endif
  55. #endif /* HAVE_AFINET6 */
  56. /* Defines for glibc2.0 users. */
  57. #ifndef SIOCSIFTXQLEN
  58. #define SIOCSIFTXQLEN 0x8943
  59. #define SIOCGIFTXQLEN 0x8942
  60. #endif
  61. /* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
  62. #ifndef ifr_qlen
  63. #define ifr_qlen ifr_ifru.ifru_mtu
  64. #endif
  65. #ifndef HAVE_TXQUEUELEN
  66. #define HAVE_TXQUEUELEN 1
  67. #endif
  68. #ifndef IFF_DYNAMIC
  69. #define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */
  70. #endif
  71. /* Display an Internet socket address. */
  72. static const char *INET_sprint(struct sockaddr *sap, int numeric)
  73. {
  74. static char *buff;
  75. free(buff);
  76. if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
  77. return "[NONE SET]";
  78. buff = INET_rresolve((struct sockaddr_in *) sap, numeric, 0xffffff00);
  79. return buff;
  80. }
  81. #ifdef UNUSED_AND_BUGGY
  82. static int INET_getsock(char *bufp, struct sockaddr *sap)
  83. {
  84. char *sp = bufp, *bp;
  85. unsigned int i;
  86. unsigned val;
  87. struct sockaddr_in *sock_in;
  88. sock_in = (struct sockaddr_in *) sap;
  89. sock_in->sin_family = AF_INET;
  90. sock_in->sin_port = 0;
  91. val = 0;
  92. bp = (char *) &val;
  93. for (i = 0; i < sizeof(sock_in->sin_addr.s_addr); i++) {
  94. *sp = toupper(*sp);
  95. if ((unsigned)(*sp - 'A') <= 5)
  96. bp[i] |= (int) (*sp - ('A' - 10));
  97. else if (isdigit(*sp))
  98. bp[i] |= (int) (*sp - '0');
  99. else
  100. return -1;
  101. bp[i] <<= 4;
  102. sp++;
  103. *sp = toupper(*sp);
  104. if ((unsigned)(*sp - 'A') <= 5)
  105. bp[i] |= (int) (*sp - ('A' - 10));
  106. else if (isdigit(*sp))
  107. bp[i] |= (int) (*sp - '0');
  108. else
  109. return -1;
  110. sp++;
  111. }
  112. sock_in->sin_addr.s_addr = htonl(val);
  113. return (sp - bufp);
  114. }
  115. #endif
  116. static int INET_input(/*int type,*/ const char *bufp, struct sockaddr *sap)
  117. {
  118. return INET_resolve(bufp, (struct sockaddr_in *) sap, 0);
  119. /*
  120. switch (type) {
  121. case 1:
  122. return (INET_getsock(bufp, sap));
  123. case 256:
  124. return (INET_resolve(bufp, (struct sockaddr_in *) sap, 1));
  125. default:
  126. return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0));
  127. }
  128. */
  129. }
  130. static const struct aftype inet_aftype = {
  131. .name = "inet",
  132. .title = "DARPA Internet",
  133. .af = AF_INET,
  134. .alen = 4,
  135. .sprint = INET_sprint,
  136. .input = INET_input,
  137. };
  138. #ifdef HAVE_AFINET6
  139. /* Display an Internet socket address. */
  140. /* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */
  141. static const char *INET6_sprint(struct sockaddr *sap, int numeric)
  142. {
  143. static char *buff;
  144. free(buff);
  145. if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
  146. return "[NONE SET]";
  147. buff = INET6_rresolve((struct sockaddr_in6 *) sap, numeric);
  148. return buff;
  149. }
  150. #ifdef UNUSED
  151. static int INET6_getsock(char *bufp, struct sockaddr *sap)
  152. {
  153. struct sockaddr_in6 *sin6;
  154. sin6 = (struct sockaddr_in6 *) sap;
  155. sin6->sin6_family = AF_INET6;
  156. sin6->sin6_port = 0;
  157. if (inet_pton(AF_INET6, bufp, sin6->sin6_addr.s6_addr) <= 0)
  158. return -1;
  159. return 16; /* ?;) */
  160. }
  161. #endif
  162. static int INET6_input(/*int type,*/ const char *bufp, struct sockaddr *sap)
  163. {
  164. return INET6_resolve(bufp, (struct sockaddr_in6 *) sap);
  165. /*
  166. switch (type) {
  167. case 1:
  168. return (INET6_getsock(bufp, sap));
  169. default:
  170. return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap));
  171. }
  172. */
  173. }
  174. static const struct aftype inet6_aftype = {
  175. .name = "inet6",
  176. .title = "IPv6",
  177. .af = AF_INET6,
  178. .alen = sizeof(struct in6_addr),
  179. .sprint = INET6_sprint,
  180. .input = INET6_input,
  181. };
  182. #endif /* HAVE_AFINET6 */
  183. /* Display an UNSPEC address. */
  184. static char *UNSPEC_print(unsigned char *ptr)
  185. {
  186. static char *buff;
  187. char *pos;
  188. unsigned int i;
  189. if (!buff);
  190. buff = xmalloc(sizeof(struct sockaddr) * 3 + 1);
  191. pos = buff;
  192. for (i = 0; i < sizeof(struct sockaddr); i++) {
  193. /* careful -- not every libc's sprintf returns # bytes written */
  194. sprintf(pos, "%02X-", (*ptr++ & 0377));
  195. pos += 3;
  196. }
  197. /* Erase trailing "-". Works as long as sizeof(struct sockaddr) != 0 */
  198. *--pos = '\0';
  199. return buff;
  200. }
  201. /* Display an UNSPEC socket address. */
  202. static const char *UNSPEC_sprint(struct sockaddr *sap, int numeric)
  203. {
  204. if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
  205. return "[NONE SET]";
  206. return UNSPEC_print((unsigned char *)sap->sa_data);
  207. }
  208. static const struct aftype unspec_aftype = {
  209. .name = "unspec",
  210. .title = "UNSPEC",
  211. .af = AF_UNSPEC,
  212. .alen = 0,
  213. .print = UNSPEC_print,
  214. .sprint = UNSPEC_sprint,
  215. };
  216. static const struct aftype *const aftypes[] = {
  217. &inet_aftype,
  218. #ifdef HAVE_AFINET6
  219. &inet6_aftype,
  220. #endif
  221. &unspec_aftype,
  222. NULL
  223. };
  224. /* Check our protocol family table for this family. */
  225. const struct aftype *get_aftype(const char *name)
  226. {
  227. const struct aftype *const *afp;
  228. afp = aftypes;
  229. while (*afp != NULL) {
  230. if (!strcmp((*afp)->name, name))
  231. return (*afp);
  232. afp++;
  233. }
  234. return NULL;
  235. }
  236. /* Check our protocol family table for this family. */
  237. static const struct aftype *get_afntype(int af)
  238. {
  239. const struct aftype *const *afp;
  240. afp = aftypes;
  241. while (*afp != NULL) {
  242. if ((*afp)->af == af)
  243. return *afp;
  244. afp++;
  245. }
  246. return NULL;
  247. }
  248. struct user_net_device_stats {
  249. unsigned long long rx_packets; /* total packets received */
  250. unsigned long long tx_packets; /* total packets transmitted */
  251. unsigned long long rx_bytes; /* total bytes received */
  252. unsigned long long tx_bytes; /* total bytes transmitted */
  253. unsigned long rx_errors; /* bad packets received */
  254. unsigned long tx_errors; /* packet transmit problems */
  255. unsigned long rx_dropped; /* no space in linux buffers */
  256. unsigned long tx_dropped; /* no space available in linux */
  257. unsigned long rx_multicast; /* multicast packets received */
  258. unsigned long rx_compressed;
  259. unsigned long tx_compressed;
  260. unsigned long collisions;
  261. /* detailed rx_errors: */
  262. unsigned long rx_length_errors;
  263. unsigned long rx_over_errors; /* receiver ring buff overflow */
  264. unsigned long rx_crc_errors; /* recved pkt with crc error */
  265. unsigned long rx_frame_errors; /* recv'd frame alignment error */
  266. unsigned long rx_fifo_errors; /* recv'r fifo overrun */
  267. unsigned long rx_missed_errors; /* receiver missed packet */
  268. /* detailed tx_errors */
  269. unsigned long tx_aborted_errors;
  270. unsigned long tx_carrier_errors;
  271. unsigned long tx_fifo_errors;
  272. unsigned long tx_heartbeat_errors;
  273. unsigned long tx_window_errors;
  274. };
  275. struct interface {
  276. struct interface *next, *prev;
  277. char name[IFNAMSIZ]; /* interface name */
  278. short type; /* if type */
  279. short flags; /* various flags */
  280. int metric; /* routing metric */
  281. int mtu; /* MTU value */
  282. int tx_queue_len; /* transmit queue length */
  283. struct ifmap map; /* hardware setup */
  284. struct sockaddr addr; /* IP address */
  285. struct sockaddr dstaddr; /* P-P IP address */
  286. struct sockaddr broadaddr; /* IP broadcast address */
  287. struct sockaddr netmask; /* IP network mask */
  288. int has_ip;
  289. char hwaddr[32]; /* HW address */
  290. int statistics_valid;
  291. struct user_net_device_stats stats; /* statistics */
  292. int keepalive; /* keepalive value for SLIP */
  293. int outfill; /* outfill value for SLIP */
  294. };
  295. smallint interface_opt_a; /* show all interfaces */
  296. static struct interface *int_list, *int_last;
  297. #if 0
  298. /* like strcmp(), but knows about numbers */
  299. except that the freshly added calls to xatoul() brf on ethernet aliases with
  300. uClibc with e.g.: ife->name='lo' name='eth0:1'
  301. static int nstrcmp(const char *a, const char *b)
  302. {
  303. const char *a_ptr = a;
  304. const char *b_ptr = b;
  305. while (*a == *b) {
  306. if (*a == '\0') {
  307. return 0;
  308. }
  309. if (!isdigit(*a) && isdigit(*(a+1))) {
  310. a_ptr = a+1;
  311. b_ptr = b+1;
  312. }
  313. a++;
  314. b++;
  315. }
  316. if (isdigit(*a) && isdigit(*b)) {
  317. return xatoul(a_ptr) > xatoul(b_ptr) ? 1 : -1;
  318. }
  319. return *a - *b;
  320. }
  321. #endif
  322. static struct interface *add_interface(char *name)
  323. {
  324. struct interface *ife, **nextp, *new;
  325. for (ife = int_last; ife; ife = ife->prev) {
  326. int n = /*n*/strcmp(ife->name, name);
  327. if (n == 0)
  328. return ife;
  329. if (n < 0)
  330. break;
  331. }
  332. new = xzalloc(sizeof(*new));
  333. safe_strncpy(new->name, name, IFNAMSIZ);
  334. nextp = ife ? &ife->next : &int_list;
  335. new->prev = ife;
  336. new->next = *nextp;
  337. if (new->next)
  338. new->next->prev = new;
  339. else
  340. int_last = new;
  341. *nextp = new;
  342. return new;
  343. }
  344. static char *get_name(char *name, char *p)
  345. {
  346. /* Extract <name> from nul-terminated p where p matches
  347. <name>: after leading whitespace.
  348. If match is not made, set name empty and return unchanged p */
  349. int namestart = 0, nameend = 0;
  350. while (isspace(p[namestart]))
  351. namestart++;
  352. nameend = namestart;
  353. while (p[nameend] && p[nameend] != ':' && !isspace(p[nameend]))
  354. nameend++;
  355. if (p[nameend] == ':') {
  356. if ((nameend - namestart) < IFNAMSIZ) {
  357. memcpy(name, &p[namestart], nameend - namestart);
  358. name[nameend - namestart] = '\0';
  359. p = &p[nameend];
  360. } else {
  361. /* Interface name too large */
  362. name[0] = '\0';
  363. }
  364. } else {
  365. /* trailing ':' not found - return empty */
  366. name[0] = '\0';
  367. }
  368. return p + 1;
  369. }
  370. /* If scanf supports size qualifiers for %n conversions, then we can
  371. * use a modified fmt that simply stores the position in the fields
  372. * having no associated fields in the proc string. Of course, we need
  373. * to zero them again when we're done. But that is smaller than the
  374. * old approach of multiple scanf occurrences with large numbers of
  375. * args. */
  376. /* static const char *const ss_fmt[] = { */
  377. /* "%lln%llu%lu%lu%lu%lu%ln%ln%lln%llu%lu%lu%lu%lu%lu", */
  378. /* "%llu%llu%lu%lu%lu%lu%ln%ln%llu%llu%lu%lu%lu%lu%lu", */
  379. /* "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu" */
  380. /* }; */
  381. /* Lie about the size of the int pointed to for %n. */
  382. #if INT_MAX == LONG_MAX
  383. static const char *const ss_fmt[] = {
  384. "%n%llu%u%u%u%u%n%n%n%llu%u%u%u%u%u",
  385. "%llu%llu%u%u%u%u%n%n%llu%llu%u%u%u%u%u",
  386. "%llu%llu%u%u%u%u%u%u%llu%llu%u%u%u%u%u%u"
  387. };
  388. #else
  389. static const char *const ss_fmt[] = {
  390. "%n%llu%lu%lu%lu%lu%n%n%n%llu%lu%lu%lu%lu%lu",
  391. "%llu%llu%lu%lu%lu%lu%n%n%llu%llu%lu%lu%lu%lu%lu",
  392. "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu"
  393. };
  394. #endif
  395. static void get_dev_fields(char *bp, struct interface *ife, int procnetdev_vsn)
  396. {
  397. memset(&ife->stats, 0, sizeof(struct user_net_device_stats));
  398. sscanf(bp, ss_fmt[procnetdev_vsn],
  399. &ife->stats.rx_bytes, /* missing for 0 */
  400. &ife->stats.rx_packets,
  401. &ife->stats.rx_errors,
  402. &ife->stats.rx_dropped,
  403. &ife->stats.rx_fifo_errors,
  404. &ife->stats.rx_frame_errors,
  405. &ife->stats.rx_compressed, /* missing for <= 1 */
  406. &ife->stats.rx_multicast, /* missing for <= 1 */
  407. &ife->stats.tx_bytes, /* missing for 0 */
  408. &ife->stats.tx_packets,
  409. &ife->stats.tx_errors,
  410. &ife->stats.tx_dropped,
  411. &ife->stats.tx_fifo_errors,
  412. &ife->stats.collisions,
  413. &ife->stats.tx_carrier_errors,
  414. &ife->stats.tx_compressed /* missing for <= 1 */
  415. );
  416. if (procnetdev_vsn <= 1) {
  417. if (procnetdev_vsn == 0) {
  418. ife->stats.rx_bytes = 0;
  419. ife->stats.tx_bytes = 0;
  420. }
  421. ife->stats.rx_multicast = 0;
  422. ife->stats.rx_compressed = 0;
  423. ife->stats.tx_compressed = 0;
  424. }
  425. }
  426. static inline int procnetdev_version(char *buf)
  427. {
  428. if (strstr(buf, "compressed"))
  429. return 2;
  430. if (strstr(buf, "bytes"))
  431. return 1;
  432. return 0;
  433. }
  434. static int if_readconf(void)
  435. {
  436. int numreqs = 30;
  437. struct ifconf ifc;
  438. struct ifreq *ifr;
  439. int n, err = -1;
  440. int skfd;
  441. ifc.ifc_buf = NULL;
  442. /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
  443. (as of 2.1.128) */
  444. skfd = socket(AF_INET, SOCK_DGRAM, 0);
  445. if (skfd < 0) {
  446. bb_perror_msg("error: no inet socket available");
  447. return -1;
  448. }
  449. for (;;) {
  450. ifc.ifc_len = sizeof(struct ifreq) * numreqs;
  451. ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);
  452. if (ioctl_or_warn(skfd, SIOCGIFCONF, &ifc) < 0) {
  453. goto out;
  454. }
  455. if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
  456. /* assume it overflowed and try again */
  457. numreqs += 10;
  458. continue;
  459. }
  460. break;
  461. }
  462. ifr = ifc.ifc_req;
  463. for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
  464. add_interface(ifr->ifr_name);
  465. ifr++;
  466. }
  467. err = 0;
  468. out:
  469. close(skfd);
  470. free(ifc.ifc_buf);
  471. return err;
  472. }
  473. static int if_readlist_proc(char *target)
  474. {
  475. static smallint proc_read;
  476. FILE *fh;
  477. char buf[512];
  478. struct interface *ife;
  479. int err, procnetdev_vsn;
  480. if (proc_read)
  481. return 0;
  482. if (!target)
  483. proc_read = 1;
  484. fh = fopen(_PATH_PROCNET_DEV, "r");
  485. if (!fh) {
  486. bb_perror_msg("warning: cannot open %s, limiting output", _PATH_PROCNET_DEV);
  487. return if_readconf();
  488. }
  489. fgets(buf, sizeof buf, fh); /* eat line */
  490. fgets(buf, sizeof buf, fh);
  491. procnetdev_vsn = procnetdev_version(buf);
  492. err = 0;
  493. while (fgets(buf, sizeof buf, fh)) {
  494. char *s, name[128];
  495. s = get_name(name, buf);
  496. ife = add_interface(name);
  497. get_dev_fields(s, ife, procnetdev_vsn);
  498. ife->statistics_valid = 1;
  499. if (target && !strcmp(target, name))
  500. break;
  501. }
  502. if (ferror(fh)) {
  503. bb_perror_msg(_PATH_PROCNET_DEV);
  504. err = -1;
  505. proc_read = 0;
  506. }
  507. fclose(fh);
  508. return err;
  509. }
  510. static int if_readlist(void)
  511. {
  512. int err = if_readlist_proc(NULL);
  513. /* Needed in order to get ethN:M aliases */
  514. if (!err)
  515. err = if_readconf();
  516. return err;
  517. }
  518. /* Fetch the interface configuration from the kernel. */
  519. static int if_fetch(struct interface *ife)
  520. {
  521. struct ifreq ifr;
  522. char *ifname = ife->name;
  523. int skfd;
  524. skfd = xsocket(AF_INET, SOCK_DGRAM, 0);
  525. strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
  526. if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
  527. close(skfd);
  528. return -1;
  529. }
  530. ife->flags = ifr.ifr_flags;
  531. strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
  532. memset(ife->hwaddr, 0, 32);
  533. if (ioctl(skfd, SIOCGIFHWADDR, &ifr) >= 0)
  534. memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
  535. ife->type = ifr.ifr_hwaddr.sa_family;
  536. strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
  537. ife->metric = 0;
  538. if (ioctl(skfd, SIOCGIFMETRIC, &ifr) >= 0)
  539. ife->metric = ifr.ifr_metric;
  540. strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
  541. ife->mtu = 0;
  542. if (ioctl(skfd, SIOCGIFMTU, &ifr) >= 0)
  543. ife->mtu = ifr.ifr_mtu;
  544. memset(&ife->map, 0, sizeof(struct ifmap));
  545. #ifdef SIOCGIFMAP
  546. strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
  547. if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0)
  548. ife->map = ifr.ifr_map;
  549. #endif
  550. #ifdef HAVE_TXQUEUELEN
  551. strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
  552. ife->tx_queue_len = -1; /* unknown value */
  553. if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) >= 0)
  554. ife->tx_queue_len = ifr.ifr_qlen;
  555. #else
  556. ife->tx_queue_len = -1; /* unknown value */
  557. #endif
  558. strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
  559. ifr.ifr_addr.sa_family = AF_INET;
  560. memset(&ife->addr, 0, sizeof(struct sockaddr));
  561. if (ioctl(skfd, SIOCGIFADDR, &ifr) == 0) {
  562. ife->has_ip = 1;
  563. ife->addr = ifr.ifr_addr;
  564. strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
  565. memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
  566. if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) >= 0)
  567. ife->dstaddr = ifr.ifr_dstaddr;
  568. strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
  569. memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
  570. if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) >= 0)
  571. ife->broadaddr = ifr.ifr_broadaddr;
  572. strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
  573. memset(&ife->netmask, 0, sizeof(struct sockaddr));
  574. if (ioctl(skfd, SIOCGIFNETMASK, &ifr) >= 0)
  575. ife->netmask = ifr.ifr_netmask;
  576. }
  577. close(skfd);
  578. return 0;
  579. }
  580. static int do_if_fetch(struct interface *ife)
  581. {
  582. if (if_fetch(ife) < 0) {
  583. const char *errmsg;
  584. if (errno == ENODEV) {
  585. /* Give better error message for this case. */
  586. errmsg = "Device not found";
  587. } else {
  588. errmsg = strerror(errno);
  589. }
  590. bb_error_msg("%s: error fetching interface information: %s",
  591. ife->name, errmsg);
  592. return -1;
  593. }
  594. return 0;
  595. }
  596. static const struct hwtype unspec_hwtype = {
  597. .name = "unspec",
  598. .title = "UNSPEC",
  599. .type = -1,
  600. .print = UNSPEC_print
  601. };
  602. static const struct hwtype loop_hwtype = {
  603. .name = "loop",
  604. .title = "Local Loopback",
  605. .type = ARPHRD_LOOPBACK
  606. };
  607. #include <net/if_arp.h>
  608. #if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined(_NEWLIB_VERSION)
  609. #include <net/ethernet.h>
  610. #else
  611. #include <linux/if_ether.h>
  612. #endif
  613. /* Display an Ethernet address in readable format. */
  614. static char *pr_ether(unsigned char *ptr)
  615. {
  616. static char *buff;
  617. free(buff);
  618. buff = xasprintf("%02X:%02X:%02X:%02X:%02X:%02X",
  619. (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377),
  620. (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)
  621. );
  622. return buff;
  623. }
  624. static int in_ether(const char *bufp, struct sockaddr *sap);
  625. static const struct hwtype ether_hwtype = {
  626. .name = "ether",
  627. .title = "Ethernet",
  628. .type = ARPHRD_ETHER,
  629. .alen = ETH_ALEN,
  630. .print = pr_ether,
  631. .input = in_ether
  632. };
  633. static unsigned hexchar2int(char c)
  634. {
  635. if (isdigit(c))
  636. return c - '0';
  637. c &= ~0x20; /* a -> A */
  638. if ((unsigned)(c - 'A') <= 5)
  639. return c - ('A' - 10);
  640. return ~0U;
  641. }
  642. /* Input an Ethernet address and convert to binary. */
  643. static int in_ether(const char *bufp, struct sockaddr *sap)
  644. {
  645. unsigned char *ptr;
  646. char c;
  647. int i;
  648. unsigned val;
  649. sap->sa_family = ether_hwtype.type;
  650. ptr = (unsigned char*) sap->sa_data;
  651. i = 0;
  652. while ((*bufp != '\0') && (i < ETH_ALEN)) {
  653. val = hexchar2int(*bufp++) * 0x10;
  654. if (val > 0xff) {
  655. errno = EINVAL;
  656. return -1;
  657. }
  658. c = *bufp;
  659. if (c == ':' || c == 0)
  660. val >>= 4;
  661. else {
  662. val |= hexchar2int(c);
  663. if (val > 0xff) {
  664. errno = EINVAL;
  665. return -1;
  666. }
  667. }
  668. if (c != 0)
  669. bufp++;
  670. *ptr++ = (unsigned char) val;
  671. i++;
  672. /* We might get a semicolon here - not required. */
  673. if (*bufp == ':') {
  674. bufp++;
  675. }
  676. }
  677. return 0;
  678. }
  679. #include <net/if_arp.h>
  680. static const struct hwtype ppp_hwtype = {
  681. .name = "ppp",
  682. .title = "Point-to-Point Protocol",
  683. .type = ARPHRD_PPP
  684. };
  685. #if ENABLE_FEATURE_IPV6
  686. static const struct hwtype sit_hwtype = {
  687. .name = "sit",
  688. .title = "IPv6-in-IPv4",
  689. .type = ARPHRD_SIT,
  690. .print = UNSPEC_print,
  691. .suppress_null_addr = 1
  692. };
  693. #endif
  694. static const struct hwtype *const hwtypes[] = {
  695. &loop_hwtype,
  696. &ether_hwtype,
  697. &ppp_hwtype,
  698. &unspec_hwtype,
  699. #if ENABLE_FEATURE_IPV6
  700. &sit_hwtype,
  701. #endif
  702. NULL
  703. };
  704. #ifdef IFF_PORTSEL
  705. static const char *const if_port_text[] = {
  706. /* Keep in step with <linux/netdevice.h> */
  707. "unknown",
  708. "10base2",
  709. "10baseT",
  710. "AUI",
  711. "100baseT",
  712. "100baseTX",
  713. "100baseFX",
  714. NULL
  715. };
  716. #endif
  717. /* Check our hardware type table for this type. */
  718. const struct hwtype *get_hwtype(const char *name)
  719. {
  720. const struct hwtype *const *hwp;
  721. hwp = hwtypes;
  722. while (*hwp != NULL) {
  723. if (!strcmp((*hwp)->name, name))
  724. return (*hwp);
  725. hwp++;
  726. }
  727. return NULL;
  728. }
  729. /* Check our hardware type table for this type. */
  730. const struct hwtype *get_hwntype(int type)
  731. {
  732. const struct hwtype *const *hwp;
  733. hwp = hwtypes;
  734. while (*hwp != NULL) {
  735. if ((*hwp)->type == type)
  736. return *hwp;
  737. hwp++;
  738. }
  739. return NULL;
  740. }
  741. /* return 1 if address is all zeros */
  742. static int hw_null_address(const struct hwtype *hw, void *ap)
  743. {
  744. unsigned int i;
  745. unsigned char *address = (unsigned char *) ap;
  746. for (i = 0; i < hw->alen; i++)
  747. if (address[i])
  748. return 0;
  749. return 1;
  750. }
  751. static const char TRext[] ALIGN1 = "\0\0\0Ki\0Mi\0Gi\0Ti";
  752. static void print_bytes_scaled(unsigned long long ull, const char *end)
  753. {
  754. unsigned long long int_part;
  755. const char *ext;
  756. unsigned int frac_part;
  757. int i;
  758. frac_part = 0;
  759. ext = TRext;
  760. int_part = ull;
  761. i = 4;
  762. do {
  763. if (int_part >= 1024) {
  764. frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
  765. int_part /= 1024;
  766. ext += 3; /* KiB, MiB, GiB, TiB */
  767. }
  768. --i;
  769. } while (i);
  770. printf("X bytes:%llu (%llu.%u %sB)%s", ull, int_part, frac_part, ext, end);
  771. }
  772. static void ife_print(struct interface *ptr)
  773. {
  774. const struct aftype *ap;
  775. const struct hwtype *hw;
  776. int hf;
  777. int can_compress = 0;
  778. #ifdef HAVE_AFINET6
  779. FILE *f;
  780. char addr6[40], devname[20];
  781. struct sockaddr_in6 sap;
  782. int plen, scope, dad_status, if_idx;
  783. char addr6p[8][5];
  784. #endif
  785. ap = get_afntype(ptr->addr.sa_family);
  786. if (ap == NULL)
  787. ap = get_afntype(0);
  788. hf = ptr->type;
  789. if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
  790. can_compress = 1;
  791. hw = get_hwntype(hf);
  792. if (hw == NULL)
  793. hw = get_hwntype(-1);
  794. printf("%-9.9s Link encap:%s ", ptr->name, hw->title);
  795. /* For some hardware types (eg Ash, ATM) we don't print the
  796. hardware address if it's null. */
  797. if (hw->print != NULL && (!(hw_null_address(hw, ptr->hwaddr) &&
  798. hw->suppress_null_addr)))
  799. printf("HWaddr %s ", hw->print((unsigned char *)ptr->hwaddr));
  800. #ifdef IFF_PORTSEL
  801. if (ptr->flags & IFF_PORTSEL) {
  802. printf("Media:%s", if_port_text[ptr->map.port] /* [0] */);
  803. if (ptr->flags & IFF_AUTOMEDIA)
  804. printf("(auto)");
  805. }
  806. #endif
  807. bb_putchar('\n');
  808. if (ptr->has_ip) {
  809. printf(" %s addr:%s ", ap->name,
  810. ap->sprint(&ptr->addr, 1));
  811. if (ptr->flags & IFF_POINTOPOINT) {
  812. printf(" P-t-P:%s ", ap->sprint(&ptr->dstaddr, 1));
  813. }
  814. if (ptr->flags & IFF_BROADCAST) {
  815. printf(" Bcast:%s ", ap->sprint(&ptr->broadaddr, 1));
  816. }
  817. printf(" Mask:%s\n", ap->sprint(&ptr->netmask, 1));
  818. }
  819. #ifdef HAVE_AFINET6
  820. #define IPV6_ADDR_ANY 0x0000U
  821. #define IPV6_ADDR_UNICAST 0x0001U
  822. #define IPV6_ADDR_MULTICAST 0x0002U
  823. #define IPV6_ADDR_ANYCAST 0x0004U
  824. #define IPV6_ADDR_LOOPBACK 0x0010U
  825. #define IPV6_ADDR_LINKLOCAL 0x0020U
  826. #define IPV6_ADDR_SITELOCAL 0x0040U
  827. #define IPV6_ADDR_COMPATv4 0x0080U
  828. #define IPV6_ADDR_SCOPE_MASK 0x00f0U
  829. #define IPV6_ADDR_MAPPED 0x1000U
  830. #define IPV6_ADDR_RESERVED 0x2000U /* reserved address space */
  831. f = fopen(_PATH_PROCNET_IFINET6, "r");
  832. if (f != NULL) {
  833. while (fscanf
  834. (f, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n",
  835. addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
  836. addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope,
  837. &dad_status, devname) != EOF
  838. ) {
  839. if (!strcmp(devname, ptr->name)) {
  840. sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
  841. addr6p[0], addr6p[1], addr6p[2], addr6p[3],
  842. addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
  843. inet_pton(AF_INET6, addr6,
  844. (struct sockaddr *) &sap.sin6_addr);
  845. sap.sin6_family = AF_INET6;
  846. printf(" inet6 addr: %s/%d",
  847. INET6_sprint((struct sockaddr *) &sap, 1),
  848. plen);
  849. printf(" Scope:");
  850. switch (scope & IPV6_ADDR_SCOPE_MASK) {
  851. case 0:
  852. puts("Global");
  853. break;
  854. case IPV6_ADDR_LINKLOCAL:
  855. puts("Link");
  856. break;
  857. case IPV6_ADDR_SITELOCAL:
  858. puts("Site");
  859. break;
  860. case IPV6_ADDR_COMPATv4:
  861. puts("Compat");
  862. break;
  863. case IPV6_ADDR_LOOPBACK:
  864. puts("Host");
  865. break;
  866. default:
  867. puts("Unknown");
  868. }
  869. }
  870. }
  871. fclose(f);
  872. }
  873. #endif
  874. printf(" ");
  875. /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
  876. if (ptr->flags == 0) {
  877. printf("[NO FLAGS] ");
  878. } else {
  879. static const char ife_print_flags_strs[] ALIGN1 =
  880. "UP\0"
  881. "BROADCAST\0"
  882. "DEBUG\0"
  883. "LOOPBACK\0"
  884. "POINTOPOINT\0"
  885. "NOTRAILERS\0"
  886. "RUNNING\0"
  887. "NOARP\0"
  888. "PROMISC\0"
  889. "ALLMULTI\0"
  890. "SLAVE\0"
  891. "MASTER\0"
  892. "MULTICAST\0"
  893. #ifdef HAVE_DYNAMIC
  894. "DYNAMIC\0"
  895. #endif
  896. ;
  897. static const unsigned short ife_print_flags_mask[] ALIGN2 = {
  898. IFF_UP,
  899. IFF_BROADCAST,
  900. IFF_DEBUG,
  901. IFF_LOOPBACK,
  902. IFF_POINTOPOINT,
  903. IFF_NOTRAILERS,
  904. IFF_RUNNING,
  905. IFF_NOARP,
  906. IFF_PROMISC,
  907. IFF_ALLMULTI,
  908. IFF_SLAVE,
  909. IFF_MASTER,
  910. IFF_MULTICAST
  911. #ifdef HAVE_DYNAMIC
  912. ,IFF_DYNAMIC
  913. #endif
  914. };
  915. const unsigned short *mask = ife_print_flags_mask;
  916. const char *str = ife_print_flags_strs;
  917. do {
  918. if (ptr->flags & *mask) {
  919. printf("%s ", str);
  920. }
  921. mask++;
  922. str += strlen(str) + 1;
  923. } while (*str);
  924. }
  925. /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
  926. printf(" MTU:%d Metric:%d", ptr->mtu, ptr->metric ? ptr->metric : 1);
  927. #ifdef SIOCSKEEPALIVE
  928. if (ptr->outfill || ptr->keepalive)
  929. printf(" Outfill:%d Keepalive:%d", ptr->outfill, ptr->keepalive);
  930. #endif
  931. bb_putchar('\n');
  932. /* If needed, display the interface statistics. */
  933. if (ptr->statistics_valid) {
  934. /* XXX: statistics are currently only printed for the primary address,
  935. * not for the aliases, although strictly speaking they're shared
  936. * by all addresses.
  937. */
  938. printf(" ");
  939. printf("RX packets:%llu errors:%lu dropped:%lu overruns:%lu frame:%lu\n",
  940. ptr->stats.rx_packets, ptr->stats.rx_errors,
  941. ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors,
  942. ptr->stats.rx_frame_errors);
  943. if (can_compress)
  944. printf(" compressed:%lu\n",
  945. ptr->stats.rx_compressed);
  946. printf(" ");
  947. printf("TX packets:%llu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n",
  948. ptr->stats.tx_packets, ptr->stats.tx_errors,
  949. ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
  950. ptr->stats.tx_carrier_errors);
  951. printf(" collisions:%lu ", ptr->stats.collisions);
  952. if (can_compress)
  953. printf("compressed:%lu ", ptr->stats.tx_compressed);
  954. if (ptr->tx_queue_len != -1)
  955. printf("txqueuelen:%d ", ptr->tx_queue_len);
  956. printf("\n R");
  957. print_bytes_scaled(ptr->stats.rx_bytes, " T");
  958. print_bytes_scaled(ptr->stats.tx_bytes, "\n");
  959. }
  960. if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
  961. ptr->map.base_addr)) {
  962. printf(" ");
  963. if (ptr->map.irq)
  964. printf("Interrupt:%d ", ptr->map.irq);
  965. if (ptr->map.base_addr >= 0x100) /* Only print devices using it for
  966. I/O maps */
  967. printf("Base address:0x%lx ",
  968. (unsigned long) ptr->map.base_addr);
  969. if (ptr->map.mem_start) {
  970. printf("Memory:%lx-%lx ", ptr->map.mem_start,
  971. ptr->map.mem_end);
  972. }
  973. if (ptr->map.dma)
  974. printf("DMA chan:%x ", ptr->map.dma);
  975. bb_putchar('\n');
  976. }
  977. bb_putchar('\n');
  978. }
  979. static int do_if_print(struct interface *ife) /*, int *opt_a)*/
  980. {
  981. int res;
  982. res = do_if_fetch(ife);
  983. if (res >= 0) {
  984. if ((ife->flags & IFF_UP) || interface_opt_a)
  985. ife_print(ife);
  986. }
  987. return res;
  988. }
  989. static struct interface *lookup_interface(char *name)
  990. {
  991. struct interface *ife = NULL;
  992. if (if_readlist_proc(name) < 0)
  993. return NULL;
  994. ife = add_interface(name);
  995. return ife;
  996. }
  997. #ifdef UNUSED
  998. static int for_all_interfaces(int (*doit) (struct interface *, void *),
  999. void *cookie)
  1000. {
  1001. struct interface *ife;
  1002. if (!int_list && (if_readlist() < 0))
  1003. return -1;
  1004. for (ife = int_list; ife; ife = ife->next) {
  1005. int err = doit(ife, cookie);
  1006. if (err)
  1007. return err;
  1008. }
  1009. return 0;
  1010. }
  1011. #endif
  1012. /* for ipv4 add/del modes */
  1013. static int if_print(char *ifname)
  1014. {
  1015. struct interface *ife;
  1016. int res;
  1017. if (!ifname) {
  1018. /*res = for_all_interfaces(do_if_print, &interface_opt_a);*/
  1019. if (!int_list && (if_readlist() < 0))
  1020. return -1;
  1021. for (ife = int_list; ife; ife = ife->next) {
  1022. int err = do_if_print(ife); /*, &interface_opt_a);*/
  1023. if (err)
  1024. return err;
  1025. }
  1026. return 0;
  1027. }
  1028. ife = lookup_interface(ifname);
  1029. res = do_if_fetch(ife);
  1030. if (res >= 0)
  1031. ife_print(ife);
  1032. return res;
  1033. }
  1034. int display_interfaces(char *ifname)
  1035. {
  1036. int status;
  1037. status = if_print(ifname);
  1038. return (status < 0); /* status < 0 == 1 -- error */
  1039. }