/
niceSOFT
/
inetutils
Обзор
Документация
Войти
/
niceSOFT
/
inetutils
Код
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
ifconfig/system/linux.c
992 строки
24 KB
Simon Josefsson
maint: Run 'make update-copyright'
20 янв 2026, 11:50
Не верифицирован
20 янв 2026, 11:50
1ce61cd
Код
Авторство
О чём код?
/* linux.c -- Linux specific code for ifconfig Copyright (C) 2001-2026 Free Software Foundation, Inc. This file is part of GNU Inetutils. GNU Inetutils is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GNU Inetutils is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see `http://www.gnu.org/licenses/'. */ /* Written by Marcus Brinkmann. */ #include <config.h> #include <sys/stat.h> #include <stdio.h> #include <errno.h> #include <xalloc.h> #include <unistd.h> #include <string.h> #if STDC_HEADERS # include <stdlib.h> #else # ifndef HAVE_STRCHR # define strchr index # define strrchr rindex # endif #endif #include <sys/ioctl.h> #include <net/if.h> #include <net/if_arp.h> #ifdef HAVE_NETINET_ETHER_H # include <netinet/ether.h> #endif #include <read-file.h> #include <attribute.h> #include "../ifconfig.h" /* ARPHRD stuff. */ static void print_hwaddr_ether (format_data_t form MAYBE_UNUSED, unsigned char *data) { *column += printf ("%02X:%02X:%02X:%02X:%02X:%02X", data[0], data[1], data[2], data[3], data[4], data[5]); had_output = 1; } static void print_hwaddr_arcnet (format_data_t form MAYBE_UNUSED, unsigned char *data) { *column += printf ("%02X", data[0]); had_output = 1; } static void print_hwaddr_dlci (format_data_t form MAYBE_UNUSED, unsigned char *data) { *column += printf ("%i", *((short *) data)); had_output = 1; } static void print_hwaddr_ax25 (format_data_t form, unsigned char *data) { int i = 0; while (i < 6 && (data[i] >> 1) != ' ') { put_char (form, (data[i] >> 1)); i++; } i = (data[6] & 0x1E) >> 1; if (i) { *column += printf ("-%i", i); had_output = 1; } #undef mangle } static void print_hwaddr_irda (format_data_t form MAYBE_UNUSED, unsigned char *data) { *column += printf ("%02X:%02X:%02X:%02X", data[3], data[2], data[1], data[0]); had_output = 1; } static void print_hwaddr_rose (format_data_t form MAYBE_UNUSED, unsigned char *data) { *column += printf ("%02X%02X%02X%02X%02X", data[0], data[1], data[2], data[3], data[4]); had_output = 1; } struct arphrd_symbol { const char *name; const char *title; int value; void (*print_hwaddr) (format_data_t form, unsigned char *data); } arphrd_symbols[] = { /* ARP protocol HARDWARE identifiers. */ #ifdef ARPHRD_NETROM /* From KA9Q: NET/ROM pseudo. */ {"NETROM", "AMPR NET/ROM", ARPHRD_NETROM, print_hwaddr_ax25}, #endif #ifdef ARPHRD_ETHER /* Ethernet 10/100Mbps. */ {"ETHER", "Ethernet", ARPHRD_ETHER, print_hwaddr_ether}, #endif #ifdef ARPHRD_EETHER /* Experimental Ethernet. */ {"EETHER", "Experimental Etherner", ARPHRD_EETHER, NULL}, #endif #ifdef ARPHRD_AX25 /* AX.25 Level 2. */ {"AX25", "AMPR AX.25", ARPHRD_AX25, print_hwaddr_ax25}, #endif #ifdef ARPHRD_PRONET /* PROnet token ring. */ {"PRONET", "PROnet token ring", ARPHRD_PRONET, NULL}, #endif #ifdef ARPHRD_CHAOS /* Chaosnet. */ {"CHAOS", "Chaosnet", ARPHRD_CHAOS, NULL}, #endif #ifdef ARPHRD_IEEE802 /* IEEE 802.2 Ethernet/TR/TB. */ {"IEEE802", "16/4 Mbps Token Ring", ARPHRD_IEEE802, print_hwaddr_ether}, #endif #ifdef ARPHRD_ARCNET /* ARCnet. */ {"ARCNET", "ARCnet", ARPHRD_ARCNET, print_hwaddr_arcnet}, #endif #ifdef ARPHRD_APPLETLK /* APPLEtalk. */ {"APPLETLK", "Appletalk", ARPHRD_APPLETLK, NULL}, #endif #ifdef ARPHRD_DLCI /* Frame Relay DLCI. */ {"DLCI", "Frame Relay DLCI", ARPHRD_DLCI, print_hwaddr_dlci}, #endif #ifdef ARPHRD_ATM /* ATM. */ {"ATM", "ATM", ARPHRD_ATM, NULL}, #endif #ifdef ARPHRD_METRICOM /* Metricom STRIP (new IANA id). */ {"METRICOM", "Metricom STRIP", ARPHRD_METRICOM, NULL}, #endif /* Dummy types for non ARP hardware. */ #ifdef ARPHRD_SLIP {"SLIP", "Serial Line IP", ARPHRD_SLIP, NULL}, #endif #ifdef ARPHRD_CSLIP {"CSLIP", "VJ Serial Line IP", ARPHRD_CSLIP, NULL}, #endif #ifdef ARPHRD_SLIP6 {"SLIP6", "6-bit Serial Line IP", ARPHRD_SLIP6, NULL}, #endif #ifdef ARPHRD_CSLIP6 {"CSLIP6", "VJ 6-bit Serial Line IP", ARPHRD_CSLIP6, NULL}, #endif #ifdef ARPHRD_RSRVD /* Notional KISS type. */ {"SLIP", "Notional KISS type", ARPHRD_SLIP, NULL}, #endif #ifdef ARPHRD_ADAPT {"ADAPT", "Adaptive Serial Line IP", ARPHRD_ADAPT, NULL}, #endif #ifdef ARPHRD_ROSE {"ROSE", "AMPR ROSE", ARPHRD_ROSE, print_hwaddr_rose}, #endif #ifdef ARPHRD_X25 /* CCITT X.25. */ {"X25", "CCITT X.25", ARPHRD_X25, NULL}, #endif #ifdef ARPHRD_HWX25 /* Boards with X.25 in firmware. */ {"HWX25", "CCITT X.25 in firmware", ARPHRD_HWX25, NULL}, #endif #ifdef ARPHRD_PPP {"PPP", "Point-to-Point Protocol", ARPHRD_PPP, NULL}, #endif #ifdef ARPHRD_HDLC /* (Cisco) HDLC. */ {"HDLC", "(Cisco)-HDLC", ARPHRD_HDLC, NULL}, #endif #ifdef ARPHRD_LAPB /* LAPB. */ {"LAPB", "LAPB", ARPHRD_LAPB, NULL}, #endif #ifdef ARPHRD_DDCMP /* Digital's DDCMP. */ {"DDCMP", "DDCMP", ARPHRD_DDCMP, NULL}, #endif #ifdef ARPHRD_TUNNEL /* IPIP tunnel. */ {"TUNNEL", "IPIP Tunnel", ARPHRD_TUNNEL, NULL}, #endif #ifdef ARPHRD_TUNNEL6 /* IPIP6 tunnel. */ {"TUNNEL", "IPIP6 Tunnel", ARPHRD_TUNNEL6, NULL}, #endif #ifdef ARPHRD_FRAD /* Frame Relay Access Device. */ {"FRAD", "Frame Relay Access Device", ARPHRD_FRAD, NULL}, #endif #ifdef ARPHRD_SKIP /* SKIP vif. */ {"SKIP", "SKIP vif", ARPHRD_SKIP, NULL}, #endif #ifdef ARPHRD_LOOPBACK /* Loopback device. */ {"LOOPBACK", "Local Loopback", ARPHRD_LOOPBACK, NULL}, #endif #ifdef ARPHRD_LOCALTALK /* Localtalk device. */ {"LOCALTALK", "Localtalk", ARPHRD_LOCALTALK, NULL}, #endif #ifdef ARPHRD_FDDI /* Fiber Distributed Data Interface. */ {"FDDI", "Fiber Distributed Data Interface", ARPHRD_FDDI, NULL}, #endif #ifdef ARPHRD_BIF /* AP1000 BIF. */ {"BIF", "AP1000 BIF", ARPHRD_BIF, NULL}, #endif #ifdef ARPHRD_SIT /* sit0 device - IPv6-in-IPv4. */ {"SIT", "IPv6-in-IPv4", ARPHRD_SIT, NULL}, #endif #ifdef ARPHRD_IPDDP /* IP-in-DDP tunnel. */ {"IPDDP", "IP-in-DDP", ARPHRD_IPDDP, NULL}, #endif #ifdef ARPHRD_IPGRE /* GRE over IP. */ {"IPGRE", "GRE over IP", ARPHRD_IPGRE, NULL}, #endif #ifdef ARPHRD_PIMREG /* PIMSM register interface. */ {"PIMREG", "PIMSM register", ARPHRD_PIMREG, NULL}, #endif #ifdef ARPHRD_HIPPI /* High Performance Parallel I'face. */ {"HIPPI", "HIPPI", ARPHRD_HIPPI, print_hwaddr_ether}, #endif #ifdef ARPHRD_ASH /* (Nexus Electronics) Ash. */ {"ASH", "Ash", ARPHRD_ASH, NULL}, #endif #ifdef ARPHRD_ECONET /* Acorn Econet. */ {"ECONET", "Econet", ARPHRD_ECONET, NULL}, #endif #ifdef ARPHRD_IRDA /* Linux-IrDA. */ {"IRDA", "IrLap", ARPHRD_IRDA, print_hwaddr_irda}, #endif #ifdef ARPHRD_FCPP /* Point to point fibrechanel. */ {"FCPP", "FCPP", ARPHRD_FCPP, NULL}, #endif #ifdef ARPHRD_FCAL /* Fibrechanel arbitrated loop. */ {"FCAL", "FCAL", ARPHRD_FCAL, NULL}, #endif #ifdef ARPHRD_FCPL /* Fibrechanel public loop. */ {"FCPL", "FCPL", ARPHRD_FCPL, NULL}, #endif #ifdef ARPHRD_FCPFABRIC /* Fibrechanel fabric. */ {"FCFABRIC", "FCFABRIC", ARPHRD_FCPFABRIC, NULL}, #endif #ifdef ARPHRD_IEEE802_TR /* Magic type ident for TR. */ {"IEEE802_TR", "16/4 Mbps Token Ring (New)", ARPHRD_IEEE802_TR, print_hwaddr_ether}, #endif #ifdef ARPHRD_VOID {"VOID", "Void (nothing is known)", ARPHRD_VOID, NULL}, #endif }; struct arphrd_symbol * arphrd_findvalue (int value) { struct arphrd_symbol *arp = arphrd_symbols; while (arp->name != NULL) { if (arp->value == value) break; arp++; } if (arp->name) return arp; else return NULL; } struct pnd_stats { struct pnd_stats *next; char *name; unsigned long long rx_packets; /* total packets received */ unsigned long long tx_packets; /* total packets transmitted */ unsigned long long rx_bytes; /* total bytes received */ unsigned long long tx_bytes; /* total bytes transmitted */ unsigned long rx_errors; /* packets receive errors */ unsigned long tx_errors; /* packet transmit errors */ unsigned long rx_dropped; /* input packets dropped */ unsigned long tx_dropped; /* transmit packets dropped */ unsigned long rx_multicast; /* multicast packets received */ unsigned long rx_compressed; /* compressed packets received */ unsigned long tx_compressed; /* compressed packets transmitted */ unsigned long collisions; /* detailed rx_errors: */ unsigned long rx_length_errors; unsigned long rx_over_errors; /* receiver ring buffer overflow */ unsigned long rx_crc_errors; /* received packets with crc error */ unsigned long rx_frame_errors; /* received frame alignment errors */ unsigned long rx_fifo_errors; /* recveiver fifo overruns */ unsigned long rx_missed_errors; /* receiver missed packets */ /* detailed tx_errors */ unsigned long tx_aborted_errors; unsigned long tx_carrier_errors; unsigned long tx_fifo_errors; unsigned long tx_heartbeat_errors; unsigned long tx_window_errors; }; struct pnd_stats *stats_head, *stats_tail; static int pnd_stats_init = 0; static int procnet_parse_fields_v1 (char *buf, struct pnd_stats *stats) { int n = sscanf (buf, "%llu %lu %lu %lu %lu %llu %lu %lu %lu %lu %lu", &stats->rx_packets, &stats->rx_errors, &stats->rx_dropped, &stats->rx_fifo_errors, &stats->rx_frame_errors, &stats->tx_packets, &stats->tx_errors, &stats->tx_dropped, &stats->tx_fifo_errors, &stats->collisions, &stats->tx_carrier_errors); stats->rx_bytes = 0; stats->tx_bytes = 0; stats->rx_multicast = 0; return n == 11; } static int procnet_parse_fields_v2 (char *buf, struct pnd_stats *stats) { int n = sscanf (buf, "%llu %llu %lu %lu %lu %lu %llu %llu %lu %lu %lu %lu %lu", &stats->rx_bytes, &stats->rx_packets, &stats->rx_errors, &stats->rx_dropped, &stats->rx_fifo_errors, &stats->rx_frame_errors, &stats->tx_bytes, &stats->tx_packets, &stats->tx_errors, &stats->tx_dropped, &stats->tx_fifo_errors, &stats->collisions, &stats->tx_carrier_errors); stats->rx_multicast = 0; return n == 13; } static int procnet_parse_fields_v3 (char *buf, struct pnd_stats *stats) { int n = sscanf (buf, "%llu %llu %lu %lu %lu %lu %lu %lu %llu %llu %lu %lu %lu %lu %lu %lu", &stats->rx_bytes, &stats->rx_packets, &stats->rx_errors, &stats->rx_dropped, &stats->rx_fifo_errors, &stats->rx_frame_errors, &stats->rx_compressed, &stats->rx_multicast, &stats->tx_bytes, &stats->tx_packets, &stats->tx_errors, &stats->tx_dropped, &stats->tx_fifo_errors, &stats->collisions, &stats->tx_carrier_errors, &stats->tx_compressed); return n == 16; } static int (*pnd_parser[]) (char *, struct pnd_stats *) = { procnet_parse_fields_v1, procnet_parse_fields_v2, procnet_parse_fields_v3 }; static int pnd_version (char *buf) { if (strstr (buf, "compressed")) return 2; if (strstr (buf, "bytes")) return 1; return 0; } static void pnd_read (void) { FILE *fp; char *buf = NULL; size_t bufsize = 0; int v; fp = fopen (PATH_PROCNET_DEV, "r"); if (!fp) { error (0, errno, "cannot open %s", PATH_PROCNET_DEV); return; } /* Skip header lines */ if (getline (&buf, &bufsize, fp) < 0 || getline (&buf, &bufsize, fp) < 0) { error (0, errno, "malformed %s", PATH_PROCNET_DEV); fclose (fp); free (buf); return; } v = pnd_version (buf); while (getline (&buf, &bufsize, fp) > 0) { struct pnd_stats *stats = xzalloc (sizeof (*stats)); char *p = buf, *q; size_t len; while (*p && isascii (*(unsigned char *) p) && isspace (*(unsigned char *) p)) p++; q = strchr (p, ':'); if (!q) { error (0, errno, "malformed %s", PATH_PROCNET_DEV); free (stats); break; } len = q - p; stats->name = xmalloc (len + 1); memcpy (stats->name, p, len); stats->name[len] = 0; if (pnd_parser[v] (q + 1, stats) == 0) { error (0, errno, "malformed %s", PATH_PROCNET_DEV); free (stats); break; } stats->next = NULL; if (stats_tail) stats_tail->next = stats; else stats_head = stats; stats_tail = stats; } fclose (fp); free (buf); } struct pnd_stats * pnd_stats_locate (const char *name) { struct pnd_stats *stats; if (!pnd_stats_init) { pnd_read (); pnd_stats_init = 1; } for (stats = stats_head; stats; stats = stats->next) if (strcmp (stats->name, name) == 0) break; return stats; } /* Output format stuff. */ const char *system_default_format = "net-tools"; void system_fh_ifstat_query (format_data_t form, int argc, char *argv[]) { select_arg (form, argc, argv, pnd_stats_locate (form->ifr->ifr_name) ? 0 : 1); } #define _IU_DECLARE(fld) \ void \ _IU_CAT2 (system_fh_,fld) (format_data_t form, int argc, char *argv[]) \ { \ struct pnd_stats *stats = pnd_stats_locate (form->ifr->ifr_name); \ if (!stats) \ put_string (form, "(" #fld " unknown)"); \ else \ put_ulong (form, argc, argv, stats->fld); \ } _IU_DECLARE (rx_packets) _IU_DECLARE (tx_packets) _IU_DECLARE (rx_bytes) _IU_DECLARE (tx_bytes) _IU_DECLARE (rx_errors) _IU_DECLARE (tx_errors) _IU_DECLARE (rx_dropped) _IU_DECLARE (tx_dropped) _IU_DECLARE (rx_multicast) _IU_DECLARE (rx_compressed) _IU_DECLARE (tx_compressed) _IU_DECLARE (collisions) _IU_DECLARE (rx_length_errors) _IU_DECLARE (rx_over_errors) _IU_DECLARE (rx_crc_errors) _IU_DECLARE (rx_frame_errors) _IU_DECLARE (rx_fifo_errors) _IU_DECLARE (rx_missed_errors) _IU_DECLARE (tx_aborted_errors) _IU_DECLARE (tx_carrier_errors) _IU_DECLARE (tx_fifo_errors) _IU_DECLARE (tx_heartbeat_errors) _IU_DECLARE (tx_window_errors) void system_fh_hwaddr_query (format_data_t form, int argc, char *argv[]) { #ifdef SIOCGIFHWADDR struct arphrd_symbol *arp; if (ioctl (form->sfd, SIOCGIFHWADDR, form->ifr) < 0) select_arg (form, argc, argv, 1); arp = arphrd_findvalue (form->ifr->ifr_hwaddr.sa_family); select_arg (form, argc, argv, (arp && arp->print_hwaddr) ? 0 : 1); #else select_arg (form, argc, argv, 1); #endif } void system_fh_hwaddr (format_data_t form, int argc MAYBE_UNUSED, MAYBE_UNUSED char *argv[]) { #ifdef SIOCGIFHWADDR if (ioctl (form->sfd, SIOCGIFHWADDR, form->ifr) < 0) error (EXIT_FAILURE, errno, "SIOCGIFHWADDR failed for interface `%s'", form->ifr->ifr_name); else { struct arphrd_symbol *arp; arp = arphrd_findvalue (form->ifr->ifr_hwaddr.sa_family); if (arp && arp->print_hwaddr) arp->print_hwaddr (form, (unsigned char *) form->ifr->ifr_hwaddr.sa_data); else put_string (form, "(hwaddr unknown)"); } #else *column += printf ("(not available)"); had_output = 1; #endif } void system_fh_hwtype_query (format_data_t form, int argc, char *argv[]) { #ifdef SIOCGIFHWADDR if (ioctl (form->sfd, SIOCGIFHWADDR, form->ifr) >= 0) select_arg (form, argc, argv, 0); else #endif select_arg (form, argc, argv, 1); } void system_fh_hwtype (format_data_t form, int argc MAYBE_UNUSED, MAYBE_UNUSED char *argv[]) { #ifdef SIOCGIFHWADDR if (ioctl (form->sfd, SIOCGIFHWADDR, form->ifr) < 0) error (EXIT_FAILURE, errno, "SIOCGIFHWADDR failed for interface `%s'", form->ifr->ifr_name); else { struct arphrd_symbol *arp; arp = arphrd_findvalue (form->ifr->ifr_hwaddr.sa_family); if (arp) put_string (form, arp->title); else put_string (form, "(hwtype unknown)"); } #else *column += printf ("(not available)"); had_output = 1; #endif } /* Accept every value of metric as printable. The net-tools' * implementation of ifconfig displays metric 0 as `1', so we * aim at the same thing, even though all other unices disagree. */ void system_fh_metric_query (format_data_t form, int argc, char *argv[]) { #ifdef SIOCGIFMETRIC if (ioctl (form->sfd, SIOCGIFMETRIC, form->ifr) >= 0) select_arg (form, argc, argv, 0); else #endif select_arg (form, argc, argv, 1); } void system_fh_metric (format_data_t form, int argc, char *argv[]) { #ifdef SIOCGIFMETRIC if (ioctl (form->sfd, SIOCGIFMETRIC, form->ifr) < 0) error (EXIT_FAILURE, errno, "SIOCGIFMETRIC failed for interface `%s'", form->ifr->ifr_name); else put_int (form, argc, argv, form->ifr->ifr_metric ? form->ifr->ifr_metric : 1); #else *column += printf ("(not available)"); had_output = 1; #endif } void system_fh_txqlen_query (format_data_t form, int argc, char *argv[]) { #ifdef SIOCGIFTXQLEN if (ioctl (form->sfd, SIOCGIFTXQLEN, form->ifr) >= 0) select_arg (form, argc, argv, (form->ifr->ifr_qlen >= 0) ? 0 : 1); else #endif select_arg (form, argc, argv, 1); } void system_fh_txqlen (format_data_t form, int argc, char *argv[]) { #ifdef SIOCGIFTXQLEN if (ioctl (form->sfd, SIOCGIFTXQLEN, form->ifr) < 0) error (EXIT_FAILURE, errno, "SIOCGIFTXQLEN failed for interface `%s'", form->ifr->ifr_name); else put_int (form, argc, argv, form->ifr->ifr_qlen); #else *column += printf ("(not available)"); had_output = 1; #endif } /* Argument parsing stuff. */ const char *system_help = "\ NAME [ADDR] [broadcast BRDADDR]\ [pointopoint|dstaddr DSTADDR] [netmask MASK]\ [ether|hwaddr|lladdr MACADDR]\ [metric N] [mtu N] [txqueuelen N] [up|down] [FLAGS]"; void system_parse_opt_set_txqlen (struct ifconfig *ifp, char *arg) { char *end; if (!ifp) error (EXIT_FAILURE, 0, "no interface specified for txqlen `%s'", arg); if (!(ifp->valid & IF_VALID_SYSTEM)) { ifp->system = malloc (sizeof (struct system_ifconfig)); if (!ifp->system) error (EXIT_FAILURE, errno, "can't get memory for system interface configuration"); ifp->system->valid = 0; ifp->valid |= IF_VALID_SYSTEM; } if (ifp->system->valid & IF_VALID_TXQLEN) error (EXIT_FAILURE, 0, "only one txqlen allowed for interface `%s'", ifp->name); ifp->system->txqlen = strtol (arg, &end, 0); if (*arg == '\0' || *end != '\0') error (EXIT_FAILURE, 0, "txqlen value `%s' for interface `%s' is not a number", arg, ifp->name); ifp->system->valid |= IF_VALID_TXQLEN; } static struct argp_option linux_argp_options[] = { {"txqlen", 'T', "N", 0, "set transmit queue length to N", 0}, {NULL, 0, NULL, 0, NULL, 0} }; static error_t linux_argp_parser (int key, char *arg, struct argp_state *state) { struct ifconfig *ifp = *(struct ifconfig **) state->input; switch (key) { case 'T': /* txqlen */ system_parse_opt_set_txqlen (ifp, arg); break; default: return ARGP_ERR_UNKNOWN; } return 0; } static struct argp linux_argp = { linux_argp_options, linux_argp_parser, NULL, NULL, NULL, NULL, NULL }; struct argp_child system_argp_child = { &linux_argp, 0, "Linux-specific options", 0 }; int system_parse_opt (struct ifconfig **ifpp, char option, char *arg) { struct ifconfig *ifp = *ifpp; switch (option) { case 'T': /* txqlen */ system_parse_opt_set_txqlen (ifp, arg); break; default: return 0; } return 1; } int system_parse_opt_rest (struct ifconfig **ifp, int argc, char *argv[]) { int i = 0; enum { EXPECT_AF, EXPECT_NOTHING, EXPECT_BROADCAST, EXPECT_DSTADDR, EXPECT_NETMASK, EXPECT_HWADDR, EXPECT_MTU, EXPECT_METRIC, EXPECT_TXQLEN, } expect = EXPECT_AF; int mask, rev; *ifp = parse_opt_new_ifs (argv[0]); while (++i < argc) { switch (expect) { case EXPECT_BROADCAST: parse_opt_set_brdaddr (*ifp, argv[i]); break; case EXPECT_DSTADDR: parse_opt_set_point_to_point (*ifp, argv[i]); break; case EXPECT_NETMASK: parse_opt_set_netmask (*ifp, argv[i]); break; case EXPECT_HWADDR: parse_opt_set_hwaddr (*ifp, argv[i]); break; case EXPECT_MTU: parse_opt_set_mtu (*ifp, argv[i]); break; case EXPECT_METRIC: parse_opt_set_metric (*ifp, argv[i]); break; case EXPECT_TXQLEN: system_parse_opt_set_txqlen (*ifp, argv[i]); break; case EXPECT_AF: expect = EXPECT_NOTHING; if (!strcmp (argv[i], "inet")) continue; else if (!strcmp (argv[i], "inet6")) { error (0, 0, "%s is not a supported address family", argv[i]); return 0; } break; case EXPECT_NOTHING: break; } if (expect != EXPECT_NOTHING) expect = EXPECT_NOTHING; else if (!strcmp (argv[i], "broadcast")) expect = EXPECT_BROADCAST; else if (!strcmp (argv[i], "dstaddr") || !strcmp (argv[i], "pointopoint")) expect = EXPECT_DSTADDR; else if (!strcmp (argv[i], "netmask")) expect = EXPECT_NETMASK; else if (!strcmp (argv[i], "ether") || !strcmp (argv[i], "hwaddr") || !strcmp (argv[i], "lladdr")) expect = EXPECT_HWADDR; else if (!strcmp (argv[i], "metric")) expect = EXPECT_METRIC; else if (!strcmp (argv[i], "mtu")) expect = EXPECT_MTU; else if (!strcmp (argv[i], "txqueuelen")) expect = EXPECT_TXQLEN; else if (!strcmp (argv[i], "up")) parse_opt_set_flag (*ifp, IFF_UP | IFF_RUNNING, 0); else if (!strcmp (argv[i], "down")) parse_opt_set_flag (*ifp, IFF_UP, 1); else if (((mask = if_nameztoflag (argv[i], &rev)) & ~IU_IFF_CANTCHANGE) != 0) parse_opt_set_flag (*ifp, mask, rev); else parse_opt_set_address (*ifp, argv[i]); } switch (expect) { case EXPECT_BROADCAST: error (0, 0, "option `broadcast' requires an argument"); break; case EXPECT_DSTADDR: error (0, 0, "option `pointopoint' (`dstaddr') requires an argument"); break; case EXPECT_NETMASK: error (0, 0, "option `netmask' requires an argument"); break; case EXPECT_HWADDR: error (0, 0, "option `hwaddr' requires an argument"); break; case EXPECT_METRIC: error (0, 0, "option `metric' requires an argument"); break; case EXPECT_MTU: error (0, 0, "option `mtu' requires an argument"); break; case EXPECT_TXQLEN: error (0, 0, "option `txqueuelen' requires an argument"); break; case EXPECT_AF: case EXPECT_NOTHING: return 1; } return 0; } int system_preconfigure (int sfd MAYBE_UNUSED, struct ifreq *ifr MAYBE_UNUSED) { return 0; } int system_configure (int sfd, struct ifreq *ifr, struct system_ifconfig *ifs) { if (ifs->valid & IF_VALID_TXQLEN) { #ifndef SIOCSIFTXQLEN error (0, 0, "don't know how to set the txqlen on this system"); return -1; #else int err = 0; ifr->ifr_qlen = ifs->txqlen; err = ioctl (sfd, SIOCSIFTXQLEN, ifr); if (err < 0) error (0, errno, "SIOCSIFTXQLEN failed"); if (verbose) printf ("Set txqlen value of `%s' to `%i'.\n", ifr->ifr_name, ifr->ifr_qlen); #endif } return 0; } static struct if_nameindex * linux_if_nameindex (void) { char *content, *it; size_t length, index; struct if_nameindex *idx = NULL; int fd; fd = socket (AF_INET, SOCK_DGRAM, 0); if (fd < 0) return NULL; /* Read a public text file. */ content = read_file (PATH_PROCNET_DEV, 0, &length); if (content == NULL) return NULL; /* Count how many interfaces we have. */ { size_t n = 0; it = content; do { it = memchr (it + 1, ':', length - (it - content)); n++; } while (it); idx = malloc (n * sizeof (*idx)); if (idx == NULL) { int saved_errno = errno; close (fd); free (content); errno = saved_errno; return NULL; } } for (it = memchr (content, ':', length), index = 0; it; it = memchr (it, ':', length - (it - content)), index++) { char *start = it - 1; *it = '\0'; while (*start != ' ' && *start != '\n') start--; idx[index].if_name = strdup (start + 1); idx[index].if_index = index + 1; #if defined SIOCGIFINDEX { struct ifreq cur; strcpy (cur.ifr_name, idx[index].if_name); cur.ifr_index = -1; if (ioctl (fd, SIOCGIFINDEX, &cur) >= 0) idx[index].if_index = cur.ifr_index; } #endif if (idx[index].if_name == NULL) { int saved_errno = errno; close (fd); free (content); errno = saved_errno; return NULL; } } idx[index].if_index = 0; idx[index].if_name = NULL; free (content); return idx; } /* System hooks. */ struct if_nameindex *(*system_if_nameindex) (void) = linux_if_nameindex;