linux 网络编程配置网卡信息

1、ioctl /usr/include/linux/sockios.h

# cat /usr/include/linux/sockios.h
/*
 * INET     An implementation of the TCP/IP protocol suite for the LINUX
 *      operating system.  INET is implemented using the  BSD Socket
 *      interface as the means of communication with the user level.
 *
 *      Definitions of the socket-level I/O control calls.
 *
 * Version: @(#)sockios.h   1.0.2   03/09/93
 *
 * Authors: Ross Biro
 *      Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
 *
 *      This program 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
 *      2 of the License, or (at your option) any later version.
 */
#ifndef _LINUX_SOCKIOS_H
#define _LINUX_SOCKIOS_H

#include <asm/sockios.h>

/* Linux-specific socket ioctls */
#define SIOCINQ     FIONREAD
#define SIOCOUTQ    TIOCOUTQ        /* output queue size (not sent + not acked) */

/* Routing table calls. */
#define SIOCADDRT   0x890B      /* add routing table entry  */
#define SIOCDELRT   0x890C      /* delete routing table entry   */
#define SIOCRTMSG   0x890D      /* call to routing system   */

/* Socket configuration controls. */
#define SIOCGIFNAME 0x8910      /* get iface name       */
#define SIOCSIFLINK 0x8911      /* set iface channel        */
#define SIOCGIFCONF 0x8912      /* get iface list       */
#define SIOCGIFFLAGS    0x8913      /* get flags            */
#define SIOCSIFFLAGS    0x8914      /* set flags            */
#define SIOCGIFADDR 0x8915      /* get PA address       */
#define SIOCSIFADDR 0x8916      /* set PA address       */
#define SIOCGIFDSTADDR  0x8917      /* get remote PA address    */
#define SIOCSIFDSTADDR  0x8918      /* set remote PA address    */
#define SIOCGIFBRDADDR  0x8919      /* get broadcast PA address */
#define SIOCSIFBRDADDR  0x891a      /* set broadcast PA address */
#define SIOCGIFNETMASK  0x891b      /* get network PA mask      */
#define SIOCSIFNETMASK  0x891c      /* set network PA mask      */
#define SIOCGIFMETRIC   0x891d      /* get metric           */
#define SIOCSIFMETRIC   0x891e      /* set metric           */
#define SIOCGIFMEM  0x891f      /* get memory address (BSD) */
#define SIOCSIFMEM  0x8920      /* set memory address (BSD) */
#define SIOCGIFMTU  0x8921      /* get MTU size         */
#define SIOCSIFMTU  0x8922      /* set MTU size         */
#define SIOCSIFNAME 0x8923      /* set interface name */
#define SIOCSIFHWADDR   0x8924      /* set hardware address     */
#define SIOCGIFENCAP    0x8925      /* get/set encapsulations       */
#define SIOCSIFENCAP    0x8926
#define SIOCGIFHWADDR   0x8927      /* Get hardware address     */
#define SIOCGIFSLAVE    0x8929      /* Driver slaving support   */
#define SIOCSIFSLAVE    0x8930
#define SIOCADDMULTI    0x8931      /* Multicast address lists  */
#define SIOCDELMULTI    0x8932
#define SIOCGIFINDEX    0x8933      /* name -> if_index mapping */
#define SIOGIFINDEX SIOCGIFINDEX    /* misprint compatibility :-)   */
#define SIOCSIFPFLAGS   0x8934      /* set/get extended flags set   */
#define SIOCGIFPFLAGS   0x8935
#define SIOCDIFADDR 0x8936      /* delete PA address        */
#define SIOCSIFHWBROADCAST  0x8937  /* set hardware broadcast addr  */
#define SIOCGIFCOUNT    0x8938      /* get number of devices */

#define SIOCGIFBR   0x8940      /* Bridging support     */
#define SIOCSIFBR   0x8941      /* Set bridging options     */

#define SIOCGIFTXQLEN   0x8942      /* Get the tx queue length  */
#define SIOCSIFTXQLEN   0x8943      /* Set the tx queue length  */

/* SIOCGIFDIVERT was:   0x8944      Frame diversion support */
/* SIOCSIFDIVERT was:   0x8945      Set frame diversion options */

#define SIOCETHTOOL 0x8946      /* Ethtool interface        */

#define SIOCGMIIPHY 0x8947      /* Get address of MII PHY in use. */
#define SIOCGMIIREG 0x8948      /* Read MII PHY register.   */
#define SIOCSMIIREG 0x8949      /* Write MII PHY register.  */

#define SIOCWANDEV  0x894A      /* get/set netdev parameters    */

#define SIOCOUTQNSD 0x894B      /* output queue size (not sent only) */

/* ARP cache control calls. */
            /*  0x8950 - 0x8952  * obsolete calls, don't re-use */
#define SIOCDARP    0x8953      /* delete ARP table entry   */
#define SIOCGARP    0x8954      /* get ARP table entry      */
#define SIOCSARP    0x8955      /* set ARP table entry      */

/* RARP cache control calls. */
#define SIOCDRARP   0x8960      /* delete RARP table entry  */
#define SIOCGRARP   0x8961      /* get RARP table entry     */
#define SIOCSRARP   0x8962      /* set RARP table entry     */

/* Driver configuration calls */

#define SIOCGIFMAP  0x8970      /* Get device parameters    */
#define SIOCSIFMAP  0x8971      /* Set device parameters    */

/* DLCI configuration calls */

#define SIOCADDDLCI 0x8980      /* Create new DLCI device   */
#define SIOCDELDLCI 0x8981      /* Delete DLCI device       */

#define SIOCGIFVLAN 0x8982      /* 802.1Q VLAN support      */
#define SIOCSIFVLAN 0x8983      /* Set 802.1Q VLAN options  */

/* bonding calls */

#define SIOCBONDENSLAVE 0x8990      /* enslave a device to the bond */
#define SIOCBONDRELEASE 0x8991      /* release a slave from the bond*/
#define SIOCBONDSETHWADDR      0x8992   /* set the hw addr of the bond  */
#define SIOCBONDSLAVEINFOQUERY 0x8993   /* rtn info about slave state   */
#define SIOCBONDINFOQUERY      0x8994   /* rtn info about bond state    */
#define SIOCBONDCHANGEACTIVE   0x8995   /* update to a new active slave */

/* bridge calls */
#define SIOCBRADDBR     0x89a0      /* create new bridge device     */
#define SIOCBRDELBR     0x89a1      /* remove bridge device         */
#define SIOCBRADDIF 0x89a2      /* add interface to bridge      */
#define SIOCBRDELIF 0x89a3      /* remove interface from bridge */

/* hardware time stamping: parameters in linux/net_tstamp.h */
#define SIOCSHWTSTAMP   0x89b0      /* set and get config       */
#define SIOCGHWTSTAMP   0x89b1      /* get config           */

/* Device private ioctl calls */

/*
 *  These 16 ioctls are available to devices via the do_ioctl() device
 *  vector. Each device should include this file and redefine these names
 *  as their own. Because these are device dependent it is a good idea
 *  _NOT_ to issue them to random objects and hope.
 *
 *  THESE IOCTLS ARE _DEPRECATED_ AND WILL DISAPPEAR IN 2.5.X -DaveM
 */

#define SIOCDEVPRIVATE  0x89F0  /* to 89FF */

/*
 *  These 16 ioctl calls are protocol private
 */

#define SIOCPROTOPRIVATE 0x89E0

2、/usr/include/net/if.h

https://unix.superglobalmegacorp.com/Net2/newsrc/net/if.h.html

# cat /usr/include/net/if.h
/* net/if.h -- declarations for inquiring about network interfaces
   Copyright (C) 1997,98,99,2000,2001,2012 Free Software Foundation, Inc.
   This file is part of the GNU C Library.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library 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
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, see
   <http://www.gnu.org/licenses/>.  */

#ifndef _NET_IF_H
#define _NET_IF_H 1

#include <features.h>

#ifdef __USE_MISC
# include <sys/types.h>
# include <sys/socket.h>
#endif


/* Length of interface name.  */
#define IF_NAMESIZE 16

struct if_nameindex
  {
    unsigned int if_index;  /* 1, 2, ... */
    char *if_name;    /* null terminated name: "eth0", ... */
  };


#ifdef __USE_MISC
/* Standard interface flags. */
enum
  {
    IFF_UP = 0x1,   /* Interface is up.  */
# define IFF_UP IFF_UP
    IFF_BROADCAST = 0x2,  /* Broadcast address valid.  */
# define IFF_BROADCAST  IFF_BROADCAST
    IFF_DEBUG = 0x4,    /* Turn on debugging.  */
# define IFF_DEBUG  IFF_DEBUG
    IFF_LOOPBACK = 0x8,   /* Is a loopback net.  */
# define IFF_LOOPBACK IFF_LOOPBACK
    IFF_POINTOPOINT = 0x10, /* Interface is point-to-point link.  */
# define IFF_POINTOPOINT IFF_POINTOPOINT
    IFF_NOTRAILERS = 0x20,  /* Avoid use of trailers.  */
# define IFF_NOTRAILERS IFF_NOTRAILERS
    IFF_RUNNING = 0x40,   /* Resources allocated.  */
# define IFF_RUNNING  IFF_RUNNING
    IFF_NOARP = 0x80,   /* No address resolution protocol.  */
# define IFF_NOARP  IFF_NOARP
    IFF_PROMISC = 0x100,  /* Receive all packets.  */
# define IFF_PROMISC  IFF_PROMISC

    /* Not supported */
    IFF_ALLMULTI = 0x200, /* Receive all multicast packets.  */
# define IFF_ALLMULTI IFF_ALLMULTI

    IFF_MASTER = 0x400,   /* Master of a load balancer.  */
# define IFF_MASTER IFF_MASTER
    IFF_SLAVE = 0x800,    /* Slave of a load balancer.  */
# define IFF_SLAVE  IFF_SLAVE

    IFF_MULTICAST = 0x1000, /* Supports multicast.  */
# define IFF_MULTICAST  IFF_MULTICAST

    IFF_PORTSEL = 0x2000, /* Can set media type.  */
# define IFF_PORTSEL  IFF_PORTSEL
    IFF_AUTOMEDIA = 0x4000, /* Auto media select active.  */
# define IFF_AUTOMEDIA  IFF_AUTOMEDIA
    IFF_DYNAMIC = 0x8000  /* Dialup device with changing addresses.  */
# define IFF_DYNAMIC  IFF_DYNAMIC
  };

/* The ifaddr structure contains information about one address of an
   interface.  They are maintained by the different address families,
   are allocated and attached when an address is set, and are linked
   together so all addresses for an interface can be located.  */

struct ifaddr
  {
    struct sockaddr ifa_addr; /* Address of interface.  */
    union
      {
  struct sockaddr ifu_broadaddr;
  struct sockaddr ifu_dstaddr;
      } ifa_ifu;
    struct iface *ifa_ifp;  /* Back-pointer to interface.  */
    struct ifaddr *ifa_next;  /* Next address for interface.  */
  };

# define ifa_broadaddr  ifa_ifu.ifu_broadaddr /* broadcast address  */
# define ifa_dstaddr  ifa_ifu.ifu_dstaddr /* other end of link  */

/* Device mapping structure. I'd just gone off and designed a
   beautiful scheme using only loadable modules with arguments for
   driver options and along come the PCMCIA people 8)

   Ah well. The get() side of this is good for WDSETUP, and it'll be
   handy for debugging things. The set side is fine for now and being
   very small might be worth keeping for clean configuration.  */

struct ifmap
  {
    unsigned long int mem_start;
    unsigned long int mem_end;
    unsigned short int base_addr;
    unsigned char irq;
    unsigned char dma;
    unsigned char port;
    /* 3 bytes spare */
  };

/* Interface request structure used for socket ioctl's.  All interface
   ioctl's must have parameter definitions which begin with ifr_name.
   The remainder may be interface specific.  */

struct ifreq
  {
# define IFHWADDRLEN  6
# define IFNAMSIZ IF_NAMESIZE
    union
      {
  char ifrn_name[IFNAMSIZ]; /* Interface name, e.g. "en0".  */
      } ifr_ifrn;

    union
      {
  struct sockaddr ifru_addr;
  struct sockaddr ifru_dstaddr;
  struct sockaddr ifru_broadaddr;
  struct sockaddr ifru_netmask;
  struct sockaddr ifru_hwaddr;
  short int ifru_flags;
  int ifru_ivalue;
  int ifru_mtu;
  struct ifmap ifru_map;
  char ifru_slave[IFNAMSIZ];  /* Just fits the size */
  char ifru_newname[IFNAMSIZ];
  __caddr_t ifru_data;
      } ifr_ifru;
  };
# define ifr_name ifr_ifrn.ifrn_name  /* interface name   */
# define ifr_hwaddr ifr_ifru.ifru_hwaddr  /* MAC address    */
# define ifr_addr ifr_ifru.ifru_addr  /* address    */
# define ifr_dstaddr  ifr_ifru.ifru_dstaddr /* other end of p-p lnk */
# define ifr_broadaddr  ifr_ifru.ifru_broadaddr /* broadcast address  */
# define ifr_netmask  ifr_ifru.ifru_netmask /* interface net mask */
# define ifr_flags  ifr_ifru.ifru_flags /* flags    */
# define ifr_metric ifr_ifru.ifru_ivalue  /* metric   */
# define ifr_mtu  ifr_ifru.ifru_mtu /* mtu      */
# define ifr_map  ifr_ifru.ifru_map /* device map   */
# define ifr_slave  ifr_ifru.ifru_slave /* slave device   */
# define ifr_data ifr_ifru.ifru_data  /* for use by interface */
# define ifr_ifindex  ifr_ifru.ifru_ivalue    /* interface index      */
# define ifr_bandwidth  ifr_ifru.ifru_ivalue  /* link bandwidth */
# define ifr_qlen ifr_ifru.ifru_ivalue  /* queue length   */
# define ifr_newname  ifr_ifru.ifru_newname /* New name   */
# define _IOT_ifreq _IOT(_IOTS(char),IFNAMSIZ,_IOTS(char),16,0,0)
# define _IOT_ifreq_short _IOT(_IOTS(char),IFNAMSIZ,_IOTS(short),1,0,0)
# define _IOT_ifreq_int _IOT(_IOTS(char),IFNAMSIZ,_IOTS(int),1,0,0)


/* Structure used in SIOCGIFCONF request.  Used to retrieve interface
   configuration for machine (useful for programs which must know all
   networks accessible).  */

struct ifconf
  {
    int ifc_len;      /* Size of buffer.  */
    union
      {
  __caddr_t ifcu_buf;
  struct ifreq *ifcu_req;
      } ifc_ifcu;
  };
# define ifc_buf  ifc_ifcu.ifcu_buf /* Buffer address.  */
# define ifc_req  ifc_ifcu.ifcu_req /* Array of structures.  */
# define _IOT_ifconf _IOT(_IOTS(struct ifconf),1,0,0,0,0) /* not right */
#endif  /* Misc.  */

__BEGIN_DECLS

/* Convert an interface name to an index, and vice versa.  */
extern unsigned int if_nametoindex (const char *__ifname) __THROW;
extern char *if_indextoname (unsigned int __ifindex, char *__ifname) __THROW;

/* Return a list of all interfaces and their indices.  */
extern struct if_nameindex *if_nameindex (void) __THROW;

/* Free the data returned from if_nameindex.  */
extern void if_freenameindex (struct if_nameindex *__ptr) __THROW;

__END_DECLS

#endif /* net/if.h */

3、 net-tools 

https://net-tools.sourceforge.io/

https://sourceforge.net/projects/net-tools/

ifconfig.c

/*
 * ifconfig   This file contains an implementation of the command
 *              that either displays or sets the characteristics of
 *              one or more of the system's networking interfaces.
 *
 * Version:     $Id: ifconfig.c,v 1.59 2011-01-01 03:22:31 ecki Exp $
 *
 * Author:      Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
 *              and others.  Copyright 1993 MicroWalt Corporation
 *
 *              This program 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 2 of the License, or  (at
 *              your option) any later version.
 *
 * Patched to support 'add' and 'del' keywords for INET(4) addresses
 * by Mrs. Brisby <mrs.brisby@nimh.org>
 *
 * {1.34} - 19980630 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 *                     - gettext instead of catgets for i18n
 *          10/1998  - Andi Kleen. Use interface list primitives.
 *        20001008 - Bernd Eckenfels, Patch from RH for setting mtu
 *            (default AF was wrong)
 *          20010404 - Arnaldo Carvalho de Melo, use setlocale
 */

#define DFLT_AF "inet"

#include "config.h"

#include <features.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>

/* Ugh.  But libc5 doesn't provide POSIX types.  */
#include <asm/types.h>


#if HAVE_HWSLIP
#include <linux/if_slip.h>
#endif

#if HAVE_AFINET6

#ifndef _LINUX_IN6_H
/*
 *    This is in linux/include/net/ipv6.h.
 */

struct in6_ifreq {
    struct in6_addr ifr6_addr;
    __u32 ifr6_prefixlen;
    unsigned int ifr6_ifindex;
};

#endif

#endif                /* HAVE_AFINET6 */

#if HAVE_AFIPX
#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1)
#include <netipx/ipx.h>
#else
#include "ipx.h"
#endif
#endif
#include "net-support.h"
#include "pathnames.h"
#include "version.h"
#include "../intl.h"
#include "interface.h"
#include "sockets.h"
#include "util.h"

static char *Release = RELEASE;

int opt_a = 0;            /* show all interfaces          */
int opt_v = 0;            /* debugging output flag        */

int addr_family = 0;        /* currently selected AF        */

/* for ipv4 add/del modes */
static int get_nmbc_parent(char *parent, in_addr_t *nm, in_addr_t *bc);
static int set_ifstate(char *parent, in_addr_t ip, in_addr_t nm, in_addr_t bc,
               int flag);

static int if_print(char *ifname)
{
    int res;

    if (ife_short)
    printf(_("Iface      MTU    RX-OK RX-ERR RX-DRP RX-OVR    TX-OK TX-ERR TX-DRP TX-OVR Flg\n"));

    if (!ifname) {
    res = for_all_interfaces(do_if_print, &opt_a);
    } else {
    struct interface *ife;

    ife = lookup_interface(ifname);
    if (!ife) {
        return -1;
    }
    res = do_if_fetch(ife);
    if (res >= 0)
        ife_print(ife);
    }
    return res;
}

/* Set a certain interface flag. */
static int set_flag(char *ifname, short flag)
{
    struct ifreq ifr;

    safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
    if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
    fprintf(stderr, _("%s: ERROR while getting interface flags: %s\n"),
        ifname,    strerror(errno));
    return (-1);
    }
    safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
    ifr.ifr_flags |= flag;
    if (ioctl(skfd, SIOCSIFFLAGS, &ifr) < 0) {
    perror("SIOCSIFFLAGS");
    return -1;
    }
    return (0);
}

/* Clear a certain interface flag. */
static int clr_flag(char *ifname, short flag)
{
    struct ifreq ifr;
    int fd;

    if (strchr(ifname, ':')) {
        /* This is a v4 alias interface.  Downing it via a socket for
       another AF may have bad consequences. */
        fd = get_socket_for_af(AF_INET);
    if (fd < 0) {
        fprintf(stderr, _("No support for INET on this system.\n"));
        return -1;
    }
    } else
        fd = skfd;

    safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
    if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
    fprintf(stderr, _("%s: ERROR while getting interface flags: %s\n"),
        ifname, strerror(errno));
    return -1;
    }
    safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
    ifr.ifr_flags &= ~flag;
    if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
    perror("SIOCSIFFLAGS");
    return -1;
    }
    return (0);
}

/** test is a specified flag is set */
static int test_flag(char *ifname, short flags)
{
    struct ifreq ifr;
    int fd;

    if (strchr(ifname, ':')) {
        /* This is a v4 alias interface.  Downing it via a socket for
       another AF may have bad consequences. */
        fd = get_socket_for_af(AF_INET);
    if (fd < 0) {
        fprintf(stderr, _("No support for INET on this system.\n"));
        return -1;
    }
    } else
        fd = skfd;

    safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
    if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
    fprintf(stderr, _("%s: ERROR while testing interface flags: %s\n"),
        ifname, strerror(errno));
    return -1;
    }
    return (ifr.ifr_flags & flags);
}

static void usage(int rc)
{
    FILE *fp = rc ? stderr : stdout;
    fprintf(fp, _("Usage:\n  ifconfig [-a] [-v] [-s] <interface> [[<AF>] <address>]\n"));
#if HAVE_AFINET
    fprintf(fp, _("  [add <address>[/<prefixlen>]]\n"));
    fprintf(fp, _("  [del <address>[/<prefixlen>]]\n"));
    fprintf(fp, _("  [[-]broadcast [<address>]]  [[-]pointopoint [<address>]]\n"));
    fprintf(fp, _("  [netmask <address>]  [dstaddr <address>]  [tunnel <address>]\n"));
#endif
#ifdef SIOCSKEEPALIVE
    fprintf(fp, _("  [outfill <NN>] [keepalive <NN>]\n"));
#endif
    fprintf(fp, _("  [hw <HW> <address>]  [mtu <NN>]\n"));
    fprintf(fp, _("  [[-]trailers]  [[-]arp]  [[-]allmulti]\n"));
    fprintf(fp, _("  [multicast]  [[-]promisc]\n"));
    fprintf(fp, _("  [mem_start <NN>]  [io_addr <NN>]  [irq <NN>]  [media <type>]\n"));
#ifdef HAVE_TXQUEUELEN
    fprintf(fp, _("  [txqueuelen <NN>]\n"));
#endif
#ifdef SIOCSIFNAME
    fprintf(fp, _("  [name <newname>]\n"));
#endif
#ifdef HAVE_DYNAMIC
    fprintf(fp, _("  [[-]dynamic]\n"));
#endif
    fprintf(fp, _("  [up|down] ...\n\n"));

    fprintf(fp, _("  <HW>=Hardware Type.\n"));
    fprintf(fp, _("  List of possible hardware types:\n"));
    print_hwlist(0); /* 1 = ARPable */
    fprintf(fp, _("  <AF>=Address family. Default: %s\n"), DFLT_AF);
    fprintf(fp, _("  List of possible address families:\n"));
    print_aflist(0); /* 1 = routeable */
    exit(rc);
}

static void version(void)
{
    printf("%s\n", Release);
    exit(E_VERSION);
}

static int set_netmask(int skfd, struct ifreq *ifr, struct sockaddr *sa)
{
    int err = 0;

    memcpy(&ifr->ifr_netmask, sa, sizeof(struct sockaddr));
    if (ioctl(skfd, SIOCSIFNETMASK, ifr) < 0) {
    fprintf(stderr, "SIOCSIFNETMASK: %s\n",
        strerror(errno));
    err = 1;
    }
    return err;
}

int main(int argc, char **argv)
{
    struct sockaddr_storage _sa, _samask;
    struct sockaddr *sa = (struct sockaddr *)&_sa;
    struct sockaddr *samask = (struct sockaddr *)&_samask;
    struct sockaddr_in *sin = (struct sockaddr_in *)&_sa;
    char host[128];
    const struct aftype *ap;
    const struct hwtype *hw;
    struct ifreq ifr;
    int goterr = 0, didnetmask = 0, neednetmask=0;
    char **spp;
    int fd;
#if HAVE_AFINET6
    extern struct aftype inet6_aftype;
    struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&_sa;
    struct in6_ifreq ifr6;
    unsigned long prefix_len;
    char *cp;
#endif
#if HAVE_AFINET
    extern struct aftype inet_aftype;
#endif

#if I18N
    setlocale(LC_ALL, "");
    bindtextdomain("net-tools", "/usr/share/locale");
    textdomain("net-tools");
#endif

    /* Find any options. */
    argc--;
    argv++;
    while (argc && *argv[0] == '-') {
    if (!strcmp(*argv, "-a"))
        opt_a = 1;

    else if (!strcmp(*argv, "-s"))
        ife_short = 1;

    else if (!strcmp(*argv, "-v"))
        opt_v = 1;

    else if (!strcmp(*argv, "-V") || !strcmp(*argv, "-version") ||
        !strcmp(*argv, "--version"))
        version();

    else if (!strcmp(*argv, "-?") || !strcmp(*argv, "-h") ||
        !strcmp(*argv, "-help") || !strcmp(*argv, "--help"))
        usage(E_USAGE);

    else {
        fprintf(stderr, _("ifconfig: option `%s' not recognised.\n"),
            argv[0]);
        fprintf(stderr, _("ifconfig: `--help' gives usage information.\n"));
        exit(1);
    }

    argv++;
    argc--;
    }

    /* Create a channel to the NET kernel. */
    if ((skfd = sockets_open(0)) < 0) {
    perror("socket");
    exit(1);
    }

    /* Do we have to show the current setup? */
    if (argc == 0) {
    int err = if_print((char *) NULL);
    (void) close(skfd);
    exit(err < 0);
    }
    /* No. Fetch the interface name. */
    spp = argv;
    safe_strncpy(ifr.ifr_name, *spp++, IFNAMSIZ);
    if (*spp == (char *) NULL) {
    int err = if_print(ifr.ifr_name);
    (void) close(skfd);
    exit(err < 0);
    }

    /* The next argument is either an address family name, or an option. */
    if ((ap = get_aftype(*spp)) != NULL)
    spp++; /* it was a AF name */
    else
    ap = get_aftype(DFLT_AF);

    if (ap) {
    addr_family = ap->af;
    skfd = ap->fd;
    }

    /* Process the remaining arguments. */
    while (*spp != (char *) NULL) {
    if (!strcmp(*spp, "arp")) {
        goterr |= clr_flag(ifr.ifr_name, IFF_NOARP);
        spp++;
        continue;
    }
    if (!strcmp(*spp, "-arp")) {
        goterr |= set_flag(ifr.ifr_name, IFF_NOARP);
        spp++;
        continue;
    }
#ifdef IFF_PORTSEL
    if (!strcmp(*spp, "media") || !strcmp(*spp, "port")) {
        if (*++spp == NULL)
        usage(E_OPTERR);
        if (!strcasecmp(*spp, "auto")) {
        goterr |= set_flag(ifr.ifr_name, IFF_AUTOMEDIA);
        } else {
        int i, j, newport;
        char *endp;
        newport = strtol(*spp, &endp, 10);
        if (*endp != 0) {
            newport = -1;
            for (i = 0; if_port_text[i][0] && newport == -1; i++) {
            for (j = 0; if_port_text[i][j]; j++) {
                if (!strcasecmp(*spp, if_port_text[i][j])) {
                newport = i;
                break;
                }
            }
            }
        }
        spp++;
        if (newport == -1) {
            fprintf(stderr, _("Unknown media type.\n"));
            goterr = 1;
        } else {
            if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
            perror("port: SIOCGIFMAP");
            goterr = 1;
            continue;
            }
            ifr.ifr_map.port = newport;
            if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
            perror("port: SIOCSIFMAP");
            goterr = 1;
            }
        }
        }
        continue;
    }
#endif

    if (!strcmp(*spp, "trailers")) {
        goterr |= clr_flag(ifr.ifr_name, IFF_NOTRAILERS);
        spp++;
        continue;
    }
    if (!strcmp(*spp, "-trailers")) {
        goterr |= set_flag(ifr.ifr_name, IFF_NOTRAILERS);
        spp++;
        continue;
    }
    if (!strcmp(*spp, "promisc")) {
        goterr |= set_flag(ifr.ifr_name, IFF_PROMISC);
        spp++;
        continue;
    }
    if (!strcmp(*spp, "-promisc")) {
        goterr |= clr_flag(ifr.ifr_name, IFF_PROMISC);
        if (test_flag(ifr.ifr_name, IFF_PROMISC) > 0)
            fprintf(stderr, _("Warning: Interface %s still in promisc mode... maybe other application is running?\n"), ifr.ifr_name);
        spp++;
        continue;
    }
    if (!strcmp(*spp, "multicast")) {
        goterr |= set_flag(ifr.ifr_name, IFF_MULTICAST);
        spp++;
        continue;
    }
    if (!strcmp(*spp, "-multicast")) {
        goterr |= clr_flag(ifr.ifr_name, IFF_MULTICAST);
        if (test_flag(ifr.ifr_name, IFF_MULTICAST) > 0)
            fprintf(stderr, _("Warning: Interface %s still in MULTICAST mode.\n"), ifr.ifr_name);
        spp++;
        continue;
    }
    if (!strcmp(*spp, "allmulti")) {
        goterr |= set_flag(ifr.ifr_name, IFF_ALLMULTI);
        spp++;
        continue;
    }
    if (!strcmp(*spp, "-allmulti")) {
        goterr |= clr_flag(ifr.ifr_name, IFF_ALLMULTI);
        if (test_flag(ifr.ifr_name, IFF_ALLMULTI) > 0)
            fprintf(stderr, _("Warning: Interface %s still in ALLMULTI mode.\n"), ifr.ifr_name);
        spp++;
        continue;
    }
    if (!strcmp(*spp, "up")) {
        goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
        spp++;
        continue;
    }
    if (!strcmp(*spp, "down")) {
        goterr |= clr_flag(ifr.ifr_name, IFF_UP);
        spp++;
        continue;
    }
#ifdef HAVE_DYNAMIC
    if (!strcmp(*spp, "dynamic")) {
        goterr |= set_flag(ifr.ifr_name, IFF_DYNAMIC);
        spp++;
        continue;
    }
    if (!strcmp(*spp, "-dynamic")) {
        goterr |= clr_flag(ifr.ifr_name, IFF_DYNAMIC);
        spp++;
        if (test_flag(ifr.ifr_name, IFF_DYNAMIC) > 0)
            fprintf(stderr, _("Warning: Interface %s still in DYNAMIC mode.\n"), ifr.ifr_name);
        continue;
    }
#endif

    if (!strcmp(*spp, "mtu")) {
        if (*++spp == NULL)
        usage(E_OPTERR);
        ifr.ifr_mtu = atoi(*spp);
        if (ioctl(skfd, SIOCSIFMTU, &ifr) < 0) {
        fprintf(stderr, "SIOCSIFMTU: %s\n", strerror(errno));
        goterr = 1;
        }
        spp++;
        continue;
    }
#ifdef SIOCSKEEPALIVE
    if (!strcmp(*spp, "keepalive")) {
        if (*++spp == NULL)
        usage(E_OPTERR);
        ifr.ifr_data = (caddr_t) (uintptr_t) atoi(*spp);
        if (ioctl(skfd, SIOCSKEEPALIVE, &ifr) < 0) {
        fprintf(stderr, "SIOCSKEEPALIVE: %s\n", strerror(errno));
        goterr = 1;
        }
        spp++;
        continue;
    }
#endif

#ifdef SIOCSOUTFILL
    if (!strcmp(*spp, "outfill")) {
        if (*++spp == NULL)
        usage(E_OPTERR);
        ifr.ifr_data = (caddr_t) (uintptr_t) atoi(*spp);
        if (ioctl(skfd, SIOCSOUTFILL, &ifr) < 0) {
        fprintf(stderr, "SIOCSOUTFILL: %s\n", strerror(errno));
        goterr = 1;
        }
        spp++;
        continue;
    }
#endif

    if (!strcmp(*spp, "-broadcast")) {
        goterr |= clr_flag(ifr.ifr_name, IFF_BROADCAST);
        if (test_flag(ifr.ifr_name, IFF_BROADCAST) > 0)
            fprintf(stderr, _("Warning: Interface %s still in BROADCAST mode.\n"), ifr.ifr_name);
        spp++;
        continue;
    }
    if (!strcmp(*spp, "broadcast")) {
        if (*++spp != NULL) {
        safe_strncpy(host, *spp, (sizeof host));
        if (ap->input(0, host, &_sa) < 0) {
            if (ap->herror)
                ap->herror(host);
            else
                fprintf(stderr, _("ifconfig: Error resolving '%s' for broadcast\n"), host);
            goterr = 1;
            spp++;
            continue;
        }
        memcpy(&ifr.ifr_broadaddr, sa, sizeof(struct sockaddr));
        if (ioctl(ap->fd, SIOCSIFBRDADDR, &ifr) < 0) {
            fprintf(stderr, "SIOCSIFBRDADDR: %s\n",
                strerror(errno));
            goterr = 1;
        }
        spp++;
        }
        goterr |= set_flag(ifr.ifr_name, IFF_BROADCAST);
        continue;
    }
    if (!strcmp(*spp, "dstaddr")) {
        if (*++spp == NULL)
        usage(E_OPTERR);
        safe_strncpy(host, *spp, (sizeof host));
        if (ap->input(0, host, &_sa) < 0) {
            if (ap->herror)
                ap->herror(host);
            else
                fprintf(stderr, _("ifconfig: Error resolving '%s' for dstaddr\n"), host);
        goterr = 1;
        spp++;
        continue;
        }
        memcpy(&ifr.ifr_dstaddr, sa, sizeof(struct sockaddr));
        if (ioctl(ap->fd, SIOCSIFDSTADDR, &ifr) < 0) {
        fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
            strerror(errno));
        goterr = 1;
        }
        spp++;
        continue;
    }
    if (!strcmp(*spp, "netmask")) {
        if (*++spp == NULL || didnetmask)
        usage(E_OPTERR);
        safe_strncpy(host, *spp, (sizeof host));
        if (ap->input(0, host, &_sa) < 0) {
            if (ap->herror)
                ap->herror(host);
            else
                fprintf(stderr, _("ifconfig: Error resolving '%s' for netmask\n"), host);
        goterr = 1;
        spp++;
        continue;
        }
        didnetmask++;
        goterr |= set_netmask(ap->fd, &ifr, sa);
        spp++;
        continue;
    }
#ifdef HAVE_TXQUEUELEN
    if (!strcmp(*spp, "txqueuelen")) {
        if (*++spp == NULL)
        usage(E_OPTERR);
        ifr.ifr_qlen = strtoul(*spp, NULL, 0);
        if (ioctl(skfd, SIOCSIFTXQLEN, &ifr) < 0) {
        fprintf(stderr, "SIOCSIFTXQLEN: %s\n", strerror(errno));
        goterr = 1;
        }
        spp++;
        continue;
    }
#endif

#ifdef SIOCSIFNAME
    if (!strcmp(*spp, "name")) {
        if (*++spp == NULL)
        usage(E_OPTERR);
        safe_strncpy(ifr.ifr_newname, *spp, IFNAMSIZ);
        if (ioctl(skfd, SIOCSIFNAME, &ifr) < 0) {
        fprintf(stderr, "SIOCSIFNAME: %s\n", strerror(errno));
        goterr = 1;
        }
        spp++;
        continue;
    }
#endif

    if (!strcmp(*spp, "mem_start")) {
        if (*++spp == NULL)
        usage(E_OPTERR);
        if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
        fprintf(stderr, "mem_start: SIOCGIFMAP: %s\n", strerror(errno));
        spp++;
        goterr = 1;
        continue;
        }
        ifr.ifr_map.mem_start = strtoul(*spp, NULL, 0);
        if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
        fprintf(stderr, "mem_start: SIOCSIFMAP: %s\n", strerror(errno));
        goterr = 1;
        }
        spp++;
        continue;
    }
    if (!strcmp(*spp, "io_addr")) {
        if (*++spp == NULL)
        usage(E_OPTERR);
        if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
        fprintf(stderr, "io_addr: SIOCGIFMAP: %s\n", strerror(errno));
        spp++;
        goterr = 1;
        continue;
        }
        ifr.ifr_map.base_addr = strtol(*spp, NULL, 0);
        if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
        fprintf(stderr, "io_addr: SIOCSIFMAP: %s\n", strerror(errno));
        goterr = 1;
        }
        spp++;
        continue;
    }
    if (!strcmp(*spp, "irq")) {
        if (*++spp == NULL)
        usage(E_OPTERR);
        if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
        fprintf(stderr, "irq: SIOCGIFMAP: %s\n", strerror(errno));
        goterr = 1;
        spp++;
        continue;
        }
        ifr.ifr_map.irq = atoi(*spp);
        if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
        fprintf(stderr, "irq: SIOCSIFMAP: %s\n", strerror(errno));
        goterr = 1;
        }
        spp++;
        continue;
    }
    if (!strcmp(*spp, "-pointopoint") || !strcmp(*spp, "-pointtopoint")) {
        goterr |= clr_flag(ifr.ifr_name, IFF_POINTOPOINT);
        spp++;
        if (test_flag(ifr.ifr_name, IFF_POINTOPOINT) > 0)
            fprintf(stderr, _("Warning: Interface %s still in POINTOPOINT mode.\n"), ifr.ifr_name);
        continue;
    }
    if (!strcmp(*spp, "pointopoint") || !strcmp(*spp, "pointtopoint")) {
        if (*(spp + 1) != NULL) {
        spp++;
        safe_strncpy(host, *spp, (sizeof host));
        if (ap->input(0, host, &_sa)) {
            if (ap->herror)
                ap->herror(host);
            else
                fprintf(stderr, _("ifconfig: Error resolving '%s' for pointopoint\n"), host);
            goterr = 1;
            spp++;
            continue;
        }
        memcpy(&ifr.ifr_dstaddr, sa, sizeof(struct sockaddr));
        if (ioctl(ap->fd, SIOCSIFDSTADDR, &ifr) < 0) {
            fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
                strerror(errno));
            goterr = 1;
        }
        }
        goterr |= set_flag(ifr.ifr_name, IFF_POINTOPOINT);
        spp++;
        continue;
    };

    if (!strcmp(*spp, "hw")) {
        if (*++spp == NULL)
        usage(E_OPTERR);
        if ((hw = get_hwtype(*spp)) == NULL)
        usage(E_OPTERR);
        if (hw->input == NULL) {
            fprintf(stderr, _("hw address type `%s' has no handler to set address. failed.\n"), *spp);
            spp+=2;
            goterr = 1;
            continue;
        }
        if (*++spp == NULL)
        usage(E_OPTERR);
        safe_strncpy(host, *spp, (sizeof host));
        if (hw->input(host, &_sa) < 0) {
        fprintf(stderr, _("%s: invalid %s address.\n"), host, hw->name);
        goterr = 1;
        spp++;
        continue;
        }
        memcpy(&ifr.ifr_hwaddr, sa, sizeof(struct sockaddr));
        if (ioctl(skfd, SIOCSIFHWADDR, &ifr) < 0) {
        if (errno == EBUSY)
            fprintf(stderr, "SIOCSIFHWADDR: %s - you may need to down the interface\n",
                strerror(errno));
        else
            fprintf(stderr, "SIOCSIFHWADDR: %s\n",
                strerror(errno));
        goterr = 1;
        }
        spp++;
        continue;
    }
#if HAVE_AFINET || HAVE_AFINET6
    if (!strcmp(*spp, "add")) {
        if (*++spp == NULL)
        usage(E_OPTERR);
#if HAVE_AFINET6
        if (strchr(*spp, ':')) {
        /* INET6 */
        if ((cp = strchr(*spp, '/'))) {
            prefix_len = atol(cp + 1);
            if ((prefix_len < 0) || (prefix_len > 128))
            usage(E_OPTERR);
            *cp = 0;
        } else {
            prefix_len = 128;
        }
        safe_strncpy(host, *spp, (sizeof host));
        if (inet6_aftype.input(1, host, &_sa) < 0) {
            if (inet6_aftype.herror)
                inet6_aftype.herror(host);
            else
                fprintf(stderr, _("ifconfig: Error resolving '%s' for add\n"), host);
            goterr = 1;
            spp++;
            continue;
        }
        memcpy(&ifr6.ifr6_addr, &sin6->sin6_addr, sizeof(struct in6_addr));

        fd = get_socket_for_af(AF_INET6);
        if (fd < 0) {
            fprintf(stderr,
                _("No support for INET6 on this system.\n"));
            goterr = 1;
            spp++;
            continue;
        }
        if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
            perror("SIOGIFINDEX");
            goterr = 1;
            spp++;
            continue;
        }
        ifr6.ifr6_ifindex = ifr.ifr_ifindex;
        ifr6.ifr6_prefixlen = prefix_len;
        if (ioctl(fd, SIOCSIFADDR, &ifr6) < 0) {
            perror("SIOCSIFADDR");
            goterr = 1;
        }
        spp++;
        continue;
        }
#endif
#if HAVE_AFINET
        { /* ipv4 address a.b.c.d */
        in_addr_t ip, nm, bc;
        safe_strncpy(host, *spp, (sizeof host));
        if (inet_aftype.input(0, host, &_sa) < 0) {
            ap->herror(host);
            goterr = 1;
            spp++;
            continue;
        }
        fd = get_socket_for_af(AF_INET);
        if (fd < 0) {
            fprintf(stderr,
                _("No support for INET on this system.\n"));
            goterr = 1;
            spp++;
            continue;
        }

        memcpy(&ip, &sin->sin_addr.s_addr, sizeof(ip));

        if (get_nmbc_parent(ifr.ifr_name, &nm, &bc) < 0) {
            fprintf(stderr, _("Interface %s not initialized\n"),
                ifr.ifr_name);
            goterr = 1;
            spp++;
            continue;
        }
        set_ifstate(ifr.ifr_name, ip, nm, bc, 1);

        }
        spp++;
        continue;
#else
        fprintf(stderr, _("Bad address.\n"));
#endif
    }
#endif

#if HAVE_AFINET || HAVE_AFINET6
    if (!strcmp(*spp, "del")) {
        if (*++spp == NULL)
        usage(E_OPTERR);

#ifdef SIOCDIFADDR
#if HAVE_AFINET6
        if (strchr(*spp, ':')) {    /* INET6 */
        if ((cp = strchr(*spp, '/'))) {
            prefix_len = atol(cp + 1);
            if ((prefix_len < 0) || (prefix_len > 128))
            usage(E_OPTERR);
            *cp = 0;
        } else {
            prefix_len = 128;
        }
        safe_strncpy(host, *spp, (sizeof host));
        if (inet6_aftype.input(1, host, &_sa) < 0) {
            inet6_aftype.herror(host);
            goterr = 1;
            spp++;
            continue;
        }
        memcpy(&ifr6.ifr6_addr, &sin6->sin6_addr,
               sizeof(struct in6_addr));

        fd = get_socket_for_af(AF_INET6);
        if (fd < 0) {
            fprintf(stderr,
                _("No support for INET6 on this system.\n"));
            goterr = 1;
            spp++;
            continue;
        }
        if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
            perror("SIOGIFINDEX");
            goterr = 1;
            spp++;
            continue;
        }
        ifr6.ifr6_ifindex = ifr.ifr_ifindex;
        ifr6.ifr6_prefixlen = prefix_len;
        if (opt_v)
            fprintf(stderr, "now deleting: ioctl(SIOCDIFADDR,{ifindex=%d,prefixlen=%ld})\n",ifr.ifr_ifindex,prefix_len);
        if (ioctl(fd, SIOCDIFADDR, &ifr6) < 0) {
            fprintf(stderr, "SIOCDIFADDR: %s\n",
                strerror(errno));
            goterr = 1;
        }
        spp++;
        continue;
        }
#endif
#if HAVE_AFINET
        {
        /* ipv4 address a.b.c.d */
        in_addr_t ip, nm, bc;
        safe_strncpy(host, *spp, (sizeof host));
        if (inet_aftype.input(0, host, &_sa) < 0) {
            ap->herror(host);
            goterr = 1;
            spp++;
            continue;
        }
        fd = get_socket_for_af(AF_INET);
        if (fd < 0) {
            fprintf(stderr, _("No support for INET on this system.\n"));
            goterr = 1;
            spp++;
            continue;
        }

        /* Clear "ip" in case sizeof(unsigned long) > sizeof(sin.sin_addr.s_addr) */
        ip = 0;
        memcpy(&ip, &sin->sin_addr.s_addr, sizeof(ip));

        if (get_nmbc_parent(ifr.ifr_name, &nm, &bc) < 0) {
            fprintf(stderr, _("Interface %s not initialized\n"),
                ifr.ifr_name);
            goterr = 1;
            spp++;
            continue;
        }
        set_ifstate(ifr.ifr_name, ip, nm, bc, 0);
        }
        spp++;
        continue;
#else
        fprintf(stderr, _("Bad address.\n"));
#endif
#else
        fprintf(stderr, _("Address deletion not supported on this system.\n"));
#endif
    }
#endif
#if HAVE_AFINET6
    if (!strcmp(*spp, "tunnel")) {
        if (*++spp == NULL)
        usage(E_OPTERR);
        if ((cp = strchr(*spp, '/'))) {
        prefix_len = atol(cp + 1);
        if ((prefix_len < 0) || (prefix_len > 128))
            usage(E_OPTERR);
        *cp = 0;
        } else {
        prefix_len = 128;
        }
        safe_strncpy(host, *spp, (sizeof host));
        if (inet6_aftype.input(1, host, &_sa) < 0) {
        inet6_aftype.herror(host);
        goterr = 1;
        spp++;
        continue;
        }
        memcpy(&ifr6.ifr6_addr, &sin6->sin6_addr, sizeof(struct in6_addr));

        fd = get_socket_for_af(AF_INET6);
        if (fd < 0) {
        fprintf(stderr, _("No support for INET6 on this system.\n"));
        goterr = 1;
        spp++;
        continue;
        }
        if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
        perror("SIOGIFINDEX");
        goterr = 1;
        spp++;
        continue;
        }
        ifr6.ifr6_ifindex = ifr.ifr_ifindex;
        ifr6.ifr6_prefixlen = prefix_len;

        if (ioctl(fd, SIOCSIFDSTADDR, &ifr6) < 0) {
        fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
            strerror(errno));
        goterr = 1;
        }
        spp++;
        continue;
    }
#endif

    /* If the next argument is a valid hostname, assume OK. */
    safe_strncpy(host, *spp, (sizeof host));

    /* FIXME: sa is too small for INET6 addresses, inet6 should use that too,
       broadcast is unexpected */
    if (ap->getmask) {
        switch (ap->getmask(host, &_samask, NULL)) {
        case -1:
        usage(E_OPTERR);
        break;
        case 1:
        if (didnetmask)
            usage(E_OPTERR);

        // remeber to set the netmask from samask later
        neednetmask = 1;
        break;
        }
    }
    if (ap->input == NULL) {
       fprintf(stderr, _("ifconfig: Cannot set address for this protocol family.\n"));
       exit(1);
    }
    if (ap->input(0, host, &_sa) < 0) {
        if (ap->herror)
            ap->herror(host);
        else
            fprintf(stderr,_("ifconfig: error resolving '%s' to set address for af=%s\n"), host, ap->name);
        fprintf(stderr, _("ifconfig: `--help' gives usage information.\n"));
        exit(1);
    }
    memcpy(&ifr.ifr_addr, sa, sizeof(struct sockaddr));
    {
        int r = 0;        /* to shut gcc up */
        switch (ap->af) {
#if HAVE_AFINET
        case AF_INET:
        fd = get_socket_for_af(AF_INET);
        if (fd < 0) {
            fprintf(stderr, _("No support for INET on this system.\n"));
            exit(1);
        }
        r = ioctl(fd, SIOCSIFADDR, &ifr);
        break;
#endif
#if HAVE_AFECONET
        case AF_ECONET:
        fd = get_socket_for_af(AF_ECONET);
        if (fd < 0) {
            fprintf(stderr, _("No support for ECONET on this system.\n"));
            exit(1);
        }
        r = ioctl(fd, SIOCSIFADDR, &ifr);
        break;
#endif
        default:
        fprintf(stderr,
        _("Don't know how to set addresses for family %d.\n"), ap->af);
        exit(1);
        }
        if (r < 0) {
        perror("SIOCSIFADDR");
        goterr = 1;
        }
    }

       /*
        * Don't do the set_flag() if the address is an alias with a - at the
        * end, since it's deleted already! - Roman
        * Same goes if they used address 0.0.0.0 as the kernel uses this to
        * destroy aliases.
        *
        * Should really use regex.h here, not sure though how well it'll go
        * with the cross-platform support etc.
        */
        {
            char *ptr;
            short int found_colon = 0;
            short int bring_up = 1;
            for (ptr = ifr.ifr_name; *ptr; ptr++ )
                if (*ptr == ':') found_colon++;

            if (found_colon) {
                if (ptr[-1] == '-')
                    bring_up = 0;
                else if (ap->af == AF_INET && sin->sin_addr.s_addr == 0)
                    bring_up = 0;
            }

            if (bring_up)
                goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
        }

    spp++;
    }

    if (neednetmask) {
    goterr |= set_netmask(skfd, &ifr, samask);
    didnetmask++;
    }

    if (opt_v && goterr)
        fprintf(stderr, _("WARNING: at least one error occured. (%d)\n"), goterr);

    return (goterr);
}

struct ifcmd {
    int flag;
    unsigned long addr;
    char *base;
    int baselen;
};

static unsigned char searcher[256];

static int set_ip_using(const char *name, int c, unsigned long ip)
{
    struct ifreq ifr;
    struct sockaddr_in sin;

    safe_strncpy(ifr.ifr_name, name, IFNAMSIZ);
    memset(&sin, 0, sizeof(struct sockaddr));
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = ip;
    memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
    if (ioctl(skfd, c, &ifr) < 0)
    return -1;
    return 0;
}

static int do_ifcmd(struct interface *x, struct ifcmd *ptr)
{
    char *z, *e;
    struct sockaddr_in *sin;
    int i;

    if (do_if_fetch(x) < 0)
    return 0;
    if (strncmp(x->name, ptr->base, ptr->baselen) != 0)
    return 0; /* skip */
    z = strchr(x->name, ':');
    if (!z || !*z)
    return 0;
    z++;
    for (e = z; *e; e++)
    if (*e == '-') /* deleted */
        return 0;
    i = atoi(z);
    if (i < 0 || i > 255)
    abort();
    searcher[i] = 1;

    /* copy */
    sin = (struct sockaddr_in *)&x->dstaddr_sas;
    if (sin->sin_addr.s_addr != ptr->addr) {
    return 0;
    }

    if (ptr->flag) {
    /* turn UP */
    if (set_flag(x->name, IFF_UP | IFF_RUNNING) == -1)
        return -1;
    } else {
    /* turn DOWN */
    if (clr_flag(x->name, IFF_UP) == -1)
        return -1;
    }

    return 1; /* all done! */
}


static int get_nmbc_parent(char *parent,
               in_addr_t *nm, in_addr_t *bc)
{
    struct interface *i;
    struct sockaddr_in *sin;

    i = lookup_interface(parent);
    if (!i)
    return -1;
    if (do_if_fetch(i) < 0)
    return 0;
    sin = (struct sockaddr_in *)&i->netmask_sas;
    memcpy(nm, &sin->sin_addr.s_addr, sizeof(*nm));
    sin = (struct sockaddr_in *)&i->broadaddr_sas;
    memcpy(bc, &sin->sin_addr.s_addr, sizeof(*bc));
    return 0;
}

static int set_ifstate(char *parent, in_addr_t ip, in_addr_t nm, in_addr_t bc,
               int flag)
{
    char buf[IFNAMSIZ];
    struct ifcmd pt;
    int i;

    pt.base = parent;
    pt.baselen = strlen(parent);
    pt.addr = ip;
    pt.flag = flag;
    memset(searcher, 0, sizeof(searcher));
    i = for_all_interfaces((int (*)(struct interface *,void *))do_ifcmd,
               &pt);
    if (i == -1)
    return -1;
    if (i == 1)
    return 0;

    /* add a new interface */
    for (i = 0; i < 256; i++)
    if (searcher[i] == 0)
        break;

    if (i == 256)
    return -1; /* FAILURE!!! out of ip addresses */

    if (snprintf(buf, IFNAMSIZ, "%s:%d", parent, i) > IFNAMSIZ)
    return -1;
    if (set_ip_using(buf, SIOCSIFADDR, ip) == -1)
    return -1;
    if (set_ip_using(buf, SIOCSIFNETMASK, nm) == -1)
    return -1;
    if (set_ip_using(buf, SIOCSIFBRDADDR, bc) == -1)
    return -1;
    if (set_flag(buf, IFF_BROADCAST) == -1)
    return -1;
    return 0;
}

interface.c

/* Code to manipulate interface information, shared between ifconfig and
   netstat.

   10/1998 partly rewriten by Andi Kleen to support an interface list.
   I don't claim that the list operations are efficient @).

   8/2000  Andi Kleen make the list operations a bit more efficient.
   People are crazy enough to use thousands of aliases now.

   $Id: interface.c,v 1.35 2011-01-01 03:22:31 ecki Exp $
 */

#include "config.h"

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>

#if HAVE_AFIPX
#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1)
#include <netipx/ipx.h>
#else
#include "ipx.h"
#endif
#endif

#if HAVE_AFECONET
#include <neteconet/ec.h>
#endif

#if HAVE_HWSLIP
#include <linux/if_slip.h>
#include <net/if_arp.h>
#endif

#include "net-support.h"
#include "pathnames.h"
#include "version.h"
#include "proc.h"

#include "interface.h"
#include "sockets.h"
#include "util.h"
#include "intl.h"

#ifdef IFF_PORTSEL
const char *if_port_text[][4] =
{
  /* Keep in step with <linux/netdevice.h> */
    {"unknown", NULL, NULL, NULL},
    {"10base2", "bnc", "coax", NULL},
    {"10baseT", "utp", "tpe", NULL},
    {"AUI", "thick", "db15", NULL},
    {"100baseT", NULL, NULL, NULL},
    {"100baseTX", NULL, NULL, NULL},
    {"100baseFX", NULL, NULL, NULL},
    {NULL, NULL, NULL, NULL},
};
#endif

#define IPV6_ADDR_ANY        0x0000U

#define IPV6_ADDR_UNICAST          0x0001U
#define IPV6_ADDR_MULTICAST        0x0002U
#define IPV6_ADDR_ANYCAST    0x0004U

#define IPV6_ADDR_LOOPBACK    0x0010U
#define IPV6_ADDR_LINKLOCAL    0x0020U
#define IPV6_ADDR_SITELOCAL    0x0040U

#define IPV6_ADDR_COMPATv4    0x0080U

#define IPV6_ADDR_SCOPE_MASK    0x00f0U

#define IPV6_ADDR_MAPPED    0x1000U
#define IPV6_ADDR_RESERVED    0x2000U        /* reserved address space */

int procnetdev_vsn = 1;

int ife_short;

int if_list_all = 0;    /* do we have requested the complete proc list, yet? */

static struct interface *int_list, *int_last;

static int if_readlist_proc(const char *);

static struct interface *if_cache_add(const char *name)
{
    struct interface *ife, **nextp, *new;

    if (!int_list)
        int_last = NULL;

    /* the cache is sorted, so if we hit a smaller if, exit */
    for (ife = int_last; ife; ife = ife->prev) {
        int n = nstrcmp(ife->name, name);
        if (n == 0)
            return ife;
        if (n < 0)
            break;
    }
    new = xmalloc(sizeof(*new));
    safe_strncpy(new->name, name, IFNAMSIZ);
    nextp = ife ? &ife->next : &int_list; // keep sorting
    new->prev = ife;
    new->next = *nextp;
    if (new->next)
        new->next->prev = new;
    else
        int_last = new;
    *nextp = new;
    return new;
}

struct interface *lookup_interface(const char *name)
{
   /* if we have read all, use it */
   if (if_list_all)
       return if_cache_add(name);

   /* otherwise we read a limited list */
   if (if_readlist_proc(name) < 0)
       return NULL;

   return if_cache_add(name);
}

int for_all_interfaces(int (*doit) (struct interface *, void *), void *cookie)
{
    struct interface *ife;

    if (!if_list_all && (if_readlist() < 0))
    return -1;
    for (ife = int_list; ife; ife = ife->next) {
    int err = doit(ife, cookie);
    if (err)
        return err;
    }
    return 0;
}

int if_cache_free(void)
{
    struct interface *ife;
    while ((ife = int_list) != NULL) {
    int_list = ife->next;
    free(ife);
    }
    int_last = NULL;
    if_list_all = 0;
    return 0;
}

static int if_readconf(void)
{
    int numreqs = 30;
    struct ifconf ifc;
    struct ifreq *ifr;
    int n, err = -1;
    int skfd;

    /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
       (as of 2.1.128) */
    skfd = get_socket_for_af(AF_INET);
    if (skfd < 0) {
    fprintf(stderr, _("warning: no inet socket available: %s\n"),
        strerror(errno));
    /* Try to soldier on with whatever socket we can get hold of.  */
    skfd = sockets_open(0);
    if (skfd < 0)
        return -1;
    }

    ifc.ifc_buf = NULL;
    for (;;) {
    ifc.ifc_len = sizeof(struct ifreq) * numreqs;
    ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);

    if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) {
        perror("SIOCGIFCONF");
        goto out;
    }
    if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
        /* assume it overflowed and try again */
        numreqs *= 2;
        continue;
    }
    break;
    }

    ifr = ifc.ifc_req;
    for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
    if_cache_add(ifr->ifr_name);
    ifr++;
    }
    err = 0;

out:
    free(ifc.ifc_buf);
    return err;
}

static const char *get_name(char *name, const char *p)
{
    while (isspace(*p))
    p++;
    while (*p) {
    if (isspace(*p))
        break;
    if (*p == ':') {    /* could be an alias */
        const char *dot = p++;
         while (*p && isdigit(*p)) p++;
        if (*p == ':') {
            /* Yes it is, backup and copy it. */
            p = dot;
            *name++ = *p++;
            while (*p && isdigit(*p)) {
                *name++ = *p++;
            }
        } else {
            /* No, it isn't */
            p = dot;
        }
        p++;
        break;
    }
    *name++ = *p++;
    }
    *name++ = '\0';
    return p;
}

static int procnetdev_version(const char *buf)
{
    if (strstr(buf, "compressed"))
    return 3;
    if (strstr(buf, "bytes"))
    return 2;
    return 1;
}

static int get_dev_fields(const char *bp, struct interface *ife)
{
    switch (procnetdev_vsn) {
    case 3:
    sscanf(bp,
    "%Lu %Lu %lu %lu %lu %lu %lu %lu %Lu %Lu %lu %lu %lu %lu %lu %lu",
           &ife->stats.rx_bytes,
           &ife->stats.rx_packets,
           &ife->stats.rx_errors,
           &ife->stats.rx_dropped,
           &ife->stats.rx_fifo_errors,
           &ife->stats.rx_frame_errors,
           &ife->stats.rx_compressed,
           &ife->stats.rx_multicast,

           &ife->stats.tx_bytes,
           &ife->stats.tx_packets,
           &ife->stats.tx_errors,
           &ife->stats.tx_dropped,
           &ife->stats.tx_fifo_errors,
           &ife->stats.collisions,
           &ife->stats.tx_carrier_errors,
           &ife->stats.tx_compressed);
    break;
    case 2:
    sscanf(bp, "%Lu %Lu %lu %lu %lu %lu %Lu %Lu %lu %lu %lu %lu %lu",
           &ife->stats.rx_bytes,
           &ife->stats.rx_packets,
           &ife->stats.rx_errors,
           &ife->stats.rx_dropped,
           &ife->stats.rx_fifo_errors,
           &ife->stats.rx_frame_errors,

           &ife->stats.tx_bytes,
           &ife->stats.tx_packets,
           &ife->stats.tx_errors,
           &ife->stats.tx_dropped,
           &ife->stats.tx_fifo_errors,
           &ife->stats.collisions,
           &ife->stats.tx_carrier_errors);
    ife->stats.rx_multicast = 0;
    break;
    case 1:
    sscanf(bp, "%Lu %lu %lu %lu %lu %Lu %lu %lu %lu %lu %lu",
           &ife->stats.rx_packets,
           &ife->stats.rx_errors,
           &ife->stats.rx_dropped,
           &ife->stats.rx_fifo_errors,
           &ife->stats.rx_frame_errors,

           &ife->stats.tx_packets,
           &ife->stats.tx_errors,
           &ife->stats.tx_dropped,
           &ife->stats.tx_fifo_errors,
           &ife->stats.collisions,
           &ife->stats.tx_carrier_errors);
    ife->stats.rx_bytes = 0;
    ife->stats.tx_bytes = 0;
    ife->stats.rx_multicast = 0;
    break;
    }
    return 0;
}

static int if_readlist_proc(const char *target)
{
    FILE *fh;
    char buf[512];
    struct interface *ife;
    int err;

    fh = fopen(_PATH_PROCNET_DEV, "r");
    if (!fh) {
        fprintf(stderr, _("Warning: cannot open %s (%s). Limited output.\n"),
            _PATH_PROCNET_DEV, strerror(errno));
        return -2;
    }
    if (fgets(buf, sizeof buf, fh))
        /* eat line */;
    if (fgets(buf, sizeof buf, fh))
        /* eat line */;

#if 0                /* pretty, but can't cope with missing fields */
    fmt = proc_gen_fmt(_PATH_PROCNET_DEV, 1, fh,
               "face", "",    /* parsed separately */
               "bytes", "%lu",
               "packets", "%lu",
               "errs", "%lu",
               "drop", "%lu",
               "fifo", "%lu",
               "frame", "%lu",
               "compressed", "%lu",
               "multicast", "%lu",
               "bytes", "%lu",
               "packets", "%lu",
               "errs", "%lu",
               "drop", "%lu",
               "fifo", "%lu",
               "colls", "%lu",
               "carrier", "%lu",
               "compressed", "%lu",
               NULL);
    if (!fmt)
    return -1;
#else
    procnetdev_vsn = procnetdev_version(buf);
#endif

    err = 0;
    while (fgets(buf, sizeof buf, fh)) {
    const char *s;
    char name[IFNAMSIZ];
    s = get_name(name, buf);
    ife = if_cache_add(name);
    get_dev_fields(s, ife);
    ife->statistics_valid = 1;
    if (target && !strcmp(target,name))
        break;
    }
    if (ferror(fh)) {
    perror(_PATH_PROCNET_DEV);
    err = -1;
    }

#if 0
    free(fmt);
#endif
    fclose(fh);
    return err;
}

int if_readlist(void)
{
    /* caller will/should check not to call this too often
     *   (i.e. only if if_list_all == 0
     */
    int proc_err, conf_err;

    proc_err = if_readlist_proc(NULL);
    conf_err = if_readconf();

    if_list_all = 1;

    if (proc_err < 0 && conf_err < 0)
        return -1;
    else
        return 0;
}

/* Support for fetching an IPX address */

#if HAVE_AFIPX
static int ipx_getaddr(int sock, int ft, struct ifreq *ifr)
{
    ((struct sockaddr_ipx *) &ifr->ifr_addr)->sipx_type = ft;
    return ioctl(sock, SIOCGIFADDR, ifr);
}
#endif

/* Fetch the interface configuration from the kernel. */
int if_fetch(struct interface *ife)
{
    struct ifreq ifr;
    int fd;
    const char *ifname = ife->name;

    safe_strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
    return (-1);
    ife->flags = ifr.ifr_flags;

    safe_strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
    memset(ife->hwaddr, 0, 32);
    else
    memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);

    ife->type = ifr.ifr_hwaddr.sa_family;

    safe_strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
    ife->mtu = 0;
    else
    ife->mtu = ifr.ifr_mtu;

#if HAVE_HWSLIP
    if (ife->type == ARPHRD_SLIP || ife->type == ARPHRD_CSLIP ||
    ife->type == ARPHRD_SLIP6 || ife->type == ARPHRD_CSLIP6 ||
    ife->type == ARPHRD_ADAPT) {
#ifdef SIOCGOUTFILL
    safe_strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    if (ioctl(skfd, SIOCGOUTFILL, &ifr) < 0)
        ife->outfill = 0;
    else
        ife->outfill = (unsigned long) ifr.ifr_data;
#endif
#ifdef SIOCGKEEPALIVE
    safe_strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    if (ioctl(skfd, SIOCGKEEPALIVE, &ifr) < 0)
        ife->keepalive = 0;
    else
        ife->keepalive = (unsigned long) ifr.ifr_data;
#endif
    }
#endif

    safe_strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
    memset(&ife->map, 0, sizeof(struct ifmap));
    else
    memcpy(&ife->map, &ifr.ifr_map, sizeof(struct ifmap));

    safe_strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
    memset(&ife->map, 0, sizeof(struct ifmap));
    else
    ife->map = ifr.ifr_map;

#ifdef HAVE_TXQUEUELEN
    safe_strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0)
    ife->tx_queue_len = -1;    /* unknown value */
    else
    ife->tx_queue_len = ifr.ifr_qlen;
#else
    ife->tx_queue_len = -1;    /* unknown value */
#endif

#if HAVE_AFINET
    /* IPv4 address? */
    fd = get_socket_for_af(AF_INET);
    if (fd >= 0) {
    safe_strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    ifr.ifr_addr.sa_family = AF_INET;
    if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
        ife->has_ip = 1;
        ife->addr = ifr.ifr_addr;
        safe_strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
        if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0)
            memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
        else
            ife->dstaddr = ifr.ifr_dstaddr;

        safe_strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
        if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
            memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
        else
        ife->broadaddr = ifr.ifr_broadaddr;

        safe_strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
        if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
        memset(&ife->netmask, 0, sizeof(struct sockaddr));
        else
        ife->netmask = ifr.ifr_netmask;
    } else
        memset(&ife->addr, 0, sizeof(struct sockaddr));
    }
#endif

#if HAVE_AFATALK
    /* DDP address maybe ? */
    fd = get_socket_for_af(AF_APPLETALK);
    if (fd >= 0) {
    safe_strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
        ife->ddpaddr = ifr.ifr_addr;
        ife->has_ddp = 1;
    }
    }
#endif

#if HAVE_AFIPX
    /* Look for IPX addresses with all framing types */
    fd = get_socket_for_af(AF_IPX);
    if (fd >= 0) {
    safe_strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    if (!ipx_getaddr(fd, IPX_FRAME_ETHERII, &ifr)) {
        ife->has_ipx_bb = 1;
        ife->ipxaddr_bb = ifr.ifr_addr;
    }
    safe_strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    if (!ipx_getaddr(fd, IPX_FRAME_SNAP, &ifr)) {
        ife->has_ipx_sn = 1;
        ife->ipxaddr_sn = ifr.ifr_addr;
    }
    safe_strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    if (!ipx_getaddr(fd, IPX_FRAME_8023, &ifr)) {
        ife->has_ipx_e3 = 1;
        ife->ipxaddr_e3 = ifr.ifr_addr;
    }
    safe_strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    if (!ipx_getaddr(fd, IPX_FRAME_8022, &ifr)) {
        ife->has_ipx_e2 = 1;
        ife->ipxaddr_e2 = ifr.ifr_addr;
    }
    }
#endif

#if HAVE_AFECONET
    /* Econet address maybe? */
    fd = get_socket_for_af(AF_ECONET);
    if (fd >= 0) {
    safe_strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
        ife->ecaddr = ifr.ifr_addr;
        ife->has_econet = 1;
    }
    }
#endif

    return 0;
}

int do_if_fetch(struct interface *ife)
{
    if (if_fetch(ife) < 0) {
    const char *errmsg;
    if (errno == ENODEV) {
        /* Give better error message for this case. */
        errmsg = _("Device not found");
    } else {
        errmsg = strerror(errno);
    }
      fprintf(stderr, _("%s: error fetching interface information: %s\n"),
        ife->name, errmsg);
    return -1;
    }
    return 0;
}

int do_if_print(struct interface *ife, void *cookie)
{
    int *opt_a = (int *) cookie;
    int res;

    res = do_if_fetch(ife);
    if (res >= 0) {
    if ((ife->flags & IFF_UP) || *opt_a)
        ife_print(ife);
    }
    return res;
}

void ife_print_short(struct interface *ptr)
{
    printf("%-15.15s ", ptr->name);
    printf("%5d ", ptr->mtu);
    /* If needed, display the interface statistics. */
    if (ptr->statistics_valid) {
    printf("%8llu %6lu %6lu %-6lu ",
           ptr->stats.rx_packets, ptr->stats.rx_errors,
           ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors);
    printf("%8llu %6lu %6lu %6lu ",
           ptr->stats.tx_packets, ptr->stats.tx_errors,
           ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors);
    } else {
    printf("%-56s", _("     - no statistics available -"));
    }
    /* DONT FORGET TO ADD THE FLAGS IN ife_print_long, too */
    if (ptr->flags == 0)
    printf(_("[NO FLAGS]"));
    if (ptr->flags & IFF_ALLMULTI)
    printf("A");
    if (ptr->flags & IFF_BROADCAST)
    printf("B");
    if (ptr->flags & IFF_DEBUG)
    printf("D");
    if (ptr->flags & IFF_LOOPBACK)
    printf("L");
    if (ptr->flags & IFF_MULTICAST)
    printf("M");
#ifdef HAVE_DYNAMIC
    if (ptr->flags & IFF_DYNAMIC)
    printf("d");
#endif
    if (ptr->flags & IFF_PROMISC)
    printf("P");
    if (ptr->flags & IFF_NOTRAILERS)
    printf("N");
    if (ptr->flags & IFF_NOARP)
    printf("O");
    if (ptr->flags & IFF_POINTOPOINT)
    printf("P");
    if (ptr->flags & IFF_SLAVE)
    printf("s");
    if (ptr->flags & IFF_MASTER)
    printf("m");
    if (ptr->flags & IFF_RUNNING)
    printf("R");
    if (ptr->flags & IFF_UP)
    printf("U");
    /* DONT FORGET TO ADD THE FLAGS IN ife_print_long, too */
    printf("\n");
}

void ife_print_long(struct interface *ptr)
{
    const struct aftype *ap;
    const struct hwtype *hw;
    int hf;
    int can_compress = 0;
    unsigned long long rx, tx, short_rx, short_tx;
    const char *Rext = "B";
    const char *Text = "B";
    static char flags[200];

#if HAVE_AFIPX
    static const struct aftype *ipxtype = NULL;
#endif
#if HAVE_AFECONET
    static const struct aftype *ectype = NULL;
#endif
#if HAVE_AFATALK
    static const struct aftype *ddptype = NULL;
#endif
#if HAVE_AFINET6
    FILE *f;
    char addr6[40], devname[21];
    struct sockaddr_storage sas;
    int plen, scope, dad_status, if_idx;
    extern struct aftype inet6_aftype;
    char addr6p[8][5];
#endif

    ap = get_afntype(ptr->addr.sa_family);
    if (ap == NULL)
    ap = get_afntype(0);

    hf = ptr->type;

#if HAVE_HWSLIP
    if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
    can_compress = 1;
#endif

    hw = get_hwntype(hf);
    if (hw == NULL)
    hw = get_hwntype(-1);

    sprintf(flags, "flags=%d<", ptr->flags);
    /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
    if (ptr->flags == 0)
    strcat(flags,">");
    if (ptr->flags & IFF_UP)
    strcat(flags,_("UP,"));
    if (ptr->flags & IFF_BROADCAST)
    strcat(flags,_("BROADCAST,"));
    if (ptr->flags & IFF_DEBUG)
    strcat(flags,_("DEBUG,"));
    if (ptr->flags & IFF_LOOPBACK)
    strcat(flags,_("LOOPBACK,"));
    if (ptr->flags & IFF_POINTOPOINT)
    strcat(flags,_("POINTOPOINT,"));
    if (ptr->flags & IFF_NOTRAILERS)
    strcat(flags,_("NOTRAILERS,"));
    if (ptr->flags & IFF_RUNNING)
    strcat(flags,_("RUNNING,"));
    if (ptr->flags & IFF_NOARP)
    strcat(flags,_("NOARP,"));
    if (ptr->flags & IFF_PROMISC)
    strcat(flags,_("PROMISC,"));
    if (ptr->flags & IFF_ALLMULTI)
    strcat(flags,_("ALLMULTI,"));
    if (ptr->flags & IFF_SLAVE)
    strcat(flags,_("SLAVE,"));
    if (ptr->flags & IFF_MASTER)
    strcat(flags,_("MASTER,"));
    if (ptr->flags & IFF_MULTICAST)
    strcat(flags,_("MULTICAST,"));
#ifdef HAVE_DYNAMIC
    if (ptr->flags & IFF_DYNAMIC)
    strcat(flags,_("DYNAMIC,"));
#endif
    /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
    if (flags[strlen(flags)-1] == ',')
      flags[strlen(flags)-1] = '>';
    else
      flags[strlen(flags)-1] = 0;


    printf(_("%s: %s  mtu %d"),
       ptr->name, flags, ptr->mtu);
#ifdef SIOCSKEEPALIVE
    if (ptr->outfill || ptr->keepalive)
    printf(_("  outfill %d  keepalive %d"),
           ptr->outfill, ptr->keepalive);
#endif
    printf("\n");



#if HAVE_AFINET
    if (ptr->has_ip) {
    printf(_("        %s %s"), ap->name,
           ap->sprint(&ptr->addr_sas, 1));
    printf(_("  netmask %s"), ap->sprint(&ptr->netmask_sas, 1));
    if (ptr->flags & IFF_BROADCAST) {
        printf(_("  broadcast %s"), ap->sprint(&ptr->broadaddr_sas, 1));
    }
    if (ptr->flags & IFF_POINTOPOINT) {
        printf(_("  destination %s"), ap->sprint(&ptr->dstaddr_sas, 1));
    }
    printf("\n");
    }
#endif

#if HAVE_AFINET6
    /* FIXME: should be integrated into interface.c.   */

    if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
    while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n",
              addr6p[0], addr6p[1], addr6p[2], addr6p[3],
              addr6p[4], addr6p[5], addr6p[6], addr6p[7],
          &if_idx, &plen, &scope, &dad_status, devname) != EOF) {
        if (!strcmp(devname, ptr->name)) {
        sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
            addr6p[0], addr6p[1], addr6p[2], addr6p[3],
            addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
        inet6_aftype.input(1, addr6, &sas);
        printf(_("        %s %s  prefixlen %d"),
            inet6_aftype.name,
            inet6_aftype.sprint(&sas, 1),
            plen);
        printf(_("  scopeid 0x%x"), scope);

        flags[0] = '<'; flags[1] = 0;
        if (scope & IPV6_ADDR_COMPATv4) {
                strcat(flags, _("compat,"));
                scope -= IPV6_ADDR_COMPATv4;
        }
        if (scope == 0)
            strcat(flags, _("global,"));
        if (scope & IPV6_ADDR_LINKLOCAL)
            strcat(flags, _("link,"));
        if (scope & IPV6_ADDR_SITELOCAL)
            strcat(flags, _("site,"));
        if (scope & IPV6_ADDR_LOOPBACK)
            strcat(flags, _("host,"));
        if (flags[strlen(flags)-1] == ',')
            flags[strlen(flags)-1] = '>';
        else
            flags[strlen(flags)-1] = 0;
        printf("%s\n", flags);
        }
    }
    fclose(f);
    }
#endif

#if HAVE_AFIPX
    if (ipxtype == NULL)
    ipxtype = get_afntype(AF_IPX);

    if (ipxtype != NULL) {
    if (ptr->has_ipx_bb)
        printf(_("        %s Ethernet-II   %s\n"),
           ipxtype->name, ipxtype->sprint(&ptr->ipxaddr_bb_sas, 1));
    if (ptr->has_ipx_sn)
        printf(_("        %s Ethernet-SNAP %s\n"),
           ipxtype->name, ipxtype->sprint(&ptr->ipxaddr_sn_sas, 1));
    if (ptr->has_ipx_e2)
        printf(_("        %s Ethernet802.2 %s\n"),
           ipxtype->name, ipxtype->sprint(&ptr->ipxaddr_e2_sas, 1));
    if (ptr->has_ipx_e3)
        printf(_("        %s Ethernet802.3 %s\n"),
           ipxtype->name, ipxtype->sprint(&ptr->ipxaddr_e3_sas, 1));
    }
#endif

#if HAVE_AFATALK
    if (ddptype == NULL)
    ddptype = get_afntype(AF_APPLETALK);
    if (ddptype != NULL) {
    if (ptr->has_ddp)
        printf(_("        %s %s\n"), ddptype->name, ddptype->sprint(&ptr->ddpaddr_sas, 1));
    }
#endif

#if HAVE_AFECONET
    if (ectype == NULL)
    ectype = get_afntype(AF_ECONET);
    if (ectype != NULL) {
    if (ptr->has_econet)
        printf(_("        %s %s\n"), ectype->name, ectype->sprint(&ptr->ecaddr_sas, 1));
    }
#endif

    /* For some hardware types (eg Ash, ATM) we don't print the
       hardware address if it's null.  */
    if (hw->print != NULL && (! (hw_null_address(hw, ptr->hwaddr) &&
                  hw->suppress_null_addr)))
    printf(_("        %s %s"), hw->name, hw->print(ptr->hwaddr));
    else
    printf(_("        %s"), hw->name);
    if (ptr->tx_queue_len != -1)
        printf(_("  txqueuelen %d"), ptr->tx_queue_len);
    printf("  (%s)\n", hw->title);

#ifdef IFF_PORTSEL
    if (ptr->flags & IFF_PORTSEL) {
    printf(_("        media %s"), if_port_text[ptr->map.port][0]);
    if (ptr->flags & IFF_AUTOMEDIA)
        printf(_("autoselect"));
        printf("\n");
    }
#endif


    /* If needed, display the interface statistics. */

    if (ptr->statistics_valid) {
    /* XXX: statistics are currently only printed for the primary address,
     *      not for the aliases, although strictly speaking they're shared
     *      by all addresses.
     */
    rx = ptr->stats.rx_bytes;
    short_rx = rx * 10;
    if (rx > 1152921504606846976ull) {
        short_rx = rx / 115292150460684697ull;
        Rext = "EiB";
    } else if (rx > 1125899906842624ull) {
        short_rx /= 1125899906842624ull;
        Rext = "PiB";
    } else if (rx > 1099511627776ull) {
        short_rx /= 1099511627776ull;
        Rext = "TiB";
    } else if (rx > 1073741824ull) {
        short_rx /= 1073741824ull;
        Rext = "GiB";
    } else if (rx > 1048576) {
        short_rx /= 1048576;
        Rext = "MiB";
    } else if (rx > 1024) {
        short_rx /= 1024;
        Rext = "KiB";
    }
    tx = ptr->stats.tx_bytes;
    short_tx = tx * 10;
    if (tx > 1152921504606846976ull) {
        short_tx = tx / 115292150460684697ull;
        Text = "EiB";
    } else if (tx > 1125899906842624ull) {
        short_tx /= 1125899906842624ull;
        Text = "PiB";
    } else     if (tx > 1099511627776ull) {
        short_tx /= 1099511627776ull;
        Text = "TiB";
    } else if (tx > 1073741824ull) {
        short_tx /= 1073741824ull;
        Text = "GiB";
    } else if (tx > 1048576) {
        short_tx /= 1048576;
        Text = "MiB";
    } else if (tx > 1024) {
        short_tx /= 1024;
        Text = "KiB";
    }

    printf("        ");
    printf(_("RX packets %llu  bytes %llu (%lu.%lu %s)\n"),
        ptr->stats.rx_packets,
           rx, (unsigned long)(short_rx / 10),
           (unsigned long)(short_rx % 10), Rext);
    if (can_compress) {
          printf("        ");
        printf(_("RX compressed:%lu\n"), ptr->stats.rx_compressed);
    }
    printf("        ");
    printf(_("RX errors %lu  dropped %lu  overruns %lu  frame %lu\n"),
           ptr->stats.rx_errors, ptr->stats.rx_dropped,
           ptr->stats.rx_fifo_errors, ptr->stats.rx_frame_errors);


    printf("        ");
    printf(_("TX packets %llu  bytes %llu (%lu.%lu %s)\n"),
        ptr->stats.tx_packets,
            tx, (unsigned long)(short_tx / 10),
            (unsigned long)(short_tx % 10), Text);
    if (can_compress) {
          printf("        ");
        printf(_("TX compressed %lu\n"), ptr->stats.tx_compressed);
    }
    printf("        ");
    printf(_("TX errors %lu  dropped %lu overruns %lu  carrier %lu  collisions %lu\n"),
           ptr->stats.tx_errors,
           ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
           ptr->stats.tx_carrier_errors, ptr->stats.collisions);
    }

    if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
     ptr->map.base_addr >= 0x100)) {
    printf("        device ");
    if (ptr->map.irq)
        printf(_("interrupt %d  "), ptr->map.irq);
    if (ptr->map.base_addr >= 0x100)    /* Only print devices using it for
                           I/O maps */
        printf(_("base 0x%x  "), ptr->map.base_addr);
    if (ptr->map.mem_start) {
        printf(_("memory 0x%lx-%lx  "), ptr->map.mem_start, ptr->map.mem_end);
    }
    if (ptr->map.dma)
        printf(_("  dma 0x%x"), ptr->map.dma);
    printf("\n");
    }
    printf("\n");
}

void ife_print(struct interface *i)
{
    if (ife_short)
    ife_print_short(i);
    else
    ife_print_long(i);
}

 

主要函数:

main()
->if_print() // 输入参数 网卡ifname
  ->lookup_interface()
    ->do_if_fetch()
      ->if_fetch() // 通过ioctl API与内核交互,获取或改变内核参数
        ->ife_print()

4、/proc/net/dev

#  cat /proc/net/dev
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
  eth0: 20707884  230789    0    0    0     0          0         4 1139127757  780413    0    0    0     0       0          0
  eth1: 703035720  648487    0    0    0     0          0         0 19639557  256754    0    0    0     0       0          0
  eth2:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
  eth3:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
  eth4:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
  eth5:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
    lo: 226701541 1536989    0    0    0     0          0         0 226701541 1536989    0    0    0     0       0          0

bytes: The total number of bytes of data transmitted or received by the interface.(接口发送或接收的数据的总字节数)
packets: The total number of packets of data transmitted or received by the interface.(接口发送或接收的数据包总数)
errs: The total number of transmit or receive errors detected by the device driver.(由设备驱动程序检测到的发送或接收错误的总数)
drop: The total number of packets dropped by the device driver.(设备驱动程序丢弃的数据包总数)
fifo: The number of FIFO buffer errors.(FIFO缓冲区错误的数量)
frame: The number of packet framing errors.(分组帧错误的数量)
colls: The number of collisions detected on the interface.(接口上检测到的冲突数)
compressed: The number of compressed packets transmitted or received by the device driver. (This appears to be unused in the 2.2.15 kernel.)(设备驱动程序发送或接收的压缩数据包数)
carrier: The number of carrier losses detected by the device driver.(由设备驱动程序检测到的载波损耗的数量)
multicast: The number of multicast frames transmitted or received by the device driver.(设备驱动程序发送或接收的多播帧数)

5、其他

IFF_UP:网卡管理状态UP/DOWN,并不代表真实物理连接状态,未必插网线。

IFF_RUNNING: 网卡运行状态RUNNING/Not RUNNING,指的是设备资源是否ready、connected,一般可以作为有线网卡是否插网线、无线是否连接的状态判断。

 

posted @ 2022-03-15 13:40  JeromePowell  阅读(154)  评论(0编辑  收藏  举报