diff options
author | Rob Landley <rob@landley.net> | 2013-04-02 01:58:18 -0500 |
---|---|---|
committer | Rob Landley <rob@landley.net> | 2013-04-02 01:58:18 -0500 |
commit | a6124a5bbbbf1b255479e68aed4dee5489197949 (patch) | |
tree | 6c7822cd4f9f446a95733adbe86989a1d6b6a3b2 /toys/pending/ifconfig.c | |
parent | 2edb485af88410fba64649d2bded8c5af0f5cc08 (diff) | |
download | toybox-a6124a5bbbbf1b255479e68aed4dee5489197949.tar.gz |
Kyungwan Han submitted ifconfig.
Diffstat (limited to 'toys/pending/ifconfig.c')
-rw-r--r-- | toys/pending/ifconfig.c | 1504 |
1 files changed, 1504 insertions, 0 deletions
diff --git a/toys/pending/ifconfig.c b/toys/pending/ifconfig.c new file mode 100644 index 00000000..bbd1ece0 --- /dev/null +++ b/toys/pending/ifconfig.c @@ -0,0 +1,1504 @@ +/* ifconfig.c - Configure network interface. + * + * Copyright 2012 Ranjan Kumar <ranjankumar.bth@gmail.com>, Kyungwan Han <asura321@gamil.com> + * Reviewed by Kyungsu Kim, Kyungwan Han <asura321@gamil.com> + * + * Not in SUSv4. + * +USE_IFCONFIG(NEWTOY(ifconfig, "?a", TOYFLAG_BIN)) +config IFCONFIG + bool "ifconfig" + default y + help + usage: ifconfig [-a] interface [address] + + Configure network interface. + + [add ADDRESS[/PREFIXLEN]] + [del ADDRESS[/PREFIXLEN]] + [[-]broadcast [ADDRESS]] [[-]pointopoint [ADDRESS]] + [netmask ADDRESS] [dstaddr ADDRESS] + [outfill NN] [keepalive NN] + [hw ether|infiniband ADDRESS] [metric NN] [mtu NN] + [[-]trailers] [[-]arp] [[-]allmulti] + [multicast] [[-]promisc] [txqueuelen NN] [[-]dynamic] + [mem_start NN] [io_addr NN] [irq NN] + [up|down] ... +*/ + +#define FOR_ifconfig +#include "toys.h" +#include "toynet.h" +#include <net/route.h> +#include <stddef.h> +#include <sys/un.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/ethernet.h> +#include <alloca.h> + +#define TRUE ((int) 1) +#define HTTP_DEFAULT_PORT 80 +#define FTP_DEFAULT_PORT 21 + +#ifndef MAX_PORT_VALUE +#define MAX_PORT_VALUE 65535 +#endif + +typedef struct sockaddr_with_len { + union { + struct sockaddr sock; + struct sockaddr_in sock_in; + struct sockaddr_in6 sock_in6; + }sock_u; + socklen_t socklen; +}sockaddr_with_len; + +//Function Declaration. +int get_hostname(const char *, struct sockaddr_in *); +int get_addrinfo(const char *, struct sockaddr_in6 *); +void get_flag_value(char **, int); +void display_routes(int, int); +unsigned getport(const char *, const char *, unsigned); +void setport(struct sockaddr *, unsigned); +int connect_to_stream(const sockaddr_with_len *); +unsigned get_strtou(const char *, char **, int); +char *address_to_name(const struct sockaddr *); +sockaddr_with_len *get_sockaddr(const char *, int, sa_family_t); + +//Structure Declaration +typedef struct _proc_net_dev_info { + char ifrname[IFNAMSIZ]; //interface name. + unsigned long long receive_bytes; //total bytes received + unsigned long long receive_packets; //total packets received + unsigned long receive_errors; //bad packets received + unsigned long receive_drop; //no space in linux buffers + unsigned long receive_fifo; //receiver fifo overrun + unsigned long receive_frame; //received frame alignment error + unsigned long receive_compressed; + unsigned long receive_multicast; //multicast packets received + + unsigned long long transmit_bytes; //total bytes transmitted + unsigned long long transmit_packets; //total packets transmitted + unsigned long transmit_errors; //packet transmit problems + unsigned long transmit_drop; //no space available in linux + unsigned long transmit_fifo; + unsigned long transmit_colls; + unsigned long transmit_carrier; + unsigned long transmit_compressed; //num_tr_compressed; +}PROC_NET_DEV_INFO; + +//man netdevice +typedef struct _iface_list { + int hw_type; + short ifrflags; //used for addr, broadcast, and mask. + short ifaddr; //if set print ifraddr, irrdstaddr, ifrbroadaddr and ifrnetmask. + struct sockaddr ifraddr; + struct sockaddr ifrdstaddr; + struct sockaddr ifrbroadaddr; + struct sockaddr ifrnetmask; + struct sockaddr ifrhwaddr; + int ifrmtu; + int ifrmetric; + PROC_NET_DEV_INFO dev_info; + int txqueuelen; + struct ifmap ifrmap; + struct _iface_list *next; //, *prev; +}IFACE_LIST; + + +#define HW_NAME_LEN 20 +#define HW_TITLE_LEN 30 + +typedef struct _hw_info { + char hw_name[HW_NAME_LEN]; + char hw_title[HW_TITLE_LEN]; + int hw_addrlen; +}HW_INFO; + +static const char *const field_format[] = { + "%n%llu%u%u%u%u%n%n%n%llu%u%u%u%u%u", + "%llu%llu%u%u%u%u%n%n%llu%llu%u%u%u%u%u", + "%llu%llu%u%u%u%u%u%u%llu%llu%u%u%u%u%u%u" +}; + +#define PROC_NET_DEV "/proc/net/dev" +#define PROC_NET_IFINET6 "/proc/net/if_inet6" +#define NO_RANGE -1 +#define IO_MAP_INDEX 0x100 + +static int show_iface(char *iface_name); +static void print_ip6_addr(IFACE_LIST *l_ptr); +static void clear_list(void); + +//from /net/if.h +static char *iface_flags_str[] = { + "UP", + "BROADCAST", + "DEBUG", + "LOOPBACK", + "POINTOPOINT", + "NOTRAILERS", + "RUNNING", + "NOARP", + "PROMISC", + "ALLMULTI", + "MASTER", + "SLAVE", + "MULTICAST", + "PORTSEL", + "AUTOMEDIA", + "DYNAMIC", + NULL +}; +//from /usr/include/linux/netdevice.h +#ifdef IFF_PORTSEL +//Media selection options. +# ifndef IF_PORT_UNKNOWN +enum { + IF_PORT_UNKNOWN = 0, + IF_PORT_10BASE2, + IF_PORT_10BASET, + IF_PORT_AUI, + IF_PORT_100BASET, + IF_PORT_100BASETX, + IF_PORT_100BASEFX +}; +# endif +#endif + +//from kernel header ipv6.h +#define IPV6_ADDR_ANY 0x0000U +#define IPV6_ADDR_LOOPBACK 0x0010U +#define IPV6_ADDR_LINKLOCAL 0x0020U +#define IPV6_ADDR_SITELOCAL 0x0040U +#define IPV6_ADDR_COMPATv4 0x0080U + +//================================================================================== +//for the param settings. + +//for ipv6 add/del +struct ifreq_inet6 { + struct in6_addr ifrinte6_addr; + uint32_t ifrinet6_prefixlen; + int ifrinet6_ifindex; +}; + +#ifndef SIOCSKEEPALIVE +# define SIOCSKEEPALIVE (SIOCDEVPRIVATE) /* Set keepalive timeout in sec */ +# define SIOCGKEEPALIVE (SIOCDEVPRIVATE+1) /* Get keepalive timeout */ +#endif + +#ifndef SIOCSOUTFILL +# define SIOCSOUTFILL (SIOCDEVPRIVATE+2) /* Set outfill timeout */ +# define SIOCGOUTFILL (SIOCDEVPRIVATE+3) /* Get outfill timeout */ +#endif + +#ifndef INFINIBAND_ALEN +# define INFINIBAND_ALEN 20 +#endif + +static void set_data(int sockfd, struct ifreq *ifre, char *kval, int request, const char *req_name); +static void set_flags(int sockfd, struct ifreq *ifre, int arg_flag, int flag); //verify +static void set_mtu(int sockfd, struct ifreq *ifre, const char *mtu); //verify +static void set_metric(int sockfd, struct ifreq *ifre, const char *metric); //verify +static void set_qlen(int sockfd, struct ifreq *ifre, const char *qlen); //verify +static void set_address(int sockfd, const char *host_name, struct ifreq *ifre, int request, const char *req_name); +static void set_hw_address(int sockfd, char ***argv, struct ifreq *ifre, int request, const char *req_name); +static void set_ipv6_addr(int sockfd, struct ifreq *ifre, const char *ipv6_addr, int request, const char *req_name); +static void set_memstart(int sockfd, struct ifreq *ifre, const char *start_addr, int request, const char *req_name); +static void set_ioaddr(int sockfd, struct ifreq *ifre, const char *baddr, int request, const char *req_name); +static void set_irq(int sockfd, struct ifreq *ifre, const char *irq_val, int request, const char *req_name); + +char *omit_whitespace(const char *s) +{ + while(*s == ' ' || (unsigned char)(*s - 9) <= (13 - 9)) s++; + return (char *) s; +} + +char *safe_strncpy(char *dst, const char *src, size_t size) +{ + if(!size) return dst; + dst[--size] = '\0'; + return strncpy(dst, src, size); +} + +/* + * used to get the host name from the given ip. + */ +int get_hostname(const char *ipstr, struct sockaddr_in *sockin) +{ + struct hostent *host; + sockin->sin_family = AF_INET; + sockin->sin_port = 0; + + if(strcmp(ipstr, "default") == 0) { + sockin->sin_addr.s_addr = INADDR_ANY; + return 1; + } + + if(inet_aton(ipstr, &sockin->sin_addr)) return 0; + + host = gethostbyname(ipstr); + if(host == NULL) return -1; + memcpy(&sockin->sin_addr, host->h_addr_list[0], sizeof(struct in_addr)); + return 0; +} + +/* + * used to extract the address info from the given ip. + */ +int get_addrinfo(const char *ip, struct sockaddr_in6 *sock_in6) +{ + struct addrinfo hints, *result; + int status = 0; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_INET6; + if((status = getaddrinfo(ip, NULL, &hints, &result)) != 0) { + perror_msg("getaddrinfo: %s", gai_strerror(status)); + return -1; + } + if(result) { + memcpy(sock_in6, result->ai_addr, sizeof(*sock_in6)); + freeaddrinfo(result); + } + return 0; +} + +/* + * used to get the flag values for route command. + */ +void get_flag_value(char **flagstr, int flags) +{ + int i = 0; + char *str = *flagstr; + static const char flagchars[] = "GHRDMDAC"; + static const unsigned flagarray[] = { + RTF_GATEWAY, + RTF_HOST, + RTF_REINSTATE, + RTF_DYNAMIC, + RTF_MODIFIED, + RTF_DEFAULT, + RTF_ADDRCONF, + RTF_CACHE + }; + *str++ = 'U'; + while( (*str = flagchars[i]) != 0) { + if(flags & flagarray[i++]) ++str; + } +} + +/* + * extract inet4 route info from /proc/net/route file and display it. + */ +void display_routes(int is_more_info, int notresolve) +{ +#define IPV4_MASK (RTF_GATEWAY|RTF_HOST|RTF_REINSTATE|RTF_DYNAMIC|RTF_MODIFIED) + unsigned long dest, gate, mask; + int flags, ref, use, metric, mss, win, irtt; + char iface[64]={0,}; + char buf[BUFSIZ] = {0,}; + char *flag_val = xzalloc(10); //there are 9 flags "UGHRDMDAC" for route. + + FILE *fp = xfopen("/proc/net/route", "r"); + + xprintf("Kernel IP routing table\n" + "Destination Gateway Genmask Flags %s Iface\n", + is_more_info ? " MSS Window irtt" : "Metric Ref Use"); + fgets(buf, BUFSIZ, fp); //skip 1st line. + while(fgets(buf, BUFSIZ, fp)) { + int nitems = 0; + char *destip = NULL, *gateip = NULL, *maskip = NULL; + memset(flag_val, 0, 10); + + nitems = sscanf(buf, "%63s%lx%lx%X%d%d%d%lx%d%d%d\n", + iface, &dest, &gate, &flags, &ref, &use, &metric, &mask, &mss, &win, &irtt); + if(nitems != 11) {//EOF with no (nonspace) chars read... + if((nitems < 0) && feof(fp)) break; + perror_exit("fscanf"); + } + //skip down interfaces... + if(!(flags & RTF_UP)) continue; + + //For Destination + if(dest){ + if(inet_ntop(AF_INET, &dest, buf, BUFSIZ) > 0) destip = xstrdup(buf); + } + else { + if(!notresolve) destip = xstrdup("default"); + else destip = xstrdup("0.0.0.0"); + } + //For Gateway + if(gate){ + if(inet_ntop(AF_INET, &gate, buf, BUFSIZ) > 0) gateip = xstrdup(buf); + } + else { + if(!notresolve) gateip = xstrdup("*"); + else gateip = xstrdup("0.0.0.0"); + } + //For Mask + if(inet_ntop(AF_INET, &mask, buf, BUFSIZ) > 0) maskip = xstrdup(buf); + + //Get flag Values + get_flag_value(&flag_val, (flags & IPV4_MASK)); + if(flags & RTF_REJECT) flag_val[0] = '!'; + xprintf("%-15.15s %-15.15s %-16s%-6s", destip, gateip, maskip, flag_val); + if(destip) free(destip); + if(gateip) free(gateip); + if(maskip) free(maskip); + if(is_more_info) xprintf("%5d %-5d %6d %s\n", mss, win, irtt, iface); + else xprintf("%-6d %-2d %7d %s\n", metric, ref, use, iface); + }//end of while... + fclose(fp); + if(flag_val) free(flag_val); +#undef IPV4_MASK + return; +} + +/* + * verify the host is local unix path. + * if so, set the swl input param accordingly. + */ +static int is_host_unix(const char *host, sockaddr_with_len **swl) +{ + if(strncmp(host, "local:", 6) == 0) { + struct sockaddr_un *sockun; + *swl = xzalloc(sizeof(struct sockaddr_with_len)); + (*swl)->socklen = sizeof(struct sockaddr_un); + (*swl)->sock_u.sock.sa_family = AF_UNIX; + sockun = (struct sockaddr_un *)&(*swl)->sock_u.sock; + safe_strncpy(sockun->sun_path, host + 6, sizeof(sockun->sun_path)); + return 1; + } + return 0; +} + +/* + * validate the input param (host) for valid ipv6 ip and extract port number (if there). + */ +static void get_host_and_port(char **host, int *port) +{ + char *ch_ptr; + const char *org_host = *host; + if(*host[0] == '[') { + (*host)++; + ch_ptr = strchr(*host, ']'); + if(!ch_ptr || (ch_ptr[1] != ':' && ch_ptr[1] != '\0')) + error_exit("bad address '%s'", org_host); + } + else { + ch_ptr = strrchr(*host, ':'); + //There is more than one ':' like "::1" + if(ch_ptr && strchr(*host, ':') != ch_ptr) + ch_ptr = NULL; + } + if(ch_ptr) { //pointer to ":" or "]:" + int size = ch_ptr - (*host) + 1; + safe_strncpy(*host, *host, size); + if(*ch_ptr != ':') { + ch_ptr++; //skip ']' + //[nn] without port + if(*ch_ptr == '\0') + return; + } + ch_ptr++; //skip ':' to get the port number. + *port = get_strtou(ch_ptr, NULL, 10); + if(errno || (unsigned)*port > MAX_PORT_VALUE) + error_exit("bad port spec '%s'", org_host); + } + return; +} + +/* + * used to extract the address info from the given host ip + * and update the swl param accordingly. + */ +static int get_socket_stream(const char *host, sa_family_t af, sockaddr_with_len **swl) +{ + struct addrinfo hints; + struct addrinfo *result, *rp; + int status = 0; + + memset(&hints, 0 , sizeof(struct addrinfo)); + hints.ai_family = af; + hints.ai_socktype = SOCK_STREAM; + + if((status = getaddrinfo(host, NULL, &hints, &result)) != 0) { + perror_exit("bad address '%s' : %s", host, gai_strerror(status)); + return status; + } + + for(rp = result; rp != NULL; rp = rp->ai_next) { + if( (rp->ai_family == AF_INET) || (rp->ai_family == AF_INET6)) { + *swl = xmalloc(sizeof(struct sockaddr_with_len)); + (*swl)->socklen = rp->ai_addrlen; + memcpy(&((*swl)->sock_u.sock), rp->ai_addr, rp->ai_addrlen); + break; + } + } + freeaddrinfo(result); + return ((!rp)? -1: status); +} + +/* + * use to get the socket address with the given host ip. + */ +sockaddr_with_len *get_sockaddr(const char *host, int port, sa_family_t af) +{ + sockaddr_with_len *swl = NULL; + int status = 0; + + //for unix + int is_unix = is_host_unix(host, &swl); + if(is_unix && swl) return swl; + + //[IPV6_ip]:port_num + if(host[0] == '[' || strrchr(host, ':')) get_host_and_port((char **)&host, &port); + + //for the socket streams. + status = get_socket_stream(host, af, &swl); + if(status) return NULL; + + setport(&swl->sock_u.sock, htons(port)); + return swl; +} + +/* + * get the numeric hostname and service name, for a given socket address. + */ +char *address_to_name(const struct sockaddr *sock) +{ + //man page of getnameinfo. + char hbuf[NI_MAXHOST] = {0,}, sbuf[NI_MAXSERV] = {0,}; + int status = 0; + if(sock->sa_family == AF_INET) { + socklen_t len = sizeof(struct sockaddr_in); + if((status = getnameinfo(sock, len, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0) + return xmsprintf("%s:%s", hbuf, sbuf); + else { + fprintf(stderr, "getnameinfo: %s\n", gai_strerror(status)); + return NULL; + } + } + else if(sock->sa_family == AF_INET6) { + socklen_t len = sizeof(struct sockaddr_in6); + if((status = getnameinfo(sock, len, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0) { + //verification for resolved hostname. + if(strchr(hbuf, ':')) return xmsprintf("[%s]:%s", hbuf, sbuf); + else return xmsprintf("%s:%s", hbuf, sbuf); + } + else { + fprintf(stderr, "getnameinfo: %s\n", gai_strerror(status)); + return NULL; + } + } + else if(sock->sa_family == AF_UNIX) { + struct sockaddr_un *sockun = (void*)sock; + return xmsprintf("local:%.*s", (int) sizeof(sockun->sun_path), sockun->sun_path); + } + else + return NULL; +} + +/* + * used to set the port number for ipv4 / ipv6 addresses. + */ +void setport(struct sockaddr *sock, unsigned port_num) +{ + //for ipv4 + if(sock->sa_family == AF_INET) { + struct sockaddr_in *sock_in = (void*)sock; + sock_in->sin_port = port_num; + } + //for ipv6 + else if(sock->sa_family == AF_INET6) { + struct sockaddr_in6 *sock_in6 = (void*)sock; + sock_in6->sin6_port = port_num; + } + return; +} + +/* + * used to get the port number for ftp and http. + */ +unsigned getport(const char *port, const char *protocol, unsigned defport) +{ +#define RANGE_STR "Port Number should be in [1-65535] range" + long v; + char *endptr = NULL; + + unsigned portnum = defport; + if(port) { + errno = 0; + v = strtol(port, &endptr, 10); + if((v > 0) && (!*endptr)) {//for numeric like 123 + portnum = v; + if(portnum > MAX_PORT_VALUE) error_exit("Invalid Port Number '%s' "RANGE_STR, port); + } + else if((v == 0) && (endptr != NULL)) { + switch(defport) { + case FTP_DEFAULT_PORT: + if(strcmp(endptr, "ftp") == 0) portnum = defport; //for "ftp" string. + else goto ERROR_EXIT; + break; + case HTTP_DEFAULT_PORT: + if(strcmp(endptr, "http") == 0) portnum = defport;//for "HTTP" string. + else goto ERROR_EXIT; + break; + default: +ERROR_EXIT: + error_exit("Invalid Port"); + break; + } + } + else perror_exit("Invalid Port Number: '%s' "RANGE_STR, port); + } +#undef RANGE_STR + return (uint16_t)portnum; +} + +/* + * used to connect with the socket. + */ +int connect_to_stream(const sockaddr_with_len *swl) +{ + int sockfd; + if((sockfd = socket(swl->sock_u.sock.sa_family, SOCK_STREAM, 0)) < 0) + perror_exit("cannot open control socket"); + if(connect(sockfd, &swl->sock_u.sock, swl->socklen) < 0) { + close(sockfd); + perror_exit("can't connect to remote host"); + } + return sockfd; +} + +/* + * used to converts string into int and validate the input str for invalid int value or out-of-range. + */ +unsigned get_strtou(const char *str, char **endp, int base) +{ + unsigned long uli; + char *endptr; + + if(!isalnum(str[0])) { + errno = ERANGE; + return UINT_MAX; + } + errno = 0; + uli = strtoul(str, &endptr, base); + if(uli > UINT_MAX) { + errno = ERANGE; + return UINT_MAX; + } + + if(endp) *endp = endptr; + if(endptr[0]) { + if(isalnum(endptr[0]) || errno) { //"123abc" or out-of-range + errno = ERANGE; + return UINT_MAX; + } + errno = EINVAL; + } + return uli; +} + + +IFACE_LIST *iface_list_head; + +/* + * display help info and exit from application. + */ +static void show_help(void) +{ + char **arg = xzalloc(sizeof(char*) *3); + arg[0] = "help"; + arg[1] = xstrdup(toys.which->name); + toy_exec(arg); +} + +void ifconfig_main(void) +{ + char **argv = toys.optargs; + + if(argv[0] && (strcmp(argv[0], "--help") == 0)) + show_help(); + + //"ifconfig" / "ifconfig eth0" + if(!argv[0] || !argv[1]) { //one or no argument + toys.exitval = show_iface(argv[0]); + //free allocated memory. + clear_list(); + return; + } + + //set ifconfig params. + { + struct ifreq ifre; + int sockfd = 0; + //get interface name + memset(&ifre, 0, sizeof(struct ifreq)); + strncpy(ifre.ifr_name, *argv, IFNAMSIZ); + ifre.ifr_name[IFNAMSIZ-1] = 0; + if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + perror_exit("cannot open control socket\n", 1); + + while(*++argv != NULL) { + /* flags settings */ + if(strcmp(argv[0], "up") == 0) + set_flags(sockfd, &ifre, IFF_UP | IFF_RUNNING, 0); + else if(strcmp(argv[0], "down") == 0) + set_flags(sockfd, &ifre, 0, IFF_UP); + + else if(strcmp(argv[0], "arp") == 0) + set_flags(sockfd, &ifre, 0, IFF_NOARP); + else if(strcmp(argv[0], "-arp") == 0) + set_flags(sockfd, &ifre, IFF_NOARP, 0); + else if(strcmp(argv[0], "trailers") == 0) + set_flags(sockfd, &ifre, 0, IFF_NOTRAILERS); + else if(strcmp(argv[0], "-trailers") == 0) + set_flags(sockfd, &ifre, IFF_NOTRAILERS, 0); + + else if(strcmp(argv[0], "promisc") == 0) + set_flags(sockfd, &ifre, IFF_PROMISC, 0); + else if(strcmp(argv[0], "-promisc") == 0) + set_flags(sockfd, &ifre, 0, IFF_PROMISC); + else if(strcmp(argv[0], "allmulti") == 0) + set_flags(sockfd, &ifre, IFF_ALLMULTI, 0); + else if(strcmp(argv[0], "-allmulti") == 0) + set_flags(sockfd, &ifre, 0, IFF_ALLMULTI); + else if(strcmp(argv[0], "multicast") == 0) + set_flags(sockfd, &ifre, IFF_MULTICAST, 0); + else if(strcmp(argv[0], "-multicast") == 0) + set_flags(sockfd, &ifre, 0, IFF_MULTICAST); + else if(strcmp(argv[0], "dynamic") == 0) + set_flags(sockfd, &ifre, IFF_DYNAMIC, 0); + else if(strcmp(argv[0], "-dynamic") == 0) + set_flags(sockfd, &ifre, 0, IFF_DYNAMIC); + else if(strcmp(argv[0], "-pointopoint") == 0) + set_flags(sockfd, &ifre, 0, IFF_POINTOPOINT); + /*value setup */ + else if(strcmp(argv[0], "pointopoint") == 0) { + if(*++argv == NULL) { + errno = EINVAL; + show_help(); + } + set_address(sockfd, *argv, &ifre, SIOCSIFDSTADDR, "SIOCSIFDSTADDR"); + set_flags(sockfd, &ifre, IFF_POINTOPOINT, 0); + } + else if(strcmp(argv[0], "netmask") == 0) { + if(*++argv == NULL) { + errno = EINVAL; + show_help(); + } + set_address(sockfd, *argv, &ifre, SIOCSIFNETMASK, "SIOCSIFNETMASK"); + } + else if(strcmp(argv[0], "-broadcast") == 0) { + set_flags(sockfd, &ifre, 0, IFF_BROADCAST); + } + else if(strcmp(argv[0], "broadcast") == 0) { + if(*++argv == NULL) { + errno = EINVAL; + show_help(); + } + set_address(sockfd, *argv, &ifre, SIOCSIFBRDADDR, "SIOCSIFBRDADDR"); + set_flags(sockfd, &ifre, IFF_BROADCAST, 0); + } + else if(strcmp(argv[0], "dstaddr") == 0) { + if(*++argv == NULL) { + errno = EINVAL; + show_help(); + } + set_address(sockfd, *argv, &ifre, SIOCSIFDSTADDR, "SIOCSIFDSTADDR"); + } + else if(strcmp(argv[0], "hw") == 0) { + if(*++argv == NULL) { + errno = EINVAL; + show_help(); + } + set_hw_address(sockfd, &argv, &ifre, SIOCSIFHWADDR, "SIOCSIFHWADDR"); + } + else if(strcmp(argv[0], "mtu") == 0) { + if(*++argv == NULL) { + errno = EINVAL; + show_help(); + } + set_mtu(sockfd, &ifre, argv[0]); + }//end of mtu + else if(strcmp(argv[0], "metric") == 0) { + if(*++argv == NULL) { + errno = EINVAL; + show_help(); + } + set_metric(sockfd, &ifre, argv[0]); + }//end of metric + else if(strcmp(argv[0], "txqueuelen") == 0) { + if(*++argv == NULL) { + errno = EINVAL; + show_help(); + } + set_qlen(sockfd, &ifre, argv[0]); + }//end of txqueuelen + else if(strcmp(argv[0], "keepalive") == 0) { + if(*++argv == NULL) { + errno = EINVAL; + show_help(); + } + set_data(sockfd, &ifre, argv[0], SIOCSKEEPALIVE, "SIOCSKEEPALIVE"); + }//end of keepalive + else if(strcmp(argv[0], "outfill") == 0) { + if(*++argv == NULL) { + errno = EINVAL; + show_help(); + } + set_data(sockfd, &ifre, argv[0], SIOCSOUTFILL, "SIOCSOUTFILL"); + }//end of outfill + else if(strcmp(argv[0], "add") == 0) { + if(*++argv == NULL) { + errno = EINVAL; + show_help(); + } + set_ipv6_addr(sockfd, &ifre, argv[0], SIOCSIFADDR, "SIOCSIFADDR"); + }//end of add ipv6 addr + else if(strcmp(argv[0], "del") == 0) { + if(*++argv == NULL) { + errno = EINVAL; + show_help(); + } + set_ipv6_addr(sockfd, &ifre, argv[0], SIOCDIFADDR, "SIOCDIFADDR"); + }//end of del ipv6 addr + else if(strcmp(argv[0], "mem_start") == 0) { + if(*++argv == NULL) { + errno = EINVAL; + show_help(); + } + set_memstart(sockfd, &ifre, argv[0], SIOCSIFMAP, "SIOCSIFMAP"); + }//end of mem_start + else if(strcmp(argv[0], "io_addr") == 0) { + if(*++argv == NULL) { + errno = EINVAL; + show_help(); + } + set_ioaddr(sockfd, &ifre, argv[0], SIOCSIFMAP, "SIOCSIFMAP"); + }//end of io_addr + else if(strcmp(argv[0], "irq") == 0) { + if(*++argv == NULL) { + errno = EINVAL; + show_help(); + } + set_irq(sockfd, &ifre, argv[0], SIOCSIFMAP, "SIOCSIFMAP"); + }//end of irq + else { + if(isdigit(argv[0][0]) || (strcmp(argv[0], "default") == 0)) { + char *iface_name = ifre.ifr_name; + short int is_colon = 0; + set_address(sockfd, *argv, &ifre, SIOCSIFADDR, "SIOCSIFADDR"); + while(*iface_name) { + if(*iface_name == ':') { + is_colon = 1; + break; + } + iface_name++; + } + //if the interface name is not an alias; set the flag and continue. + if(!is_colon) + set_flags(sockfd, &ifre, IFF_UP | IFF_RUNNING, 0); + } + else if((strcmp(argv[0], "inet") == 0) || (strcmp(argv[0], "inet6") == 0)) + continue; + else { + errno = EINVAL; + show_help(); + } + }//set ip for an interface. + + }//end of while. + if(sockfd > 0) + close(sockfd); + } + return; +}//End of main function. + + +static void set_flags(int sockfd, struct ifreq *ifre, int set_flag, int reset_flag) +{ + if(ioctl(sockfd, SIOCGIFFLAGS, ifre) < 0) + perror_exit("SIOCGIFFLAGS"); + ifre->ifr_flags = (ifre->ifr_flags & (~reset_flag)) | set_flag; + if(ioctl(sockfd, SIOCSIFFLAGS, ifre) < 0) + perror_exit("SIOCSIFFLAGS"); + return; +} + +static void set_data(int sockfd, struct ifreq *ifre, char *kval, int request, const char *req_name) +{ + unsigned long val = xstrtoul(kval, NULL, 0); + char *ptr; + ptr = ((char *) ifre) + offsetof(struct ifreq, ifr_data); + (*(__caddr_t *)ptr) = (__caddr_t)val; + + if(ioctl(sockfd, request, ifre) < 0) { + perror_exit((char *)req_name); + } + return; +} +static void set_mtu(int sockfd, struct ifreq *ifre, const char *mtu) +{ + ifre->ifr_mtu = strtoul(mtu, NULL, 0); + if(ioctl(sockfd, SIOCSIFMTU, ifre) < 0) + perror_exit("SIOCSIFMTU"); + return; +} + +static void set_metric(int sockfd, struct ifreq *ifre, const char *metric) +{ + ifre->ifr_metric = strtoul(metric, NULL, 0); + if(ioctl(sockfd, SIOCSIFMETRIC, ifre) < 0) + perror_exit("SIOCSIFMETRIC"); + return; +} + +static void set_qlen(int sockfd, struct ifreq *ifre, const char *qlen) +{ + ifre->ifr_qlen = strtoul(qlen, NULL, 0); + if(ioctl(sockfd, SIOCSIFTXQLEN, ifre) < 0) + perror_exit("SIOCSIFTXQLEN"); + return; +} + +static void set_ipv6_addr(int sockfd, struct ifreq *ifre, const char *ipv6_addr, int request, const char *req_name) +{ + char *prefix; + int plen = 0; + sockaddr_with_len *swl = NULL; + + prefix = strchr(ipv6_addr, '/'); + if(prefix) { + plen = get_int_value(prefix + 1, 0, 128); + *prefix = '\0'; + } + swl = get_sockaddr(ipv6_addr, 0, AF_INET6); + if(!swl) error_exit("error in resolving host name"); + int sockfd6; + struct ifreq_inet6 ifre6; + memcpy((char *) &ifre6.ifrinte6_addr, + (char *) &(swl->sock_u.sock_in6.sin6_addr), + sizeof(struct in6_addr)); + //Create a channel to the NET kernel. + if( (sockfd6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) + perror_exit("AF_INET6 SOCK_DGRAM", 0); + if(ioctl(sockfd6, SIOGIFINDEX, ifre) < 0) + perror_exit("SIOGIFINDEX"); + ifre6.ifrinet6_ifindex = ifre->ifr_ifindex; + ifre6.ifrinet6_prefixlen = plen; + + if(ioctl(sockfd6, request, &ifre6) < 0) + perror_exit((char *)req_name); + if(swl != NULL) { + free(swl); + swl = NULL; + } + return; +} + +static void set_address(int sockfd, const char *host_name, struct ifreq *ifre, int request, const char *req_name) +{ + struct sockaddr_in sock_in; + sockaddr_with_len *swl = NULL; + sock_in.sin_family = AF_INET; + sock_in.sin_port = 0; + + //Default 0.0.0.0 + if(strcmp(host_name, "default") == 0) + sock_in.sin_addr.s_addr = INADDR_ANY; + else { + swl = get_sockaddr(host_name, 0, AF_INET); + if(!swl) error_exit("error in resolving host name"); + + sock_in.sin_addr = swl->sock_u.sock_in.sin_addr; + } + memcpy((char *)&ifre->ifr_addr, (char *) &sock_in, sizeof(struct sockaddr)); + if(ioctl(sockfd, request, ifre) < 0) + perror_exit((char *)req_name); + + if(swl != NULL) { + free(swl); + swl = NULL; + } + return; +} + +static int hex_to_binary(const char *hw_addr, struct sockaddr *sock, int count) +{ + int i = 0, j = 0; + unsigned char nib_val; + unsigned char ch; + + char *ptr = (char *) sock->sa_data; + if(count == ETH_ALEN) + sock->sa_family = ARPHRD_ETHER; + else if(count == INFINIBAND_ALEN) + sock->sa_family = ARPHRD_INFINIBAND; + else + return -1; + //e.g. hw_addr "62:2D:A6:9E:2D:BE" + for(; *hw_addr && (i < count); i++) { + if(*hw_addr == ':') + hw_addr++; + j = nib_val = 0; + for(;j < 2; j++) { + ch = *hw_addr; + //0-9 = 10 chars. + if(((unsigned char)(ch - '0')) < 10) + ch = (ch - '0'); + //a-f = 6 chars. + else if(((unsigned char)((ch) - 'a')) < 6) + ch = (ch - ('a'-10)); + //A-F = 6 chars. + else if(((unsigned char)((ch) - 'A')) < 6) + ch = (ch - ('A'-10)); + else if(j && (ch == ':' || ch == 0)) + break; + else + return -1; + hw_addr++; + nib_val <<= 4; + nib_val += ch; + } + *ptr++ = nib_val; + } + if(*hw_addr) + return -1; + return 0; +} + +static void set_hw_address(int sockfd, char ***argv, struct ifreq *ifre, int request, const char *req_name) +{ + int hw_class = 0; + char *hw_addr; + struct sockaddr sock; + char *ptr; + char *hw_class_strings[] = { + "ether", + "infiniband", + NULL + }; + + if(strcmp(hw_class_strings[0], **argv) == 0) + hw_class = 1; + else if(strcmp(hw_class_strings[1], **argv) == 0) + hw_class = 2; + if(!hw_class || !(*argv += 1)) + show_help(); + + memset(&sock, 0, sizeof(struct sockaddr)); + hw_addr = **argv; + if(hw_class == 1) { + if(hex_to_binary(hw_addr, &sock, ETH_ALEN)) + error_exit("invalid hw-addr %s", hw_addr); + } + else { + if(hex_to_binary(hw_addr, &sock, INFINIBAND_ALEN)) + error_exit("invalid hw-addr %s", hw_addr); + } + ptr = (char *)&sock; + memcpy( ((char *) ifre) + offsetof(struct ifreq, ifr_hwaddr), ptr, sizeof(struct sockaddr)); + if(ioctl(sockfd, request, ifre) < 0) + perror_exit((char *)req_name); + return; +} + +static void set_memstart(int sockfd, struct ifreq *ifre, const char *start_addr, int request, const char *req_name) +{ + unsigned long mem_start = strtoul(start_addr, NULL, 0); + + if(ioctl(sockfd, SIOCGIFMAP, ifre) < 0) + perror_exit("SIOCGIFMAP"); + ifre->ifr_map.mem_start = mem_start; + if(ioctl(sockfd, request, ifre) < 0) + perror_exit((char *)req_name); + return; +} + +static void set_ioaddr(int sockfd, struct ifreq *ifre, const char *baddr, int request, const char *req_name) +{ + unsigned short int base_addr = strtoul(baddr, NULL, 0); + if(ioctl(sockfd, SIOCGIFMAP, ifre) < 0) + perror_exit("SIOCGIFMAP"); + ifre->ifr_map.base_addr = base_addr; + if(ioctl(sockfd, request, ifre) < 0) + perror_exit((char *)req_name); + return; +} + +static void set_irq(int sockfd, struct ifreq *ifre, const char *irq_val, int request, const char *req_name) +{ + unsigned short int irq = strtoul(irq_val, NULL, 0); + char *ptr; + struct ifmap *map; + + if(ioctl(sockfd, SIOCGIFMAP, ifre) < 0) + perror_exit("SIOCGIFMAP"); + + ptr = ((char *) ifre) + offsetof(struct ifreq, ifr_map); + map = (struct ifmap *)ptr; + map->irq = irq; + if(ioctl(sockfd, request, ifre) < 0) + perror_exit((char *)req_name); + return; +} + +/* Display ifconfig info. */ +static void get_proc_info(char *buff, IFACE_LIST *l_ptr, int version) +{ + char *name; + memset(&l_ptr->dev_info, 0, sizeof(PROC_NET_DEV_INFO)); + + buff = omit_whitespace(buff); + name = strsep(&buff, ":"); + if(!buff) + error_exit("error in getting the device name:"); + + if(strlen(name) < (IFNAMSIZ)) { + strncpy(l_ptr->dev_info.ifrname, name, IFNAMSIZ-1); + l_ptr->dev_info.ifrname[IFNAMSIZ-1] = '\0'; + } + else { + l_ptr->dev_info.ifrname[0] = '\0'; + } + + sscanf(buff, field_format[version], + &l_ptr->dev_info.receive_bytes, + &l_ptr->dev_info.receive_packets, + &l_ptr->dev_info.receive_errors, + &l_ptr->dev_info.receive_drop, + &l_ptr->dev_info.receive_fifo, + &l_ptr->dev_info.receive_frame, + &l_ptr->dev_info.receive_compressed, + &l_ptr->dev_info.receive_multicast, + &l_ptr->dev_info.transmit_bytes, + &l_ptr->dev_info.transmit_packets, + &l_ptr->dev_info.transmit_errors, + &l_ptr->dev_info.transmit_drop, + &l_ptr->dev_info.transmit_fifo, + &l_ptr->dev_info.transmit_colls, + &l_ptr->dev_info.transmit_carrier, + &l_ptr->dev_info.transmit_compressed + ); + + if(version == 0) + l_ptr->dev_info.receive_bytes = l_ptr->dev_info.transmit_bytes = 0; + if(version == 1) + l_ptr->dev_info.receive_multicast = l_ptr->dev_info.receive_compressed = l_ptr->dev_info.transmit_compressed = 0; + return; +} + +static void add_iface_to_list(IFACE_LIST *newnode) +{ + IFACE_LIST *head_ref = iface_list_head; + + if((head_ref == NULL) || strcmp(newnode->dev_info.ifrname, head_ref->dev_info.ifrname) < 0) { + newnode->next = head_ref; + head_ref = newnode; + } + else { + IFACE_LIST *current = head_ref; + while(current->next != NULL && (strcmp(current->next->dev_info.ifrname, newnode->dev_info.ifrname)) < 0) + current = current->next; + newnode->next = current->next; + current->next = newnode; + } + iface_list_head = head_ref; + return; +} + +static int get_device_info(IFACE_LIST *l_ptr) +{ + struct ifreq ifre; + char *ifrname = l_ptr->dev_info.ifrname; + int sokfd; + + sokfd = socket(AF_INET, SOCK_DGRAM, 0); + if(sokfd < 0) + return sokfd; + strncpy(ifre.ifr_name, ifrname, IFNAMSIZ); + if(ioctl(sokfd, SIOCGIFFLAGS, &ifre) < 0) { + close(sokfd); + return NO_RANGE; + } + l_ptr->ifrflags = ifre.ifr_flags; + + strncpy(ifre.ifr_name, ifrname, IFNAMSIZ); + if(ioctl(sokfd, SIOCGIFHWADDR, &ifre) >= 0) + memcpy(l_ptr->ifrhwaddr.sa_data, ifre.ifr_hwaddr.sa_data, sizeof(l_ptr->ifrhwaddr.sa_data)); + + l_ptr->hw_type = ifre.ifr_hwaddr.sa_family; + + strncpy(ifre.ifr_name, ifrname, IFNAMSIZ); + if(ioctl(sokfd, SIOCGIFMETRIC, &ifre) >= 0) + l_ptr->ifrmetric = ifre.ifr_metric; + + strncpy(ifre.ifr_name, ifrname, IFNAMSIZ); + if(ioctl(sokfd, SIOCGIFMTU, &ifre) >= 0) + l_ptr->ifrmtu = ifre.ifr_mtu; + +#ifdef SIOCGIFMAP + strncpy(ifre.ifr_name, ifrname, IFNAMSIZ); + if(ioctl(sokfd, SIOCGIFMAP, &ifre) == 0) + l_ptr->ifrmap = ifre.ifr_map; +#endif + + strncpy(ifre.ifr_name, ifrname, IFNAMSIZ); + l_ptr->txqueuelen = NO_RANGE; + if(ioctl(sokfd, SIOCGIFTXQLEN, &ifre) >= 0) + l_ptr->txqueuelen = ifre.ifr_qlen; + + strncpy(ifre.ifr_name, ifrname, IFNAMSIZ); + ifre.ifr_addr.sa_family = AF_INET; + + if(ioctl(sokfd, SIOCGIFADDR, &ifre) == 0) { + l_ptr->ifaddr = 1; + l_ptr->ifraddr = ifre.ifr_addr; + strncpy(ifre.ifr_name, ifrname, IFNAMSIZ); + if(ioctl(sokfd, SIOCGIFDSTADDR, &ifre) >= 0) + l_ptr->ifrdstaddr = ifre.ifr_dstaddr; + + strncpy(ifre.ifr_name, ifrname, IFNAMSIZ); + if(ioctl(sokfd, SIOCGIFBRDADDR, &ifre) >= 0) + l_ptr->ifrbroadaddr = ifre.ifr_broadaddr; + + strncpy(ifre.ifr_name, ifrname, IFNAMSIZ); + if(ioctl(sokfd, SIOCGIFNETMASK, &ifre) >= 0) + l_ptr->ifrnetmask = ifre.ifr_netmask; + } + close(sokfd); + return 0; +} + +static void get_ifconfig_info(void) +{ + IFACE_LIST *l_ptr; + char buff[BUFSIZ] = {0,}; + int version_num = 0; + + FILE *fp = fopen(PROC_NET_DEV, "r"); + if(fp == NULL) + return; + + fgets(buff, sizeof(buff), fp); //skip 1st header line. + fgets(buff, sizeof(buff), fp); //skip 2nd header line. + + if(strstr(buff, "compressed")) + version_num = 2; + else if(strstr(buff, "bytes")) + version_num = 1; + else + version_num = 0; + + while(fgets(buff, BUFSIZ, fp)) { + l_ptr = xzalloc(sizeof(IFACE_LIST)); + get_proc_info(buff, l_ptr, version_num); + add_iface_to_list(l_ptr); + errno = 0; + if(get_device_info(l_ptr) < 0) { + const char *errstr = strerror(errno); + fclose(fp); + fp = NULL; + clear_list(); + perror_exit("%s: error getting interface info: %s", l_ptr->dev_info.ifrname, errstr); + } + }//end of while. + fclose(fp); + fp = NULL; + return; +} + +static void get_hw_info(int hw_type, HW_INFO *hw_info) +{ +#define HW_UNSPEC -1 + switch(hw_type) { + case ARPHRD_LOOPBACK: //Loopback device. + strncpy(hw_info->hw_name, "loop", HW_NAME_LEN); + strncpy(hw_info->hw_title, "Local Loopback", HW_TITLE_LEN); + hw_info->hw_addrlen = 0; + break; + case ARPHRD_ETHER: //Ethernet + strncpy(hw_info->hw_name, "ether", HW_NAME_LEN); + strncpy(hw_info->hw_title, "Ethernet", HW_TITLE_LEN); + hw_info->hw_addrlen = ETH_ALEN; + break; + case ARPHRD_PPP: //ARPHRD_PPP + strncpy(hw_info->hw_name, "ppp", HW_NAME_LEN); + strncpy(hw_info->hw_title, "Point-to-Point Protocol", HW_TITLE_LEN); + hw_info->hw_addrlen = 0; + break; + case ARPHRD_INFINIBAND: //InfiniBand + strncpy(hw_info->hw_name, "infiniband", HW_NAME_LEN); + strncpy(hw_info->hw_title, "InfiniBand", HW_TITLE_LEN); + hw_info->hw_addrlen = 20; + break; + case ARPHRD_SIT: //sit0 device - IPv6-in-IPv4 + strncpy(hw_info->hw_name, "sit", HW_NAME_LEN); + strncpy(hw_info->hw_title, "IPv6-in-IPv4", HW_TITLE_LEN); + hw_info->hw_addrlen = 0; + break; + case HW_UNSPEC: //UNSPEC + strncpy(hw_info->hw_name, "unspec", HW_NAME_LEN); + strncpy(hw_info->hw_title, "UNSPEC", HW_TITLE_LEN); + hw_info->hw_addrlen = 0; + break; + default: + break; + } +#undef HW_UNSPEC + return; +} + +static void print_hw_addr(int hw_type, HW_INFO hw_info, IFACE_LIST *l_ptr) +{ + unsigned char *address = (unsigned char *) l_ptr->ifrhwaddr.sa_data; + if(!address || (hw_info.hw_addrlen == 0)) + return; + xprintf("HWaddr "); + if(hw_type == ARPHRD_ETHER) + xprintf("%02X:%02X:%02X:%02X:%02X:%02X", address[0], address[1], address[2], + address[3], address[4], address[5]); + return; +} + +static const char *get_ip_addr(struct sockaddr *skaddr) +{ + static char *ip_str = NULL; + struct sockaddr_in *sin; + + if(skaddr->sa_family == 0xFFFF || skaddr->sa_family == 0) + return "[NOT SET]"; + sin = (struct sockaddr_in *)skaddr; + if(sin->sin_family != AF_INET) { + errno = EAFNOSUPPORT; + return NULL; + } + if( (ip_str = inet_ntoa(sin->sin_addr)) != NULL) + return ip_str; + + return NULL; +} + +static void print_ip_addr(IFACE_LIST *l_ptr) +{ + const char *af_name; + int af = l_ptr->ifraddr.sa_family; + if(af == AF_INET) + af_name = "inet"; + else if(af == AF_INET6) + af_name = "inet6"; + else if(af == AF_UNSPEC) + af_name = "unspec"; + + xprintf("%10s%s addr:%s ", " ", af_name, get_ip_addr(&l_ptr->ifraddr)); + if(l_ptr->ifrflags & IFF_POINTOPOINT) + xprintf(" P-t-P:%s ", get_ip_addr(&l_ptr->ifrdstaddr)); + if(l_ptr->ifrflags & IFF_BROADCAST) + xprintf(" Bcast:%s ", get_ip_addr(&l_ptr->ifrbroadaddr)); + xprintf(" Mask:%s\n", get_ip_addr(&l_ptr->ifrnetmask)); + return; +} + +static void print_iface_flags(IFACE_LIST *l_ptr) +{ + if(l_ptr->ifrflags != 0) { + unsigned short mask = 1; + char **str = iface_flags_str; + for(; *str != NULL; str++) { + if(l_ptr->ifrflags & mask) + xprintf("%s ", *str); + mask = mask << 1; + } + } + else + xprintf("[NO FLAGS] "); + return; +} + +static void print_media(IFACE_LIST *l_ptr) +{ +#ifdef IFF_PORTSEL + if(l_ptr->ifrflags & IFF_PORTSEL) { + xprintf("Media:"); + if(l_ptr->ifrmap.port == IF_PORT_UNKNOWN) + xprintf("%s", "unknown"); + else if(l_ptr->ifrmap.port == IF_PORT_10BASE2) + xprintf("%s", "10base2"); + else if(l_ptr->ifrmap.port == IF_PORT_10BASET) + xprintf("%s", "10baseT"); + else if(l_ptr->ifrmap.port == IF_PORT_AUI) + xprintf("%s", "AUI"); + else if(l_ptr->ifrmap.port == IF_PORT_100BASET) + xprintf("%s", "100baseT"); + else if(l_ptr->ifrmap.port == IF_PORT_100BASETX) + xprintf("%s", "100baseTX"); + else if(l_ptr->ifrmap.port == IF_PORT_100BASEFX) + xprintf("%s", "100baseFX"); + if(l_ptr->ifrflags & IFF_AUTOMEDIA) + xprintf("(auto)"); + } +#endif + return; +} + +static void print_ip6_addr(IFACE_LIST *l_ptr) +{ + char iface_name[IFNAMSIZ] = {0,}; + char buf[BUFSIZ] = {0,}; + int plen, scope; + + FILE *fp = fopen(PROC_NET_IFINET6, "r"); + if(fp == NULL) + return; + + while(fgets(buf, BUFSIZ, fp)) { + int nitems = 0; + char ipv6_addr[40] = {0,}; + nitems = sscanf(buf, "%32s %*08x %02x %02x %*02x %16s\n", + ipv6_addr+7, &plen, &scope, iface_name); + if(nitems != 4) { + if((nitems < 0) && feof(fp)) + break; + perror_exit("sscanf"); + } + if(strcmp(l_ptr->dev_info.ifrname,iface_name) == 0) { + int i = 0; + struct sockaddr_in6 sock_in6; + int len = sizeof(ipv6_addr) / (sizeof ipv6_addr[0]); + char *ptr = ipv6_addr+7; + while((i < len-2) && (*ptr)) { + ipv6_addr[i++] = *ptr++; + //put ':' after 4th bit + if(!((i+1) % 5)) + ipv6_addr[i++] = ':'; + } + ipv6_addr[i+1] = '\0'; + if(inet_pton(AF_INET6, ipv6_addr, (struct sockaddr *) &sock_in6.sin6_addr) > 0) { + sock_in6.sin6_family = AF_INET6; + memset(buf, 0, (sizeof(buf) /sizeof(buf[0]))); + if(inet_ntop(AF_INET6, &sock_in6.sin6_addr, buf, BUFSIZ) > 0) { + xprintf("%10sinet6 addr: %s/%d", " ", buf, plen); + xprintf(" Scope:"); + if(scope == IPV6_ADDR_ANY) xprintf(" Global"); + else if(scope == IPV6_ADDR_LOOPBACK) xprintf(" Host"); + else if(scope == IPV6_ADDR_LINKLOCAL) xprintf(" Link"); + else if(scope == IPV6_ADDR_SITELOCAL) xprintf(" Site"); + else if(scope == IPV6_ADDR_COMPATv4) xprintf(" Compat"); + else xprintf("Unknown"); + xprintf("\n"); + } + } + } + }//end of while. + fclose(fp); + fp = NULL; + return; +} + +static void display_ifconfig(IFACE_LIST *l_ptr) +{ + HW_INFO hw_info; + int hw_type = l_ptr->hw_type; + + memset(&hw_info, 0, sizeof(HW_INFO)); + + get_hw_info(hw_type, &hw_info); + xprintf("%-9s Link encap:%s ", l_ptr->dev_info.ifrname, hw_info.hw_title); + print_hw_addr(hw_type, hw_info, l_ptr); + + print_media(l_ptr); + + xprintf("\n"); + if(l_ptr->ifaddr) + print_ip_addr(l_ptr); //print addr, p-p addr, broadcast addr and mask addr. + + //for ipv6 to do. + print_ip6_addr(l_ptr); + xprintf("%10s", " "); + //print flags + print_iface_flags(l_ptr); + if(!l_ptr->ifrmetric) + l_ptr->ifrmetric = 1; + xprintf(" MTU:%d Metric:%d", l_ptr->ifrmtu, l_ptr->ifrmetric); + xprintf("\n%10s", " "); + xprintf("RX packets:%llu errors:%lu dropped:%lu overruns:%lu frame:%lu\n", + l_ptr->dev_info.receive_packets, l_ptr->dev_info.receive_errors, + l_ptr->dev_info.receive_drop, l_ptr->dev_info.receive_fifo, + l_ptr->dev_info.receive_frame); + //Dummy types for non ARP hardware. + if((hw_type == ARPHRD_CSLIP) || (hw_type == ARPHRD_CSLIP6)) + xprintf("%10scompressed:%lu\n", " ", l_ptr->dev_info.receive_compressed); + xprintf("%10sTX packets:%llu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n", " ", + l_ptr->dev_info.transmit_packets, l_ptr->dev_info.transmit_errors, + l_ptr->dev_info.transmit_drop, l_ptr->dev_info.transmit_fifo, + l_ptr->dev_info.transmit_carrier); + xprintf("%10scollisions:%lu ", " ", l_ptr->dev_info.transmit_colls); + //Dummy types for non ARP hardware. + if((hw_type == ARPHRD_CSLIP) || (hw_type == ARPHRD_CSLIP6)) + xprintf("compressed:%lu ", l_ptr->dev_info.transmit_compressed); + if(l_ptr->txqueuelen != NO_RANGE) + xprintf("txqueuelen:%d ", l_ptr->txqueuelen); + + xprintf("\n%10s", " "); + xprintf("RX bytes:%llu ", l_ptr->dev_info.receive_bytes); + xprintf("TX bytes:%llu\n", l_ptr->dev_info.transmit_bytes); + if(l_ptr->ifrmap.irq || l_ptr->ifrmap.mem_start || l_ptr->ifrmap.dma || l_ptr->ifrmap.base_addr) { + xprintf("%10s", " "); + if(l_ptr->ifrmap.irq) + xprintf("Interrupt:%d ", l_ptr->ifrmap.irq); + if(l_ptr->ifrmap.base_addr >= IO_MAP_INDEX) + xprintf("Base address:0x%lx ", l_ptr->ifrmap.base_addr); + if(l_ptr->ifrmap.mem_start) + xprintf("Memory:%lx-%lx ", l_ptr->ifrmap.mem_start, l_ptr->ifrmap.mem_end); + if(l_ptr->ifrmap.dma) + xprintf("DMA chan:%x ", l_ptr->ifrmap.dma); + xprintf("\n"); + } + xprintf("\n"); + return; +} + +static int show_iface(char *iface_name) +{ + get_ifconfig_info(); + if(iface_name) { + IFACE_LIST *l_ptr; + int is_dev_found = 0; + for(l_ptr = iface_list_head; l_ptr; l_ptr = l_ptr->next) { + if(strcmp(l_ptr->dev_info.ifrname, iface_name) == 0) { + is_dev_found = 1; + display_ifconfig(l_ptr); + break; + } + } + if(!is_dev_found) { + error_msg("%s: error getting interface info.", iface_name); + return 1; + } + } + else { + IFACE_LIST *l_ptr; + for(l_ptr = iface_list_head; l_ptr; l_ptr = l_ptr->next) { + if((l_ptr->ifrflags & IFF_UP) || (toys.optflags & FLAG_a)) + display_ifconfig(l_ptr); + } + } + return 0; +} + +static void clear_list(void) +{ + IFACE_LIST *temp_ptr; + while(iface_list_head != NULL) { + temp_ptr = iface_list_head->next; + free(iface_list_head); + iface_list_head = temp_ptr; + } + return; +} |