You can use getifaddrs() / freeifaddrs() to get a linked list of all interfaces, then ioctl(fd, SIOCGIFINDEX, struct ifreq *) to get the interface index for each. Since the interfaces are sequential and always listed (regardless of whether they are active or not), I choose to list them using a loop using ioctl(fd, SIOCGIFNAME, struct ifreq *) . In all cases, fd is an AF_INET socket.
To get duplex and interface speed, you need to use ioctl(fd, SIOCETHTOOL, struct ifreq *) with ifr_data pointing to struct ethtool_cmd with cmd = ETHTOOL_GSET .
ioctls should return -1 if they fail, and a non-negative value (zero, I think) if success.
Here is an example program:
#include <unistd.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <netinet/ip.h> #include <net/if.h> #include <linux/ethtool.h> #include <linux/sockios.h> #include <string.h> #include <errno.h> #include <stdio.h> struct interface { int index; int flags; /* IFF_UP etc. */ long speed; /* Mbps; -1 is unknown */ int duplex; /* DUPLEX_FULL, DUPLEX_HALF, or unknown */ char name[IF_NAMESIZE + 1]; }; static int get_interface_common(const int fd, struct ifreq *const ifr, struct interface *const info) { struct ethtool_cmd cmd; int result; /* Interface flags. */ if (ioctl(fd, SIOCGIFFLAGS, ifr) == -1) info->flags = 0; else info->flags = ifr->ifr_flags; ifr->ifr_data = (void *)&cmd; cmd.cmd = ETHTOOL_GSET; /* "Get settings" */ if (ioctl(fd, SIOCETHTOOL, ifr) == -1) { /* Unknown */ info->speed = -1L; info->duplex = DUPLEX_UNKNOWN; } else { info->speed = ethtool_cmd_speed(&cmd); info->duplex = cmd.duplex; } do { result = close(fd); } while (result == -1 && errno == EINTR); if (result == -1) return errno; return 0; } int get_interface_by_index(const int index, struct interface *const info) { int socketfd, result; struct ifreq ifr; if (index < 1 || !info) return errno = EINVAL; socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); if (socketfd == -1) return errno; ifr.ifr_ifindex = index; if (ioctl(socketfd, SIOCGIFNAME, &ifr) == -1) { do { result = close(socketfd); } while (result == -1 && errno == EINTR); return errno = ENOENT; } info->index = index; strncpy(info->name, ifr.ifr_name, IF_NAMESIZE); info->name[IF_NAMESIZE] = '\0'; return get_interface_common(socketfd, &ifr, info); } int get_interface_by_name(const char *const name, struct interface *const info) { int socketfd, result; struct ifreq ifr; if (!name || !*name || !info) return errno = EINVAL; socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); if (socketfd == -1) return errno; strncpy(ifr.ifr_name, name, IF_NAMESIZE); if (ioctl(socketfd, SIOCGIFINDEX, &ifr) == -1) { do { result = close(socketfd); } while (result == -1 && errno == EINTR); return errno = ENOENT; } info->index = ifr.ifr_ifindex; strncpy(info->name, name, IF_NAMESIZE); info->name[IF_NAMESIZE] = '\0'; return get_interface_common(socketfd, &ifr, info); } int main(int argc, char *argv[]) { struct interface iface; int arg; int status = 0; if (argc > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) { fprintf(stderr, "\n"); fprintf(stderr, "Usage: %s { -h | --help }\n", argv[0]); fprintf(stderr, " %s\n", argv[0]); fprintf(stderr, " %s INTERFACE ...\n", argv[0]); fprintf(stderr, "\n"); return 1; } if (argc > 1) { for (arg = 1; arg < argc; arg++) { if (get_interface_by_name(argv[arg], &iface) != 0) { fprintf(stderr, "%s: No such interface.\n", argv[arg]); status = 1; continue; } printf("%s: Interface %d", iface.name, iface.index); if (iface.flags & IFF_UP) printf(", up"); if (iface.duplex == DUPLEX_FULL) printf(", full duplex"); else if (iface.duplex == DUPLEX_HALF) printf(", half duplex"); if (iface.speed > 0) printf(", %ld Mbps", iface.speed); printf("\n"); } } else { for (arg = 1; ; arg++) { if (get_interface_by_index(arg, &iface) != 0) break; printf("%s: Interface %d", iface.name, iface.index); if (iface.flags & IFF_UP) printf(", up"); if (iface.duplex == DUPLEX_FULL) printf(", full duplex"); else if (iface.duplex == DUPLEX_HALF) printf(", half duplex"); if (iface.speed > 0) printf(", %ld Mbps", iface.speed); printf("\n"); } } return status; }
If you save the above as iflist.c , you can compile it with
gcc -W -Wall -O3 iflist.c -o iflist
To see usage, run iflist -h . To list all the interfaces, run it without parameters:
./iflist
The above method will use the described multiplier. To display only specific interfaces, start it by specifying the interfaces:
./iflist eth0 lo
Duplex and speed are listed only for Ethernet interfaces, of course.
Edited to add:
If the above program does not provide bandwidth and mode for the interface, here is a simplified version that reports the exact cause (errors). This interface name is called command line options; it does not list interfaces.
#include <unistd.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <netinet/ip.h> #include <net/if.h> #include <linux/ethtool.h> #include <linux/sockios.h> #include <string.h> #include <errno.h> #include <stdio.h> int ethernet_interface(const char *const name, int *const index, int *const speed, int *const duplex) { struct ifreq ifr; struct ethtool_cmd cmd; int fd, result; if (!name || !*name) { fprintf(stderr, "Error: NULL interface name.\n"); fflush(stderr); return errno = EINVAL; } if (index) *index = -1; if (speed) *speed = -1; if (duplex) *duplex = -1; fd = socket(AF_INET, SOCK_STREAM, 0); if (fd == -1) { const int err = errno; fprintf(stderr, "%s: Cannot create AF_INET socket: %s.\n", name, strerror(err)); fflush(stderr); return errno = err; } strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); ifr.ifr_data = (void *)&cmd; cmd.cmd = ETHTOOL_GSET; if (ioctl(fd, SIOCETHTOOL, &ifr) < 0) { const int err = errno; do { result = close(fd); } while (result == -1 && errno == EINTR); fprintf(stderr, "%s: SIOCETHTOOL ioctl: %s.\n", name, strerror(err)); return errno = err; } if (speed) *speed = ethtool_cmd_speed(&cmd); if (duplex) switch (cmd.duplex) { case DUPLEX_HALF: *duplex = 0; break; case DUPLEX_FULL: *duplex = 1; break; default: fprintf(stderr, "%s: Unknown mode (0x%x).\n", name, cmd.duplex); fflush(stderr); *duplex = -1; } if (index && ioctl(fd, SIOCGIFINDEX, &ifr) >= 0) *index = ifr.ifr_ifindex; do { result = close(fd); } while (result == -1 && errno == EINTR); if (result == -1) { const int err = errno; fprintf(stderr, "%s: Error closing socket: %s.\n", name, strerror(err)); return errno = err; } return 0; } int main(int argc, char *argv[]) { int arg, speed, index, duplex; if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { fprintf(stderr, "\n"); fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]); fprintf(stderr, " %s INTERFACE ...\n", argv[0]); fprintf(stderr, "\n"); return 0; } for (arg = 1; arg < argc; arg++) { if (ethernet_interface(argv[arg], &index, &speed, &duplex)) return 1; if (index == -1) printf("%s: (no interface index)", argv[arg]); else printf("%s: interface %d", argv[arg], index); if (speed == -1) printf(", unknown bandwidth"); else printf(", %d Mbps bandwidth", speed); if (duplex == 0) printf(", half duplex.\n"); else if (duplex == 1) printf(", full duplex.\n"); else printf(", unknown mode.\n"); } return 0; }
Questions?