and added files
[bcm963xx.git] / userapps / opensource / net-snmp / apps / snmpnetstat / inet6.c
diff --git a/userapps/opensource/net-snmp/apps/snmpnetstat/inet6.c b/userapps/opensource/net-snmp/apps/snmpnetstat/inet6.c
new file mode 100644 (file)
index 0000000..f7b1767
--- /dev/null
@@ -0,0 +1,704 @@
+/****************************************************************
+       Copyright 1989, 1991, 1992 by Carnegie Mellon University
+
+                      All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the name of CMU not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  
+
+CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+******************************************************************/
+/*
+ * Copyright (c) 1983,1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of California at Berkeley. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#include <net-snmp/net-snmp-config.h>
+
+#ifdef INET6
+
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#include <stdio.h>
+
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#if HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#if HAVE_WINSOCK_H
+#include <winsock.h>
+#include "winstub.h"
+#else
+#include <sys/socket.h>
+#include <netdb.h>
+#endif
+
+#include "main.h"
+#include <net-snmp/net-snmp-includes.h>
+#include "netstat.h"
+
+static char    *inet6name(struct in6_addr *);
+
+struct stat_table {
+    int             entry;      /* entry number in table */
+    /*
+     * format string to printf(description, value, plural(value)); 
+     */
+    /*
+     * warning: the %d must be before the %s 
+     */
+    char            description[80];
+};
+
+#if DEBUGGING_INFORMATION
+        /*
+         * The following tables provide useful debugging information.
+         * This isn't normally needed or easily accessible,
+         *   but could potentially be very useful.
+         * Rather than delete it totally, it's commented out
+         */
+static oid      oid_ipstats[] = { 1, 3, 6, 1, 2, 1, 4, 0, 0 };
+struct stat_table ip_stattab[] = {
+    {3, "%d total datagram%s received"},
+    {4, "%d datagram%s with header errors"},
+    {5, "%d datagram%s with an invalid destination address"},
+    {6, "%d datagram%s forwarded"},
+    {7, "%d datagram%s with unknown protocol"},
+    {8, "%d datagram%s discarded"},
+    {9, "%d datagram%s delivered"},
+    {10, "%d output datagram request%s"},
+    {11, "%d output datagram%s discarded"},
+    {12, "%d datagram%s with no route"},
+    {14, "%d fragment%s received"},
+    {15, "%d datagram%s reassembled"},
+    {16, "%d reassembly failure%s"},
+    {17, "%d datagram%s fragmented"},
+    {18, "%d fragmentation failure%s"},
+    {19, "%d fragment%s created"}
+};
+
+static oid      oid_udpstats[] = { 1, 3, 6, 1, 2, 1, 7, 0, 0 };
+struct stat_table udp_stattab[] = {
+    {1, "%d total datagram%s received"},
+    {2, "%d datagram%s to invalid port"},
+    {3, "%d datagram%s dropped due to errors"},
+    {4, "%d output datagram request%s"}
+};
+
+static oid      oid_tcpstats[] = { 1, 3, 6, 1, 2, 1, 6, 0, 0 };
+struct stat_table tcp_stattab[] = {
+    {5, "%d active open%s"},
+    {6, "%d passive open%s"},
+    {7, "%d failed attempt%s"},
+    {8, "%d reset%s of established connections"},
+    {9, "%d current established connection%s"},
+    {10, "%d segment%s received"},
+    {11, "%d segment%s sent"},
+    {12, "%d segment%s retransmitted"}
+};
+
+static oid      oid_icmpstats[] = { 1, 3, 6, 1, 2, 1, 5, 0, 0 };
+struct stat_table icmp_stattab[] = {
+    {1, "%d total message%s received"},
+    {2, "%d message%s dropped due to errors"},
+    {14, "%d ouput message request%s"},
+    {15, "%d output message%s discarded"}
+};
+
+struct stat_table icmp_inhistogram[] = {
+    {3, "Destination unreachable: %d"},
+    {4, "Time Exceeded: %d"},
+    {5, "Parameter Problem: %d"},
+    {6, "Source Quench: %d"},
+    {7, "Redirect: %d"},
+    {8, "Echo Request: %d"},
+    {9, "Echo Reply: %d"},
+    {10, "Timestamp Request: %d"},
+    {11, "Timestamp Reply: %d"},
+    {12, "Address Mask Request: %d"},
+    {13, "Addrss Mask Reply:%d"},
+};
+
+struct stat_table icmp_outhistogram[] = {
+    {16, "Destination unreachable: %d"},
+    {17, "Time Exceeded: %d"},
+    {18, "Parameter Problem: %d"},
+    {19, "Source Quench: %d"},
+    {20, "Redirect: %d"},
+    {21, "Echo Request: %d"},
+    {22, "Echo Reply: %d"},
+    {23, "Timestamp Request: %d"},
+    {24, "Timestamp Reply: %d"},
+    {25, "Address Mask Request: %d"},
+    {26, "Addrss Mask Reply:%d"},
+};
+#endif
+
+struct tcpconn_entry {
+    oid             instance[16 + 1 + 16 + 1 + 1];
+    struct in6_addr localAddress;
+    int             locAddrSet;
+    u_short         localPort;
+    int             locPortSet;
+    struct in6_addr remoteAddress;
+    int             remAddrSet;
+    u_short         remotePort;
+    int             remPortSet;
+    int             state;
+    int             stateSet;
+    struct tcpconn_entry *next;
+};
+
+struct udp_entry {
+    oid             instance[16 + 1 + 1];
+    struct in6_addr localAddress;
+    int             locAddrSet;
+    u_short         localPort;
+    int             locPortSet;
+    struct udp_entry *next;
+};
+
+#define TCPCONN_LOCADDR        1
+#define TCPCONN_LOCPORT        2
+#define TCPCONN_REMADDR        3
+#define TCPCONN_REMPORT        4
+#define TCPCONN_IFINDEX        5
+#define TCPCONN_STATE  6
+
+static oid      oid_tcpconntable[] = { 1, 3, 6, 1, 3, 86, 1, 16, 1 };
+#define TCP_ENTRY 9
+
+#define UDP_LOCADDR    1
+#define UDP_LOCPORT    2
+#define UDP_IFINDEX    3
+
+static oid      oid_udptable[] = { 1, 3, 6, 1, 3, 87, 1, 1, 1 };
+#define UDP_ENTRY 9
+
+static const char *tcpstates[] = {
+    "",
+    "CLOSED",
+    "LISTEN",
+    "SYNSENT",
+    "SYNRECEIVED",
+    "ESTABLISHED",
+    "FINWAIT1",
+    "FINWAIT2",
+    "CLOSEWAIT",
+    "LASTACK",
+    "CLOSING",
+    "TIMEWAIT"
+};
+#define TCP_NSTATES 11
+
+static int      validUShortAssign(unsigned short *, int, const char *);
+
+/*
+ * Print a summary of connections related to an Internet
+ * protocol (currently only TCP).  For TCP, also give state of connection.
+ */
+void
+protopr6(const char *name)
+{
+    struct tcpconn_entry *tcpconn = NULL, *tcplast = NULL, *tp, *newtp;
+    struct udp_entry *udpconn = NULL, *udplast = NULL, *up, *newup;
+    netsnmp_pdu    *request = NULL, *response = NULL;
+    netsnmp_variable_list *vp;
+    oid            *instance;
+    int             first, status;
+
+    response = NULL;
+    if (strncmp(name, "tcp", 3) == 0) {
+        request = snmp_pdu_create(SNMP_MSG_GETNEXT);
+        snmp_add_null_var(request, oid_tcpconntable,
+                          sizeof(oid_tcpconntable) / sizeof(oid));
+        status = STAT_SUCCESS;
+    } else
+        status = STAT_TIMEOUT;
+    while (status == STAT_SUCCESS) {
+        if (response)
+            snmp_free_pdu(response);
+        response = NULL;
+        status = snmp_synch_response(Session, request, &response);
+        if (status != STAT_SUCCESS
+            || response->errstat != SNMP_ERR_NOERROR) {
+            snmp_perror("SNMP request failed");
+            break;
+        }
+        vp = response->variables;
+        if (!vp)
+            break;
+        if (vp->name_length != 46 ||
+            memcmp(vp->name, oid_tcpconntable, sizeof(oid_tcpconntable))) {
+            break;
+        }
+
+        request = snmp_pdu_create(SNMP_MSG_GETNEXT);
+        snmp_add_null_var(request, vp->name, vp->name_length);
+
+        instance = vp->name + 10;
+        for (tp = tcpconn; tp != NULL; tp = tp->next) {
+            if (!memcmp(instance, tp->instance, sizeof(tp->instance)))
+                break;
+        }
+        if (tp == NULL) {
+            tp = (struct tcpconn_entry *) calloc(1,
+                                                 sizeof(struct
+                                                        tcpconn_entry));
+            if (tp == NULL)
+                break;
+            if (tcplast != NULL)
+                tcplast->next = tp;
+            tcplast = tp;
+            if (tcpconn == NULL)
+                tcpconn = tp;
+            memmove(tp->instance, instance, sizeof(tp->instance));
+        }
+
+        if (vp->name[TCP_ENTRY] == TCPCONN_STATE) {
+            tp->state = *vp->val.integer;
+            tp->stateSet = 1;
+        }
+
+        if (vp->name[TCP_ENTRY] == TCPCONN_LOCADDR) {
+            memmove(&tp->localAddress, vp->val.string,
+                    sizeof(struct in6_addr));
+            tp->locAddrSet = 1;
+        }
+
+        if (vp->name[TCP_ENTRY] == TCPCONN_LOCPORT) {
+            if (validUShortAssign(&tp->localPort, *vp->val.integer,
+                                  "TCPCONN_LOCPORT"))
+                tp->locPortSet = 1;
+        }
+
+        if (vp->name[TCP_ENTRY] == TCPCONN_REMADDR) {
+            memmove(&tp->remoteAddress, vp->val.string,
+                    sizeof(struct in6_addr));
+            tp->remAddrSet = 1;
+        }
+
+        if (vp->name[TCP_ENTRY] == TCPCONN_REMPORT) {
+            if (validUShortAssign(&tp->remotePort, *vp->val.integer,
+                                  "TCPCONN_REMPORT"))
+                tp->remPortSet = 1;
+        }
+    }
+    if (response)
+        snmp_free_pdu(response);
+    response = NULL;
+
+    for (first = 1, tp = tcpconn, newtp = NULL; tp != NULL; tp = tp->next) {
+        if (newtp)
+            free(newtp);
+        newtp = tp;
+        if (!(tp->stateSet && tp->locAddrSet
+              && tp->locPortSet && tp->remAddrSet && tp->remPortSet)) {
+            printf("incomplete entry\n");
+            continue;
+        }
+        if (!aflag && tp->state == MIB_TCPCONNSTATE_LISTEN)
+            continue;
+        if (first) {
+            printf("Active Internet (%s) Connections", name);
+            if (aflag)
+                printf(" (including servers)");
+            putchar('\n');
+            printf("%-5.5s %-28.28s %-28.28s %s\n",
+                   "Proto", "Local Address", "Foreign Address", "(state)");
+            first = 0;
+        }
+        printf("%-5.5s ", name);
+        inet6print(&tp->localAddress, tp->localPort, name);
+        inet6print(&tp->remoteAddress, tp->remotePort, name);
+        if (tp->state < 1 || tp->state > TCP_NSTATES)
+            printf(" %d", tp->state);
+        else
+            printf(" %s", tcpstates[tp->state]);
+        putchar('\n');
+    }
+    if (newtp)
+        free(newtp);
+
+    response = NULL;
+    if (strncmp(name, "udp", 3) == 0) {
+        request = snmp_pdu_create(SNMP_MSG_GETNEXT);
+        snmp_add_null_var(request, oid_udptable,
+                          sizeof(oid_udptable) / sizeof(oid));
+        status = STAT_SUCCESS;
+    } else
+        status = STAT_TIMEOUT;
+    while (status == STAT_SUCCESS) {
+        if (response)
+            snmp_free_pdu(response);
+        response = NULL;
+        status = snmp_synch_response(Session, request, &response);
+        if (status != STAT_SUCCESS
+            || response->errstat != SNMP_ERR_NOERROR) {
+            fprintf(stderr, "SNMP request failed\n");
+            break;
+        }
+        vp = response->variables;
+        if (!vp)
+            break;
+        if (vp->name_length != 28 ||
+            memcmp(vp->name, oid_udptable, sizeof(oid_udptable))) {
+            break;
+        }
+
+        request = snmp_pdu_create(SNMP_MSG_GETNEXT);
+        snmp_add_null_var(request, vp->name, vp->name_length);
+
+        instance = vp->name + 10;
+        for (up = udpconn; up != NULL; up = up->next) {
+            if (!memcmp(instance, up->instance, sizeof(up->instance)))
+                break;
+        }
+        if (up == NULL) {
+            up = (struct udp_entry *) calloc(1, sizeof(struct udp_entry));
+            if (up == NULL)
+                break;
+            if (udplast != NULL)
+                udplast->next = up;
+            udplast = up;
+            if (udpconn == NULL)
+                udpconn = up;
+            memmove(up->instance, instance, sizeof(up->instance));
+        }
+
+        if (vp->name[UDP_ENTRY] == UDP_LOCADDR) {
+            memmove(&up->localAddress, vp->val.string,
+                    sizeof(struct in6_addr));
+            up->locAddrSet = 1;
+        }
+
+        if (vp->name[UDP_ENTRY] == UDP_LOCPORT) {
+            if (validUShortAssign(&up->localPort, *vp->val.integer,
+                                  "UDP_LOCPORT"))
+                up->locPortSet = 1;
+        }
+    }
+    if (response)
+        snmp_free_pdu(response);
+    response = NULL;
+
+    for (first = 1, up = udpconn, newup = NULL; up != NULL; up = up->next) {
+        if (newup)
+            free(newup);
+        newup = up;
+        if (!(up->locAddrSet && up->locPortSet)) {
+            printf("incomplete entry\n");
+            continue;
+        }
+        if (first) {
+            printf("Active Internet (%s) Connections", name);
+            putchar('\n');
+            printf("%-5.5s %-28.28s\n", "Proto", "Local Address");
+            first = 0;
+        }
+        printf("%-5.5s ", name);
+        inet6print(&up->localAddress, up->localPort, name);
+        putchar('\n');
+    }
+    if (newup)
+        free(newup);
+
+}
+
+static int
+validUShortAssign(unsigned short *pushort, int ival, const char *errstr)
+{
+    u_long          ulval = (u_long) ival;
+    if (ival > 65535) {
+        printf("Warning: %s value %ld (0x%lx) is not a port address\n",
+               errstr, ulval, ulval);
+        return 0;
+    }
+    *pushort = (unsigned short) ulval;
+    return 1;
+}
+
+
+#if DEBUGGING_INFORMATION
+        /*
+         * The following routines print out useful debugging information.
+         * This isn't normally needed or easily accessible,
+         *   but could potentially be very useful.
+         * Rather than delete it totally, it's commented out
+         */
+/*
+ * Dump UDP statistics structure.
+ */
+void
+udp_stats(void)
+{
+    oid             varname[MAX_OID_LEN], *udpentry;
+    int             varname_len;
+    netsnmp_variable_list *var;
+    int             count;
+    struct stat_table *sp = udp_stattab;
+
+    memmove(varname, oid_udpstats, sizeof(oid_udpstats));
+    varname_len = sizeof(oid_udpstats) / sizeof(oid);
+    udpentry = varname + 7;
+    printf("udp:\n");
+    count = sizeof(udp_stattab) / sizeof(struct stat_table);
+    while (count--) {
+        *udpentry = sp->entry;
+        var = getvarbyname(Session, varname, varname_len);
+        if (var && var->val.integer) {
+            putchar('\t');
+            printf(sp->description, *var->val.integer,
+                   plural((int) *var->val.integer));
+            putchar('\n');
+        }
+        if (var)
+            snmp_free_var(var);
+        sp++;
+    }
+
+}
+
+/*
+ * Dump TCP statistics structure.
+ */
+void
+tcp_stats(void)
+{
+    oid             varname[MAX_OID_LEN], *tcpentry;
+    int             varname_len;
+    netsnmp_variable_list *var;
+    int             count;
+    struct stat_table *sp = tcp_stattab;
+
+    memmove(varname, oid_tcpstats, sizeof(oid_tcpstats));
+    varname_len = sizeof(oid_tcpstats) / sizeof(oid);
+    tcpentry = varname + 7;
+    printf("tcp:\n");
+    count = sizeof(tcp_stattab) / sizeof(struct stat_table);
+    while (count--) {
+        *tcpentry = sp->entry;
+        var = getvarbyname(Session, varname, varname_len);
+        if (var && var->val.integer) {
+            putchar('\t');
+            printf(sp->description, *var->val.integer,
+                   plural((int) *var->val.integer));
+            putchar('\n');
+        }
+        if (var)
+            snmp_free_var(var);
+        sp++;
+    }
+
+}
+
+/*
+ * Dump IP statistics structure.
+ */
+void
+ip_stats(void)
+{
+    oid             varname[MAX_OID_LEN], *ipentry;
+    int             varname_len;
+    netsnmp_variable_list *var;
+    int             count;
+    struct stat_table *sp = ip_stattab;
+
+    memmove(varname, oid_ipstats, sizeof(oid_ipstats));
+    varname_len = sizeof(oid_ipstats) / sizeof(oid);
+    ipentry = varname + 7;
+    printf("ip:\n");
+    count = sizeof(ip_stattab) / sizeof(struct stat_table);
+    while (count--) {
+        *ipentry = sp->entry;
+        var = getvarbyname(Session, varname, varname_len);
+        if (var && var->val.integer) {
+            putchar('\t');
+            printf(sp->description, *var->val.integer,
+                   plural((int) *var->val.integer));
+            putchar('\n');
+        }
+        if (var)
+            snmp_free_var(var);
+        sp++;
+    }
+
+}
+
+/*
+ * Dump ICMP statistics.
+ */
+void
+icmp_stats(void)
+{
+    oid             varname[MAX_OID_LEN], *icmpentry;
+    int             varname_len;
+    netsnmp_variable_list *var;
+    int             count, first;
+    struct stat_table *sp;
+
+    memmove(varname, oid_icmpstats, sizeof(oid_icmpstats));
+    varname_len = sizeof(oid_icmpstats) / sizeof(oid);
+    icmpentry = varname + 7;
+    printf("icmp:\n");
+    sp = icmp_stattab;
+    count = sizeof(icmp_stattab) / sizeof(struct stat_table);
+    while (count--) {
+        *icmpentry = sp->entry;
+        var = getvarbyname(Session, varname, varname_len);
+        if (var && var->val.integer) {
+            putchar('\t');
+            printf(sp->description, *var->val.integer,
+                   plural((int) *var->val.integer));
+            putchar('\n');
+        }
+        if (var)
+            snmp_free_var(var);
+        sp++;
+    }
+
+    sp = icmp_outhistogram;
+    first = 1;
+    count = sizeof(icmp_outhistogram) / sizeof(struct stat_table);
+    while (count--) {
+        *icmpentry = sp->entry;
+        var = getvarbyname(Session, varname, varname_len);
+        if (var && var->val.integer && *var->val.integer != 0) {
+            if (first) {
+                printf("\tOutput Histogram:\n");
+                first = 0;
+            }
+            printf("\t\t");
+            printf(sp->description, *var->val.integer,
+                   plural((int) *var->val.integer));
+            putchar('\n');
+        }
+        if (var)
+            snmp_free_var(var);
+        sp++;
+    }
+
+    sp = icmp_inhistogram;
+    first = 1;
+    count = sizeof(icmp_inhistogram) / sizeof(struct stat_table);
+    while (count--) {
+        *icmpentry = sp->entry;
+        var = getvarbyname(Session, varname, varname_len);
+        if (var && var->val.integer && *var->val.integer != 0) {
+            if (first) {
+                printf("\tInput Histogram:\n");
+                first = 0;
+            }
+            printf("\t\t");
+            printf(sp->description, *var->val.integer,
+                   plural((int) *var->val.integer));
+            putchar('\n');
+        }
+        if (var)
+            snmp_free_var(var);
+        sp++;
+    }
+}
+#endif
+
+/*
+ * Pretty print an Internet address (net address + port).
+ * If the nflag was specified, use numbers instead of names.
+ */
+void
+inet6print(struct in6_addr *in, u_short port, const char *proto)
+{
+    struct servent *sp = 0;
+    char            line[80], *cp;
+    int             width;
+
+    sprintf(line, "%.*s.", 22, inet6name(in));
+    cp = strchr(line, '\0');
+    if (!nflag && port)
+        sp = getservbyport(htons(port), proto);
+    if (sp || port == 0)
+        sprintf(cp, "%.8s", sp ? sp->s_name : "*");
+    else
+        sprintf(cp, "%d", port);
+    width = 28;
+    printf(" %-*.*s", width, width, line);
+}
+
+/*
+ * Construct an Internet address representation.
+ * If the nflag has been supplied, give 
+ * numeric value, otherwise try for symbolic name.
+ */
+static char    *
+inet6name(struct in6_addr *in)
+{
+    register char  *cp;
+    static char     line[50];
+    struct hostent *hp;
+    static char     domain[MAXHOSTNAMELEN + 1];
+    static int      first = 1;
+
+    if (first && !nflag) {
+        first = 0;
+        if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
+            (cp = strchr(domain, '.')))
+            (void) strcpy(domain, cp + 1);
+        else
+            domain[0] = 0;
+    }
+    cp = 0;
+    if (!nflag && !IN6_IS_ADDR_UNSPECIFIED(in)) {
+        hp = gethostbyaddr((char *) in, sizeof(*in), AF_INET6);
+        if (hp) {
+            if ((cp = strchr(hp->h_name, '.')) && !strcmp(cp + 1, domain))
+                *cp = 0;
+            cp = hp->h_name;
+        }
+    }
+    if (IN6_IS_ADDR_UNSPECIFIED(in))
+        strcpy(line, "*");
+    else if (cp) {
+        strncpy(line, cp, sizeof(line));
+        line[ sizeof(line)-1 ] = 0;
+    } else
+        inet_ntop(AF_INET6, in, line, sizeof(line));
+    return (line);
+}
+
+#endif                          /* INET6 */