root/tools/tools/ifinfo/ifinfo.c
/*
 * Copyright 1996 Massachusetts Institute of Technology
 *
 * Permission to use, copy, modify, and distribute this software and
 * its documentation for any purpose and without fee is hereby
 * granted, provided that both the above copyright notice and this
 * permission notice appear in all copies, that both the above
 * copyright notice and this permission notice appear in all
 * supporting documentation, and that the name of M.I.T. not be used
 * in advertising or publicity pertaining to distribution of the
 * software without specific, written prior permission.  M.I.T. makes
 * no representations about the suitability of this software for any
 * purpose.  It is provided "as is" without express or implied
 * warranty.
 *
 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
#include <sys/types.h>
#include <sys/socket.h>         /* for PF_LINK */
#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/mbuf.h>

#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
#include <stdbool.h>
#include <ctype.h>

#include <net/if.h>
#include <net/if_types.h>
#include <net/if_mib.h>

#include "ifinfo.h"

static void printit(const struct ifmibdata *, const char *);
static const char *iftype(int);
static int isit(int, char **, const char *);
static printfcn findlink(int);

static void
usage(const char *argv0)
{
        fprintf(stderr, "%s: usage:\n\t%s [-l]\n", argv0, argv0);
        exit(EX_USAGE);
}

int
main(int argc, char **argv)
{
        int i, maxifno, retval;
        struct ifmibdata ifmd;
        int name[6];
        size_t len;
        int c;
        int dolink = 0;
        void *linkmib;
        size_t linkmiblen;
        printfcn pf;
        char *dname;

        while ((c = getopt(argc, argv, "l")) != -1) {
                switch(c) {
                case 'l':
                        dolink = 1;
                        break;
                default:
                        usage(argv[0]);
                }
        }

        retval = 1;

        name[0] = CTL_NET;
        name[1] = PF_LINK;
        name[2] = NETLINK_GENERIC;
        name[3] = IFMIB_SYSTEM;
        name[4] = IFMIB_IFCOUNT;

        len = sizeof maxifno;
        if (sysctl(name, 5, &maxifno, &len, 0, 0) < 0)
                err(EX_OSERR, "sysctl(net.link.generic.system.ifcount)");

        for (i = 1; i <= maxifno; i++) {
                len = sizeof ifmd;
                name[3] = IFMIB_IFDATA;
                name[4] = i;
                name[5] = IFDATA_GENERAL;
                if (sysctl(name, 6, &ifmd, &len, 0, 0) < 0) {
                        if (errno == ENOENT)
                                continue;

                        err(EX_OSERR, "sysctl(net.link.ifdata.%d.general)",
                            i);
                }

                if (!isit(argc - optind, argv + optind, ifmd.ifmd_name))
                        continue;

                dname = NULL;
                len = 0;
                name[5] = IFDATA_DRIVERNAME;
                if (sysctl(name, 6, NULL, &len, 0, 0) < 0) {
                        warn("sysctl(net.link.ifdata.%d.drivername)", i);
                } else {
                        if ((dname = malloc(len)) == NULL)
                                err(EX_OSERR, NULL);
                        if (sysctl(name, 6, dname, &len, 0, 0) < 0) {
                                warn("sysctl(net.link.ifdata.%d.drivername)",
                                    i);
                                free(dname);
                                dname = NULL;
                        }
                }
                printit(&ifmd, dname);
                free(dname);
                if (dolink && (pf = findlink(ifmd.ifmd_data.ifi_type))) {
                        name[5] = IFDATA_LINKSPECIFIC;
                        if (sysctl(name, 6, 0, &linkmiblen, 0, 0) < 0)
                                err(EX_OSERR,
                                    "sysctl(net.link.ifdata.%d.linkspec) size",
                                    i);
                        linkmib = malloc(linkmiblen);
                        if (!linkmib)
                                err(EX_OSERR, "malloc(%lu)",
                                    (u_long)linkmiblen);
                        if (sysctl(name, 6, linkmib, &linkmiblen, 0, 0) < 0)
                                err(EX_OSERR,
                                    "sysctl(net.link.ifdata.%d.linkspec)",
                                    i);
                        pf(linkmib, linkmiblen);
                        free(linkmib);
                }
                retval = 0;
        }

        return retval;
}

/* code after this line copied or based on code from src/sys/kern/subr_prf.c */
static inline bool
isbitpos(char c)
{
        return (c != '\0' && (c <= ' ' || (c & 0x80) != 0));
}

static inline bool
isprintnospace(char c)
{
        return (isprint(c) && c != ' ');
}

static void
print_bits(uintmax_t num, const char *bitstring)
{
        bool first;
        const char *c;
        int shift;

        c = ++bitstring;
        first = true;
        while (isbitpos(*c)) {
                if ((*c & 0x80) != 0)
                        shift = *c++ & 0x7f;
                else
                        shift = *c++ - 1;
                if (num & (1ULL << shift)) {
                        putchar(first ? (first = false, '<') : ',');
                        for (; isprintnospace(*c); ++c)
                                putchar(*c);
                } else
                        for (; isprintnospace(*c); ++c)
                                continue;
        }
        if (!first) {
                putchar('>');
        }
}
/* code before this line copied or based on code from src/sys/kern/subr_prf.c */

static void
printit(const struct ifmibdata *ifmd, const char *dname)
{
        printf("Interface %.*s", IFNAMSIZ, ifmd->ifmd_name);
        if (dname != NULL)
                printf(" (%s)", dname);
        printf(":\n");
        printf("\tflags: %x\n", ifmd->ifmd_flags);
        printf("\tpromiscuous listeners: %d\n", ifmd->ifmd_pcount);
        printf("\tsend queue length: %d\n", ifmd->ifmd_snd_len);
        printf("\tsend queue max length: %d\n", ifmd->ifmd_snd_maxlen);
        printf("\tsend queue drops: %d\n", ifmd->ifmd_snd_drops);
        printf("\ttype: %s\n", iftype(ifmd->ifmd_data.ifi_type));
        printf("\taddress length: %d\n", ifmd->ifmd_data.ifi_addrlen);
        printf("\theader length: %d\n", ifmd->ifmd_data.ifi_hdrlen);
        printf("\tlink state: %u\n", ifmd->ifmd_data.ifi_link_state);
        printf("\tvhid: %u\n", ifmd->ifmd_data.ifi_vhid);
        printf("\tdatalen: %u\n", ifmd->ifmd_data.ifi_datalen);
        printf("\tmtu: %u\n", ifmd->ifmd_data.ifi_mtu);
        printf("\tmetric: %u\n", ifmd->ifmd_data.ifi_metric);
        printf("\tline rate: %lu bit/s\n", ifmd->ifmd_data.ifi_baudrate);
        printf("\tpackets received: %lu\n", ifmd->ifmd_data.ifi_ipackets);
        printf("\tinput errors: %lu\n", ifmd->ifmd_data.ifi_ierrors);
        printf("\tpackets transmitted: %lu\n", ifmd->ifmd_data.ifi_opackets);
        printf("\toutput errors: %lu\n", ifmd->ifmd_data.ifi_oerrors);
        printf("\tcollisions: %lu\n", ifmd->ifmd_data.ifi_collisions);
        printf("\tbytes received: %lu\n", ifmd->ifmd_data.ifi_ibytes);
        printf("\tbytes transmitted: %lu\n", ifmd->ifmd_data.ifi_obytes);
        printf("\tmulticasts received: %lu\n", ifmd->ifmd_data.ifi_imcasts);
        printf("\tmulticasts transmitted: %lu\n", ifmd->ifmd_data.ifi_omcasts);
        printf("\tinput queue drops: %lu\n", ifmd->ifmd_data.ifi_iqdrops);
        printf("\tpackets for unknown protocol: %lu\n",
               ifmd->ifmd_data.ifi_noproto);
        printf("\tHW offload capabilities: 0x%lx",
            ifmd->ifmd_data.ifi_hwassist);
        print_bits(ifmd->ifmd_data.ifi_hwassist, CSUM_BITS);
        printf("\n");
        printf("\tuptime at attach or stat reset: %lu\n",
            ifmd->ifmd_data.ifi_epoch);
#ifdef notdef
        printf("\treceive timing: %lu usec\n", ifmd->ifmd_data.ifi_recvtiming);
        printf("\ttransmit timing: %lu usec\n",
               ifmd->ifmd_data.ifi_xmittiming);
#endif
}

static const char *const if_types[] = {
        "reserved",
        "other",
        "BBN 1822",
        "HDH 1822",
        "X.25 DDN",
        "X.25",
        "Ethernet",
        "ISO 8802-3 CSMA/CD",
        "ISO 8802-4 Token Bus",
        "ISO 8802-5 Token Ring",
        "ISO 8802-6 DQDB MAN",
        "StarLAN",
        "Proteon proNET-10",
        "Proteon proNET-80",
        "HyperChannel",
        "FDDI",
        "LAP-B",
        "SDLC",
        "T-1",
        "CEPT",
        "Basic rate ISDN",
        "Primary rate ISDN",
        "Proprietary P2P",
        "PPP",
        "Loopback",
        "ISO CLNP over IP",
        "Experimental Ethernet",
        "XNS over IP",
        "SLIP",
        "Ultra Technologies",
        "DS-3",
        "SMDS",
        "Frame Relay",
        "RS-232 serial",
        "Parallel printer port",
        "ARCNET",
        "ARCNET+",
        "ATM",
        "MIOX25",
        "SONET/SDH",
        "X25PLE",
        "ISO 8802-2 LLC",
        "LocalTalk",
        "SMDSDXI",
        "Frame Relay DCE",
        "V.35",
        "HSSI",
        "HIPPI",
        "Generic Modem",
        "ATM AAL5",
        "SONETPATH",
        "SONETVT",
        "SMDS InterCarrier Interface",
        "Proprietary virtual interface",
        "Proprietary multiplexing",
        "Generic tunnel interface",
        "IPv6-to-IPv4 TCP relay capturing interface",
        "6to4 tunnel interface"
};
#define NIFTYPES (int)((sizeof if_types)/(sizeof if_types[0]))

static const char *
iftype(int type)
{
        static char buf[256];

        if (type <= 0 || type >= NIFTYPES) {
                sprintf(buf, "unknown type %d", type);
                return buf;
        }

        return if_types[type];
}

static int
isit(int argc, char **argv, const char *name)
{
        if (argc == 0)
                return 1;
        for (argc = 0; argv[argc]; argc++) {
                if (strncmp(argv[argc], name, IFNAMSIZ) == 0)
                        return 1;
        }
        return 0;
}

static printfcn
findlink(int type)
{
        switch(type) {
        case IFT_ETHER:
        case IFT_ISO88023:
        case IFT_STARLAN:
                return print_1650;
        }

        return 0;
}