Blame agent/mibgroup/kernel_sunos5.c

Packit fcad23
/* Portions of this file are subject to the following copyright(s).  See
Packit fcad23
 * the Net-SNMP's COPYING file for more details and other copyrights
Packit fcad23
 * that may apply:
Packit fcad23
 */
Packit fcad23
/*
Packit fcad23
 * Portions of this file are copyrighted by:
Packit fcad23
 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
Packit fcad23
 * Use is subject to license terms specified in the COPYING file
Packit fcad23
 * distributed with the Net-SNMP package.
Packit fcad23
 */
Packit fcad23
Packit fcad23
/*- This is a -*- C -*- compatible code file
Packit fcad23
 *
Packit fcad23
 * Code for SUNOS5_INSTRUMENTATION
Packit fcad23
 *
Packit fcad23
 * This file contains includes of standard and local system header files,
Packit fcad23
 * includes of other application header files, global variable definitions,
Packit fcad23
 * static variable definitions, static function prototypes, and function
Packit fcad23
 * definitions.
Packit fcad23
 *
Packit fcad23
 * This file contains function to obtain statistics from SunOS 5.x kernel
Packit fcad23
 *
Packit fcad23
 */
Packit fcad23
Packit fcad23
#include <net-snmp/net-snmp-config.h>
Packit fcad23
#ifdef solaris2
Packit fcad23
/*-
Packit fcad23
 * Includes of standard ANSI C header files 
Packit fcad23
 */
Packit fcad23
Packit fcad23
#include <stdio.h>
Packit fcad23
#include <stdlib.h>
Packit fcad23
#include <unistd.h>
Packit fcad23
#include <string.h>
Packit fcad23
Packit fcad23
/*-
Packit fcad23
 * Includes of system header files (wrapped in duplicate include prevention)
Packit fcad23
 */
Packit fcad23
Packit fcad23
#include <fcntl.h>
Packit fcad23
#include <stropts.h>
Packit fcad23
#include <sys/types.h>
Packit fcad23
#include <kvm.h>
Packit fcad23
#include <sys/fcntl.h>
Packit fcad23
#include <kstat.h>
Packit fcad23
#include <errno.h>
Packit fcad23
#include <time.h>
Packit fcad23
#include <ctype.h>
Packit fcad23
Packit fcad23
#include <sys/sockio.h>
Packit fcad23
#include <sys/socket.h>
Packit fcad23
#include <sys/stream.h>
Packit fcad23
#include <sys/stropts.h>
Packit fcad23
#include <sys/tihdr.h>
Packit fcad23
#include <sys/tiuser.h>
Packit fcad23
#include <sys/dlpi.h>
Packit fcad23
#include <inet/common.h>
Packit fcad23
#include <inet/mib2.h>
Packit fcad23
#include <inet/ip.h>
Packit fcad23
#include <net/if.h>
Packit fcad23
#include <netinet/in.h>
Packit fcad23
Packit fcad23
/*-
Packit fcad23
 * Includes of local application header files 
Packit fcad23
 */
Packit fcad23
Packit fcad23
#include <net-snmp/net-snmp-includes.h>
Packit fcad23
#include <net-snmp/agent/net-snmp-agent-includes.h>
Packit fcad23
Packit fcad23
#include "kernel_sunos5.h"
Packit fcad23
Packit fcad23
kstat_ctl_t    *kstat_fd = 0;
Packit fcad23
Packit fcad23
/*-
Packit fcad23
 * Global variable definitions (with initialization)
Packit fcad23
 */
Packit fcad23
Packit fcad23
/*-
Packit fcad23
 * Static variable definitions (with initialization)
Packit fcad23
 */
Packit fcad23
Packit fcad23
static
Packit fcad23
mibcache        Mibcache[MIBCACHE_SIZE+1] = {
Packit fcad23
    {MIB_SYSTEM, 0, (void *) -1, 0, 0, 0, 0},
Packit fcad23
    {MIB_INTERFACES, 50 * sizeof(mib2_ifEntry_t), (void *) -1, 0, 3, 0,
Packit fcad23
     0},
Packit fcad23
    {MIB_AT, 0, (void *) -1, 0, 0, 0, 0},
Packit fcad23
    {MIB_IP, sizeof(mib2_ip_t), (void *) -1, 0, 60, 0, 0},
Packit fcad23
    {MIB_IP_ADDR, 20 * sizeof(mib2_ipAddrEntry_t), (void *) -1, 0, 60, 0,
Packit fcad23
     0},
Packit fcad23
    {MIB_IP_ROUTE, 200 * sizeof(mib2_ipRouteEntry_t), (void *) -1, 0, 30,
Packit fcad23
     0, 0},
Packit fcad23
    {MIB_IP_NET, 100 * sizeof(mib2_ipNetToMediaEntry_t), (void *) -1, 0,
Packit fcad23
     300, 0, 0},
Packit fcad23
    {MIB_ICMP, sizeof(mib2_icmp_t), (void *) -1, 0, 60, 0, 0},
Packit fcad23
    {MIB_TCP, sizeof(mib2_tcp_t), (void *) -1, 0, 60, 0, 0},
Packit fcad23
    {MIB_TCP_CONN, 1000 * sizeof(mib2_tcpConnEntry_t), (void *) -1, 0, 30,
Packit fcad23
     0, 0},
Packit fcad23
    {MIB_UDP, sizeof(mib2_udp_t), (void *) -1, 0, 30, 0, 0},
Packit fcad23
    {MIB_UDP_LISTEN, 1000 * sizeof(mib2_udpEntry_t), (void *) -1, 0, 30, 0,
Packit fcad23
     0},
Packit fcad23
    {MIB_EGP, 0, (void *) -1, 0, 0, 0, 0},
Packit fcad23
    {MIB_CMOT, 0, (void *) -1, 0, 0, 0, 0},
Packit fcad23
    {MIB_TRANSMISSION, 0, (void *) -1, 0, 0, 0, 0},
Packit fcad23
    {MIB_SNMP, 0, (void *) -1, 0, 0, 0, 0},
Packit fcad23
#ifdef SOLARIS_HAVE_IPV6_MIB_SUPPORT
Packit fcad23
#ifdef SOLARIS_HAVE_RFC4293_SUPPORT
Packit fcad23
    {MIB_IP_TRAFFIC_STATS, 20 * sizeof(mib2_ipIfStatsEntry_t), (void *)-1, 0,
Packit fcad23
     30, 0, 0},
Packit fcad23
    {MIB_IP6, 20 * sizeof(mib2_ipIfStatsEntry_t), (void *)-1, 0, 30, 0, 0},
Packit fcad23
#else
Packit fcad23
    {MIB_IP6, 20 * sizeof(mib2_ipv6IfStatsEntry_t), (void *)-1, 0, 30, 0, 0},
Packit fcad23
#endif
Packit fcad23
    {MIB_IP6_ADDR, 20 * sizeof(mib2_ipv6AddrEntry_t), (void *)-1, 0, 30, 0, 0},
Packit fcad23
    {MIB_IP6_ROUTE, 200 * sizeof(mib2_ipv6AddrEntry_t), (void *)-1, 0, 30, 0, 0},
Packit fcad23
    {MIB_ICMP6, 20 * sizeof(mib2_ipv6IfIcmpEntry_t), (void *)-1, 0, 30, 0, 0},
Packit fcad23
    {MIB_TCP6_CONN, 1000 * sizeof(mib2_tcp6ConnEntry_t), (void *) -1, 0, 30,
Packit fcad23
     0, 0},
Packit fcad23
    {MIB_UDP6_ENDPOINT, 1000 * sizeof(mib2_udp6Entry_t), (void *) -1, 0, 30,
Packit fcad23
     0, 0},
Packit fcad23
#endif
Packit fcad23
#ifdef MIB2_SCTP
Packit fcad23
    {MIB_SCTP, sizeof(mib2_sctp_t), (void *)-1, 0, 60, 0, 0},
Packit fcad23
    {MIB_SCTP_CONN, sizeof(mib2_sctpConnEntry_t), (void *)-1, 0, 60, 0, 0},
Packit fcad23
    {MIB_SCTP_CONN_LOCAL, sizeof(mib2_sctpConnLocalEntry_t), (void *)-1, 0,
Packit fcad23
     60, 0, 0},
Packit fcad23
    {MIB_SCTP_CONN_REMOTE, sizeof(mib2_sctpConnRemoteEntry_t), (void *)-1, 0,
Packit fcad23
     60, 0, 0},
Packit fcad23
#endif
Packit fcad23
    {0},
Packit fcad23
};
Packit fcad23
Packit fcad23
static
Packit fcad23
mibmap          Mibmap[MIBCACHE_SIZE+1] = {
Packit fcad23
    {MIB2_SYSTEM, 0,},
Packit fcad23
    {MIB2_INTERFACES, 0,},
Packit fcad23
    {MIB2_AT, 0,},
Packit fcad23
    {MIB2_IP, 0,},
Packit fcad23
    {MIB2_IP, MIB2_IP_20,},
Packit fcad23
    {MIB2_IP, MIB2_IP_21,},
Packit fcad23
    {MIB2_IP, MIB2_IP_22,},
Packit fcad23
    {MIB2_ICMP, 0,},
Packit fcad23
    {MIB2_TCP, 0,},
Packit fcad23
    {MIB2_TCP, MIB2_TCP_13,},
Packit fcad23
    {MIB2_UDP, 0,},
Packit fcad23
    {MIB2_UDP, MIB2_UDP_5},
Packit fcad23
    {MIB2_EGP, 0,},
Packit fcad23
    {MIB2_CMOT, 0,},
Packit fcad23
    {MIB2_TRANSMISSION, 0,},
Packit fcad23
    {MIB2_SNMP, 0,},
Packit fcad23
#ifdef SOLARIS_HAVE_IPV6_MIB_SUPPORT
Packit fcad23
#ifdef SOLARIS_HAVE_RFC4293_SUPPORT
Packit fcad23
    {MIB2_IP, MIB2_IP_TRAFFIC_STATS},
Packit fcad23
#endif
Packit fcad23
    {MIB2_IP6, 0},
Packit fcad23
    {MIB2_IP6, MIB2_IP6_ADDR},
Packit fcad23
    {MIB2_IP6, MIB2_IP6_ROUTE},
Packit fcad23
    {MIB2_ICMP6, 0},
Packit fcad23
    {MIB2_TCP6, MIB2_TCP6_CONN},
Packit fcad23
    {MIB2_UDP6, MIB2_UDP6_ENTRY},
Packit fcad23
#endif
Packit fcad23
#ifdef MIB2_SCTP
Packit fcad23
    {MIB2_SCTP, 0},
Packit fcad23
    {MIB2_SCTP, MIB2_SCTP_CONN},
Packit fcad23
    {MIB2_SCTP, MIB2_SCTP_CONN_LOCAL},
Packit fcad23
    {MIB2_SCTP, MIB2_SCTP_CONN_REMOTE},
Packit fcad23
#endif
Packit fcad23
    {0},
Packit fcad23
};
Packit fcad23
Packit fcad23
static int      sd = -2;        /* /dev/arp stream descriptor. */
Packit fcad23
Packit fcad23
/*-
Packit fcad23
 * Static function prototypes (use void as argument type if there are none)
Packit fcad23
 */
Packit fcad23
Packit fcad23
static found_e
Packit fcad23
getentry(req_e req_type, void *bufaddr, size_t len, size_t entrysize,
Packit fcad23
         void *resp, int (*comp)(void *, void *), void *arg);
Packit fcad23
Packit fcad23
static int
Packit fcad23
getmib(int groupname, int subgroupname, void **statbuf, size_t *size,
Packit fcad23
       size_t entrysize, req_e req_type, void *resp, size_t *length,
Packit fcad23
       int (*comp)(void *, void *), void *arg);
Packit fcad23
Packit fcad23
static int
Packit fcad23
getif(mib2_ifEntry_t *ifbuf, size_t size, req_e req_type, mib2_ifEntry_t *resp,
Packit fcad23
      size_t *length, int (*comp)(void *, void *), void *arg);
Packit fcad23
static void 
Packit fcad23
set_if_info(mib2_ifEntry_t *ifp, unsigned index, char *name, uint64_t flags,
Packit fcad23
            int mtu);
Packit fcad23
static int get_if_stats(mib2_ifEntry_t *ifp);
Packit fcad23
Packit fcad23
#if defined(HAVE_IF_NAMEINDEX) && defined(NETSNMP_INCLUDE_IFTABLE_REWRITES)
Packit fcad23
static int _dlpi_open(const char *devname);
Packit fcad23
static int _dlpi_get_phys_address(int fd, char *paddr, int maxlen,
Packit fcad23
                                  int *paddrlen);
Packit fcad23
static int _dlpi_get_iftype(int fd, unsigned int *iftype);
Packit fcad23
static int _dlpi_attach(int fd, int ppa);
Packit fcad23
static int _dlpi_parse_devname(char *devname, int *ppap);
Packit fcad23
#endif
Packit fcad23
Packit fcad23
Packit fcad23
Packit fcad23
static int
Packit fcad23
Name_cmp(void *, void *);
Packit fcad23
Packit fcad23
static void
Packit fcad23
init_mibcache_element(mibcache * cp);
Packit fcad23
Packit fcad23
#define	STREAM_DEV	"/dev/arp"
Packit fcad23
#define	BUFSIZE		40960   /* Buffer for  messages (should be modulo(pagesize) */
Packit fcad23
Packit fcad23
/*-
Packit fcad23
 * Function definitions
Packit fcad23
 */
Packit fcad23
Packit fcad23
#ifdef _STDC_COMPAT
Packit fcad23
#ifdef __cplusplus
Packit fcad23
extern          "C" {
Packit fcad23
#endif
Packit fcad23
#endif
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * I profiled snmpd using Quantify on a Solaris 7 box, and it turned out that
Packit fcad23
 * the calls to time() in getMibstat() were taking 18% of the total execution
Packit fcad23
 * time of snmpd when doing simple walks over the whole tree.  I guess it must
Packit fcad23
 * be difficult for Sun hardware to tell the time or something ;-).  Anyway,
Packit fcad23
 * this seemed like it was negating the point of having the cache, so I have
Packit fcad23
 * changed the code so that it runs a periodic alarm to age the cache entries
Packit fcad23
 * instead.  The meaning of the cache_ttl and cache_time members has changed to
Packit fcad23
 * support this.  cache_ttl is now the value that cache_time gets reset to when
Packit fcad23
 * we fetch a value from the kernel; cache_time then ticks down to zero in
Packit fcad23
 * steps of period (see below).  When it reaches zero, the cache entry is no
Packit fcad23
 * longer valid and we fetch a new one.  The effect of this is the same as the
Packit fcad23
 * previous code, but more efficient (because it's not calling time() for every
Packit fcad23
 * variable fetched) when you are walking the tables.  jbpn, 20020226.
Packit fcad23
 */
Packit fcad23
Packit fcad23
static void
Packit fcad23
kernel_sunos5_cache_age(unsigned int regnumber, void *data)
Packit fcad23
{
Packit fcad23
    int i = 0, period = (int)data;
Packit fcad23
Packit fcad23
    for (i = 0; i < MIBCACHE_SIZE; i++) {
Packit fcad23
	DEBUGMSGTL(("kernel_sunos5", "cache[%d] time %ld ttl %d\n", i,
Packit fcad23
		    Mibcache[i].cache_time, (int)Mibcache[i].cache_ttl));
Packit fcad23
	if (Mibcache[i].cache_time < period) {
Packit fcad23
	    Mibcache[i].cache_time = 0;
Packit fcad23
	} else {
Packit fcad23
	    Mibcache[i].cache_time -= period;
Packit fcad23
	}
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
void
Packit fcad23
init_kernel_sunos5(void)
Packit fcad23
{
Packit fcad23
    static int creg   = 0;
Packit fcad23
    const  int period = 3;
Packit fcad23
    int    alarm_id   = 0;
Packit fcad23
Packit fcad23
    if (creg == 0) {
Packit fcad23
	alarm_id = snmp_alarm_register(period, SA_REPEAT, 
Packit fcad23
                                       kernel_sunos5_cache_age,
Packit fcad23
                                       (void *)period);
Packit fcad23
	DEBUGMSGTL(("kernel_sunos5", "registered alarm %d with period %ds\n", 
Packit fcad23
		    alarm_id, period));
Packit fcad23
        ++creg;
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * Get various kernel statistics using undocumented Solaris kstat interface.
Packit fcad23
 * We need it mainly for getting network interface statistics, although it is
Packit fcad23
 * generic enough to be used for any purpose.  It knows about kstat_headers
Packit fcad23
 * module names and by the name of the statistics it tries to figure out the
Packit fcad23
 * rest of necessary information.  Returns 0 in case of success and < 0 if
Packit fcad23
 * there were any errors.
Packit fcad23
 
Packit fcad23
 * 
Packit fcad23
 * NOTE: To use this function correctly you have to know the actual type of the
Packit fcad23
 * value to be returned, so you may build the test program, figure out the type
Packit fcad23
 * and use it. Exposing kstat data types to upper layers doesn't seem to be
Packit fcad23
 * reasonable. In any case I'd expect more reasonable kstat interface. :-(
Packit fcad23
 */
Packit fcad23
Packit fcad23
Packit fcad23
int
Packit fcad23
getKstatInt(const char *classname, const char *statname, 
Packit fcad23
	    const char *varname, int *value)
Packit fcad23
{
Packit fcad23
    kstat_ctl_t    *ksc;
Packit fcad23
    kstat_t        *ks;
Packit fcad23
    kid_t           kid;
Packit fcad23
    kstat_named_t  *named;
Packit fcad23
    int             ret = -1;        /* fail unless ... */
Packit fcad23
Packit fcad23
    if (kstat_fd == 0) {
Packit fcad23
	kstat_fd = kstat_open();
Packit fcad23
	if (kstat_fd == 0) {
Packit fcad23
	    snmp_log_perror("kstat_open");
Packit fcad23
	}
Packit fcad23
    }
Packit fcad23
    if ((ksc = kstat_fd) == NULL) {
Packit fcad23
	goto Return;
Packit fcad23
    }
Packit fcad23
    ks = kstat_lookup(ksc, classname, -1, statname);
Packit fcad23
    if (ks == NULL) {
Packit fcad23
	DEBUGMSGTL(("kernel_sunos5", "class %s, stat %s not found\n",
Packit fcad23
		classname ? classname : "NULL",
Packit fcad23
		statname ? statname : "NULL"));
Packit fcad23
	goto Return;
Packit fcad23
    }
Packit fcad23
    kid = kstat_read(ksc, ks, NULL);
Packit fcad23
    if (kid == -1) {
Packit fcad23
	DEBUGMSGTL(("kernel_sunos5", "cannot read class %s stats %s\n",
Packit fcad23
		classname ? classname : "NULL", statname ? statname : "NULL"));
Packit fcad23
	goto Return;
Packit fcad23
    }
Packit fcad23
    named = kstat_data_lookup(ks, varname);
Packit fcad23
    if (named == NULL) {
Packit fcad23
	DEBUGMSGTL(("kernel_sunos5", "no var %s for class %s stat %s\n",
Packit fcad23
		varname, classname ? classname : "NULL",
Packit fcad23
		statname ? statname : "NULL"));
Packit fcad23
	goto Return;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    ret = 0;                /* maybe successful */
Packit fcad23
    switch (named->data_type) {
Packit fcad23
#ifdef KSTAT_DATA_INT32         /* Solaris 2.6 and up */
Packit fcad23
    case KSTAT_DATA_INT32:
Packit fcad23
	*value = named->value.i32;
Packit fcad23
	break;
Packit fcad23
    case KSTAT_DATA_UINT32:
Packit fcad23
	*value = named->value.ui32;
Packit fcad23
	break;
Packit fcad23
    case KSTAT_DATA_INT64:
Packit fcad23
	*value = named->value.i64;
Packit fcad23
	break;
Packit fcad23
    case KSTAT_DATA_UINT64:
Packit fcad23
	*value = named->value.ui64;
Packit fcad23
	break;
Packit fcad23
#else
Packit fcad23
    case KSTAT_DATA_LONG:
Packit fcad23
	*value = named->value.l;
Packit fcad23
	break;
Packit fcad23
    case KSTAT_DATA_ULONG:
Packit fcad23
	*value = named->value.ul;
Packit fcad23
	break;
Packit fcad23
    case KSTAT_DATA_LONGLONG:
Packit fcad23
	*value = named->value.ll;
Packit fcad23
	break;
Packit fcad23
    case KSTAT_DATA_ULONGLONG:
Packit fcad23
	*value = named->value.ull;
Packit fcad23
	break;
Packit fcad23
#endif
Packit fcad23
    default:
Packit fcad23
	snmp_log(LOG_ERR,
Packit fcad23
		"non-int type in kstat data: \"%s\" \"%s\" \"%s\" %d\n",
Packit fcad23
		classname ? classname : "NULL",
Packit fcad23
		statname ? statname : "NULL",
Packit fcad23
		varname ? varname : "NULL", named->data_type);
Packit fcad23
	ret = -1;            /* fail */
Packit fcad23
	break;
Packit fcad23
    }
Packit fcad23
 Return:
Packit fcad23
    return ret;
Packit fcad23
}
Packit fcad23
Packit fcad23
int
Packit fcad23
getKstat(const char *statname, const char *varname, void *value)
Packit fcad23
{
Packit fcad23
    kstat_ctl_t    *ksc;
Packit fcad23
    kstat_t        *ks, *kstat_data;
Packit fcad23
    kstat_named_t  *d;
Packit fcad23
    uint_t          i;
Packit fcad23
    int             instance = 0;
Packit fcad23
    char            module_name[64];
Packit fcad23
    int             ret;
Packit fcad23
    u_longlong_t    val;    /* The largest value */
Packit fcad23
    void           *v;
Packit fcad23
    static char    buf[128];
Packit fcad23
Packit fcad23
    if (value == NULL) {      /* Pretty useless but ... */
Packit fcad23
	v = (void *) &val;
Packit fcad23
    } else {
Packit fcad23
	v = value;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (kstat_fd == 0) {
Packit fcad23
	kstat_fd = kstat_open();
Packit fcad23
	if (kstat_fd == 0) {
Packit fcad23
	    snmp_log_perror("kstat_open");
Packit fcad23
	}
Packit fcad23
    }
Packit fcad23
    if ((ksc = kstat_fd) == NULL) {
Packit fcad23
	ret = -10;
Packit fcad23
	goto Return;        /* kstat errors */
Packit fcad23
    }
Packit fcad23
    if (statname == NULL || varname == NULL) {
Packit fcad23
	ret = -20;
Packit fcad23
	goto Return;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * First, get "kstat_headers" statistics. It should
Packit fcad23
     * contain all available modules. 
Packit fcad23
     */
Packit fcad23
Packit fcad23
    if ((ks = kstat_lookup(ksc, "unix", 0, "kstat_headers")) == NULL) {
Packit fcad23
	ret = -10;
Packit fcad23
	goto Return;        /* kstat errors */
Packit fcad23
    }
Packit fcad23
    if (kstat_read(ksc, ks, NULL) <= 0) {
Packit fcad23
	ret = -10;
Packit fcad23
	goto Return;        /* kstat errors */
Packit fcad23
    }
Packit fcad23
    kstat_data = ks->ks_data;
Packit fcad23
    
Packit fcad23
    /*
Packit fcad23
     * Now, look for the name of our stat in the headers buf 
Packit fcad23
     */
Packit fcad23
    for (i = 0; i < ks->ks_ndata; i++) {
Packit fcad23
	DEBUGMSGTL(("kernel_sunos5",
Packit fcad23
		    "module: %s instance: %d name: %s class: %s type: %d flags: %x\n",
Packit fcad23
		    kstat_data[i].ks_module, kstat_data[i].ks_instance,
Packit fcad23
		    kstat_data[i].ks_name, kstat_data[i].ks_class,
Packit fcad23
		    kstat_data[i].ks_type, kstat_data[i].ks_flags));
Packit fcad23
	if (strcmp(statname, kstat_data[i].ks_name) == 0) {
Packit fcad23
	    strcpy(module_name, kstat_data[i].ks_module);
Packit fcad23
	    instance = kstat_data[i].ks_instance;
Packit fcad23
	    break;
Packit fcad23
	}
Packit fcad23
    }
Packit fcad23
    
Packit fcad23
    if (i == ks->ks_ndata) {
Packit fcad23
	ret = -1;
Packit fcad23
	goto Return;        /* Not found */
Packit fcad23
    }
Packit fcad23
    
Packit fcad23
    /*
Packit fcad23
     * Get the named statistics 
Packit fcad23
     */
Packit fcad23
    if ((ks = kstat_lookup(ksc, module_name, instance, statname)) == NULL) {
Packit fcad23
	ret = -10;
Packit fcad23
	goto Return;        /* kstat errors */
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (kstat_read(ksc, ks, NULL) <= 0) {
Packit fcad23
	ret = -10;
Packit fcad23
	goto Return;        /* kstat errors */
Packit fcad23
    }
Packit fcad23
    /*
Packit fcad23
     * This function expects only name/value type of statistics, so if it is
Packit fcad23
     * not the case return an error
Packit fcad23
     */
Packit fcad23
    if (ks->ks_type != KSTAT_TYPE_NAMED) {
Packit fcad23
	ret = -2;
Packit fcad23
	goto Return;        /* Invalid stat type */
Packit fcad23
    }
Packit fcad23
    
Packit fcad23
    for (i = 0, d = KSTAT_NAMED_PTR(ks); i < ks->ks_ndata; i++, d++) {
Packit fcad23
	DEBUGMSGTL(("kernel_sunos5", "variable: \"%s\" (type %d)\n", 
Packit fcad23
		    d->name, d->data_type));
Packit fcad23
Packit fcad23
	if (strcmp(d->name, varname) == 0) {
Packit fcad23
	    switch (d->data_type) {
Packit fcad23
	    case KSTAT_DATA_CHAR:
Packit fcad23
		DEBUGMSGTL(("kernel_sunos5", "value: %s\n", d->value.c));
Packit fcad23
		*(char **)v = buf;
Packit fcad23
		strlcpy(buf, d->value.c, sizeof(buf));
Packit fcad23
		break;
Packit fcad23
#ifdef KSTAT_DATA_INT32         /* Solaris 2.6 and up */
Packit fcad23
	    case KSTAT_DATA_INT32:
Packit fcad23
		*(Counter *)v = d->value.i32;
Packit fcad23
		DEBUGMSGTL(("kernel_sunos5", "value: %d\n", d->value.i32));
Packit fcad23
		break;
Packit fcad23
	    case KSTAT_DATA_UINT32:
Packit fcad23
		*(Counter *)v = d->value.ui32;
Packit fcad23
		DEBUGMSGTL(("kernel_sunos5", "value: %u\n", d->value.ui32));
Packit fcad23
		break;
Packit fcad23
	    case KSTAT_DATA_INT64:
Packit fcad23
		*(int64_t *)v = d->value.i64;
Packit fcad23
		DEBUGMSGTL(("kernel_sunos5", "value: %ld\n", (long)d->value.i64));
Packit fcad23
		break;
Packit fcad23
	    case KSTAT_DATA_UINT64:
Packit fcad23
		*(uint64_t *)v = d->value.ui64;
Packit fcad23
		DEBUGMSGTL(("kernel_sunos5", "value: %lu\n", (unsigned long)d->value.ui64));
Packit fcad23
		break;
Packit fcad23
#else
Packit fcad23
	    case KSTAT_DATA_LONG:
Packit fcad23
		*(Counter *)v = d->value.l;
Packit fcad23
		DEBUGMSGTL(("kernel_sunos5", "value: %ld\n", d->value.l));
Packit fcad23
		break;
Packit fcad23
	    case KSTAT_DATA_ULONG:
Packit fcad23
		*(Counter *)v = d->value.ul;
Packit fcad23
		DEBUGMSGTL(("kernel_sunos5", "value: %lu\n", d->value.ul));
Packit fcad23
		break;
Packit fcad23
	    case KSTAT_DATA_LONGLONG:
Packit fcad23
		*(Counter *)v = d->value.ll;
Packit fcad23
		DEBUGMSGTL(("kernel_sunos5", "value: %lld\n",
Packit fcad23
			    (long)d->value.ll));
Packit fcad23
		break;
Packit fcad23
	    case KSTAT_DATA_ULONGLONG:
Packit fcad23
		*(Counter *)v = d->value.ull;
Packit fcad23
		DEBUGMSGTL(("kernel_sunos5", "value: %llu\n",
Packit fcad23
			    (unsigned long)d->value.ull));
Packit fcad23
		break;
Packit fcad23
#endif
Packit fcad23
	    case KSTAT_DATA_FLOAT:
Packit fcad23
		*(float *)v = d->value.f;
Packit fcad23
		DEBUGMSGTL(("kernel_sunos5", "value: %f\n", d->value.f));
Packit fcad23
		break;
Packit fcad23
	    case KSTAT_DATA_DOUBLE:
Packit fcad23
		*(double *)v = d->value.d;
Packit fcad23
		DEBUGMSGTL(("kernel_sunos5", "value: %f\n", d->value.d));
Packit fcad23
		break;
Packit fcad23
	    default:
Packit fcad23
		DEBUGMSGTL(("kernel_sunos5",
Packit fcad23
			    "UNKNOWN TYPE %d (stat \"%s\" var \"%s\")\n",
Packit fcad23
			    d->data_type, statname, varname));
Packit fcad23
		ret = -3;
Packit fcad23
		goto Return;        /* Invalid data type */
Packit fcad23
	    }
Packit fcad23
	    ret = 0;        /* Success  */
Packit fcad23
	    goto Return;
Packit fcad23
	}
Packit fcad23
    }
Packit fcad23
    ret = -4;               /* Name not found */
Packit fcad23
 Return:
Packit fcad23
    return ret;
Packit fcad23
}
Packit fcad23
Packit fcad23
int
Packit fcad23
getKstatString(const char *statname, const char *varname,
Packit fcad23
               char *value, size_t value_len)
Packit fcad23
{
Packit fcad23
    kstat_ctl_t    *ksc;
Packit fcad23
    kstat_t        *ks, *kstat_data;
Packit fcad23
    kstat_named_t  *d;
Packit fcad23
    size_t          i, instance = 0;
Packit fcad23
    char            module_name[64];
Packit fcad23
    int             ret;
Packit fcad23
Packit fcad23
    if (kstat_fd == 0) {
Packit fcad23
        kstat_fd = kstat_open();
Packit fcad23
        if (kstat_fd == 0) {
Packit fcad23
            snmp_log_perror("kstat_open");
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
    if ((ksc = kstat_fd) == NULL) {
Packit fcad23
        ret = -10;
Packit fcad23
        goto Return;        /* kstat errors */
Packit fcad23
    }
Packit fcad23
    if (statname == NULL || varname == NULL) {
Packit fcad23
        ret = -20;
Packit fcad23
        goto Return;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * First, get "kstat_headers" statistics. It should
Packit fcad23
     * contain all available modules.
Packit fcad23
     */
Packit fcad23
Packit fcad23
    if ((ks = kstat_lookup(ksc, "unix", 0, "kstat_headers")) == NULL) {
Packit fcad23
        ret = -10;
Packit fcad23
        goto Return;        /* kstat errors */
Packit fcad23
    }
Packit fcad23
    if (kstat_read(ksc, ks, NULL) <= 0) {
Packit fcad23
        ret = -10;
Packit fcad23
        goto Return;        /* kstat errors */
Packit fcad23
    }
Packit fcad23
    kstat_data = ks->ks_data;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * Now, look for the name of our stat in the headers buf
Packit fcad23
     */
Packit fcad23
    for (i = 0; i < ks->ks_ndata; i++) {
Packit fcad23
        DEBUGMSGTL(("kernel_sunos5",
Packit fcad23
                    "module: %s instance: %d name: %s class: %s type: %d flags: %x\n",
Packit fcad23
                    kstat_data[i].ks_module, kstat_data[i].ks_instance,
Packit fcad23
                    kstat_data[i].ks_name, kstat_data[i].ks_class,
Packit fcad23
                    kstat_data[i].ks_type, kstat_data[i].ks_flags));
Packit fcad23
        if (strcmp(statname, kstat_data[i].ks_name) == 0) {
Packit fcad23
            strcpy(module_name, kstat_data[i].ks_module);
Packit fcad23
            instance = kstat_data[i].ks_instance;
Packit fcad23
            break;
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (i == ks->ks_ndata) {
Packit fcad23
        ret = -1;
Packit fcad23
        goto Return;        /* Not found */
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * Get the named statistics
Packit fcad23
     */
Packit fcad23
    if ((ks = kstat_lookup(ksc, module_name, instance, statname)) == NULL) {
Packit fcad23
        ret = -10;
Packit fcad23
        goto Return;        /* kstat errors */
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (kstat_read(ksc, ks, NULL) <= 0) {
Packit fcad23
        ret = -10;
Packit fcad23
        goto Return;        /* kstat errors */
Packit fcad23
    }
Packit fcad23
    /*
Packit fcad23
     * This function expects only name/value type of statistics, so if it is
Packit fcad23
     * not the case return an error
Packit fcad23
     */
Packit fcad23
    if (ks->ks_type != KSTAT_TYPE_NAMED) {
Packit fcad23
        ret = -2;
Packit fcad23
        goto Return;        /* Invalid stat type */
Packit fcad23
    }
Packit fcad23
Packit fcad23
    for (i = 0, d = KSTAT_NAMED_PTR(ks); i < ks->ks_ndata; i++, d++) {
Packit fcad23
        DEBUGMSGTL(("kernel_sunos5", "variable: \"%s\" (type %d)\n",
Packit fcad23
                    d->name, d->data_type));
Packit fcad23
Packit fcad23
        if (strcmp(d->name, varname) == 0) {
Packit fcad23
            switch (d->data_type) {
Packit fcad23
            case KSTAT_DATA_CHAR:
Packit fcad23
                strlcpy(value, d->value.c, value_len);
Packit fcad23
                DEBUGMSGTL(("kernel_sunos5", "value: %s\n", d->value.c));
Packit fcad23
                break;
Packit fcad23
            default:
Packit fcad23
                DEBUGMSGTL(("kernel_sunos5",
Packit fcad23
                            "NONSTRING TYPE %d (stat \"%s\" var \"%s\")\n",
Packit fcad23
                            d->data_type, statname, varname));
Packit fcad23
                ret = -3;
Packit fcad23
                goto Return;        /* Invalid data type */
Packit fcad23
            }
Packit fcad23
            ret = 0;        /* Success  */
Packit fcad23
            goto Return;
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
    ret = -4;               /* Name not found */
Packit fcad23
 Return:
Packit fcad23
    return ret;
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * get MIB-II statistics. It maintaines a simple cache which buffers the last
Packit fcad23
 * read block of MIB statistics (which may contain the whole table). It calls
Packit fcad23
 * *comp to compare every entry with an entry pointed by arg. *comp should
Packit fcad23
 * return 0 if comparison is successful.  Req_type may be GET_FIRST, GET_EXACT,
Packit fcad23
 * GET_NEXT.  If search is successful getMibstat returns 0, otherwise 1.
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
getMibstat(mibgroup_e grid, void *resp, size_t entrysize,
Packit fcad23
	   req_e req_type, int (*comp) (void *, void *), void *arg)
Packit fcad23
{
Packit fcad23
    int             ret, rc = -1, mibgr, mibtb, cache_valid;
Packit fcad23
    size_t          length;
Packit fcad23
    mibcache       *cachep;
Packit fcad23
    found_e         result = NOT_FOUND;
Packit fcad23
    void           *ep;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * We assume that Mibcache is initialized in mibgroup_e enum order so we
Packit fcad23
     * don't check the validity of index here.
Packit fcad23
     */
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("kernel_sunos5", "getMibstat (%d, *, %d, %d, *, *)\n",
Packit fcad23
		grid, (int)entrysize, req_type));
Packit fcad23
    cachep = &Mibcache[grid];
Packit fcad23
    mibgr = Mibmap[grid].group;
Packit fcad23
    mibtb = Mibmap[grid].table;
Packit fcad23
Packit fcad23
    if (cachep->cache_addr == (void *) -1)  /* Hasn't been initialized yet */
Packit fcad23
	init_mibcache_element(cachep);
Packit fcad23
    if (cachep->cache_size == 0) {  /* Memory allocation problems */
Packit fcad23
	cachep->cache_addr = resp;  /* So use caller supplied address instead of cache */
Packit fcad23
	cachep->cache_size = entrysize;
Packit fcad23
	cachep->cache_last_found = 0;
Packit fcad23
    }
Packit fcad23
    if (req_type != GET_NEXT)
Packit fcad23
	cachep->cache_last_found = 0;
Packit fcad23
Packit fcad23
    cache_valid = (cachep->cache_time > 0);
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("kernel_sunos5","... cache_valid %d time %ld ttl %d now %ld\n",
Packit fcad23
		cache_valid, cachep->cache_time, (int)cachep->cache_ttl,
Packit fcad23
		time(NULL)));
Packit fcad23
    if (cache_valid) {
Packit fcad23
	/*
Packit fcad23
	 * Is it really? 
Packit fcad23
	 */
Packit fcad23
	if (cachep->cache_comp != (void *)comp || cachep->cache_arg != arg) {
Packit fcad23
	    cache_valid = 0;        /* Nope. */
Packit fcad23
	}
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (cache_valid) {
Packit fcad23
	/*
Packit fcad23
	 * Entry is valid, let's try to find a match 
Packit fcad23
	 */
Packit fcad23
Packit fcad23
	if (req_type == GET_NEXT) {
Packit fcad23
	    result = getentry(req_type,
Packit fcad23
			      (void *)((char *)cachep->cache_addr +
Packit fcad23
				       (cachep->cache_last_found * entrysize)),
Packit fcad23
			      cachep->cache_length -
Packit fcad23
			      (cachep->cache_last_found * entrysize),
Packit fcad23
			      entrysize, &ep, comp, arg);
Packit fcad23
            } else {
Packit fcad23
                result = getentry(req_type, cachep->cache_addr,
Packit fcad23
				  cachep->cache_length, entrysize, &ep, comp,
Packit fcad23
				  arg);
Packit fcad23
            }
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if ((cache_valid == 0) || (result == NOT_FOUND) ||
Packit fcad23
	(result == NEED_NEXT && cachep->cache_flags & CACHE_MOREDATA)) {
Packit fcad23
	/*
Packit fcad23
	 * Either the cache is old, or we haven't found anything, or need the
Packit fcad23
	 * next item which hasn't been read yet.  In any case, fill the cache
Packit fcad23
	 * up and try to find our entry.
Packit fcad23
	 */
Packit fcad23
Packit fcad23
	if (grid == MIB_INTERFACES) {
Packit fcad23
	    rc = getif((mib2_ifEntry_t *) cachep->cache_addr,
Packit fcad23
		       cachep->cache_size, req_type,
Packit fcad23
		       (mib2_ifEntry_t *) & ep, &length, comp, arg);
Packit fcad23
	} else {
Packit fcad23
	    rc = getmib(mibgr, mibtb, &(cachep->cache_addr),
Packit fcad23
			&(cachep->cache_size), entrysize, req_type, &ep,
Packit fcad23
			&length, comp, arg);
Packit fcad23
	}
Packit fcad23
Packit fcad23
	if (rc >= 0) {      /* Cache has been filled up */
Packit fcad23
	    cachep->cache_time = cachep->cache_ttl;
Packit fcad23
	    cachep->cache_length = length;
Packit fcad23
	    if (rc == 1)    /* Found but there are more unread data */
Packit fcad23
		cachep->cache_flags |= CACHE_MOREDATA;
Packit fcad23
	    else {
Packit fcad23
		cachep->cache_flags &= ~CACHE_MOREDATA;
Packit fcad23
                if (rc > 1)  {
Packit fcad23
                    cachep->cache_time = 0;
Packit fcad23
                    }
Packit fcad23
                 }
Packit fcad23
	    cachep->cache_comp = (void *) comp;
Packit fcad23
	    cachep->cache_arg = arg;
Packit fcad23
	} else {
Packit fcad23
	    cachep->cache_comp = NULL;
Packit fcad23
	    cachep->cache_arg = NULL;
Packit fcad23
	}
Packit fcad23
    }
Packit fcad23
    DEBUGMSGTL(("kernel_sunos5", "... result %d rc %d\n", result, rc));
Packit fcad23
    
Packit fcad23
    if (result == FOUND || rc == 0 || rc == 1) {
Packit fcad23
	/*
Packit fcad23
	 * Entry has been found, deliver it 
Packit fcad23
	 */
Packit fcad23
	if (resp != NULL) {
Packit fcad23
	    memcpy(resp, ep, entrysize);
Packit fcad23
	}
Packit fcad23
	ret = 0;
Packit fcad23
	cachep->cache_last_found =
Packit fcad23
	    ((char *)ep - (char *)cachep->cache_addr) / entrysize;
Packit fcad23
    } else {
Packit fcad23
	ret = 1;            /* Not found */
Packit fcad23
    }
Packit fcad23
    DEBUGMSGTL(("kernel_sunos5", "... getMibstat returns %d\n", ret));
Packit fcad23
    return ret;
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * Get a MIB-II entry from the buffer buffaddr, which satisfies the criterion,
Packit fcad23
 * computed by (*comp), which gets arg as the first argument and pointer to the
Packit fcad23
 * current position in the buffer as the second. If found entry is pointed by
Packit fcad23
 * resp.
Packit fcad23
 */
Packit fcad23
Packit fcad23
static found_e
Packit fcad23
getentry(req_e req_type, void *bufaddr, size_t len,
Packit fcad23
	 size_t entrysize, void *resp, int (*comp)(void *, void *),
Packit fcad23
	 void *arg)
Packit fcad23
{
Packit fcad23
    void *bp = bufaddr, **rp = resp;
Packit fcad23
    int previous_found = 0;
Packit fcad23
    
Packit fcad23
    if ((len > 0) && (len % entrysize != 0)) {
Packit fcad23
        /* 
Packit fcad23
         * The data in the cache does not make sense, the size must be a 
Packit fcad23
         * multiple of the entry. Could be caused by alignment issues etc. 
Packit fcad23
         */
Packit fcad23
        DEBUGMSGTL(("kernel_sunos5", 
Packit fcad23
            "bad cache length %d - not multiple of entry size %d\n", 
Packit fcad23
            (int)len, (int)entrysize));
Packit fcad23
        return NOT_FOUND;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * Here we have to perform address arithmetic with pointer to void. Ugly...
Packit fcad23
     */
Packit fcad23
Packit fcad23
    for (; len > 0; len -= entrysize, bp = (char *) bp + entrysize) {
Packit fcad23
	if (rp != (void *) NULL) {
Packit fcad23
	    *rp = bp;
Packit fcad23
	}
Packit fcad23
Packit fcad23
	if (req_type == GET_FIRST || (req_type == GET_NEXT && previous_found)){
Packit fcad23
	    return FOUND;
Packit fcad23
	}
Packit fcad23
Packit fcad23
	if ((*comp)(arg, bp) == 0) {
Packit fcad23
	    if (req_type == GET_EXACT) {
Packit fcad23
		return FOUND;
Packit fcad23
	    } else {        /* GET_NEXT */
Packit fcad23
		previous_found++;
Packit fcad23
		continue;
Packit fcad23
	    }
Packit fcad23
	}
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (previous_found) {
Packit fcad23
	return NEED_NEXT;
Packit fcad23
    } else {
Packit fcad23
	return NOT_FOUND;
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * Initialize a cache element. It allocates the memory and sets the time stamp
Packit fcad23
 * to invalidate the element.
Packit fcad23
 */
Packit fcad23
static void
Packit fcad23
init_mibcache_element(mibcache * cp)
Packit fcad23
{
Packit fcad23
    if (cp == (mibcache *)NULL) {
Packit fcad23
	return;
Packit fcad23
    }
Packit fcad23
    if (cp->cache_size) {
Packit fcad23
	cp->cache_addr = malloc(cp->cache_size);
Packit fcad23
    }
Packit fcad23
    cp->cache_time = 0;
Packit fcad23
    cp->cache_comp = NULL;
Packit fcad23
    cp->cache_arg = NULL;
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * Get MIB-II statistics from the Solaris kernel.  It uses undocumented
Packit fcad23
 * interface to TCP/IP streams modules, which provides extended MIB-II for the
Packit fcad23
 * following groups: ip, icmp, tcp, udp, egp.
Packit fcad23
 
Packit fcad23
 * 
Packit fcad23
 * Usage: groupname, subgroupname are from <inet/mib2.h>, 
Packit fcad23
 *        size%sizeof(statbuf) == 0,
Packit fcad23
 *        entrysize should be exact size of MIB-II entry,
Packit fcad23
 *        req_type:
Packit fcad23
 *                   GET_FIRST - get the first entry in the buffer
Packit fcad23
 *                   GET_EXACT - get exact match
Packit fcad23
 *                   GET_NEXT  - get next entry after the exact match
Packit fcad23
 * 
Packit fcad23
 * (*comp) is a compare function, provided by the caller, which gets arg as the
Packit fcad23
 * first argument and pointer to the current entry as th second. If compared,
Packit fcad23
 * should return 0 and found entry will be pointed by resp.
Packit fcad23
 * 
Packit fcad23
 * If search is successful and no more data to read, it returns 0,
Packit fcad23
 * if successful and there is more data -- 1,
Packit fcad23
 * if not found and end of data -- 2, any other errors -- < 0
Packit fcad23
 * (negative error numbers are pretty random).
Packit fcad23
 * 
Packit fcad23
 * NOTE: needs to be protected by a mutex in reentrant environment 
Packit fcad23
 */
Packit fcad23
Packit fcad23
static int
Packit fcad23
getmib(int groupname, int subgroupname, void **statbuf, size_t *size,
Packit fcad23
       size_t entrysize, req_e req_type, void *resp,
Packit fcad23
       size_t *length, int (*comp)(void *, void *), void *arg)
Packit fcad23
{
Packit fcad23
    int             rc, ret = 0, flags;
Packit fcad23
    char            buf[BUFSIZE];
Packit fcad23
    struct strbuf   strbuf;
Packit fcad23
    struct T_optmgmt_req *tor = (struct T_optmgmt_req *) buf;
Packit fcad23
    struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *) buf;
Packit fcad23
    struct T_error_ack *tea = (struct T_error_ack *) buf;
Packit fcad23
    struct opthdr  *req;
Packit fcad23
    found_e         result = FOUND;
Packit fcad23
    size_t oldsize;
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("kernel_sunos5", "...... getmib (%d, %d, ...)\n",
Packit fcad23
		groupname, subgroupname));
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * Open the stream driver and push all MIB-related modules 
Packit fcad23
     */
Packit fcad23
Packit fcad23
    if (sd == -2) {         /* First time */
Packit fcad23
	if ((sd = open(STREAM_DEV, O_RDWR)) == -1) {
Packit fcad23
	    snmp_log_perror(STREAM_DEV);
Packit fcad23
	    ret = -1;
Packit fcad23
	    goto Return;
Packit fcad23
	}
Packit fcad23
	if (ioctl(sd, I_PUSH, "tcp") == -1) {
Packit fcad23
	    snmp_log_perror("I_PUSH tcp");
Packit fcad23
	    ret = -1;
Packit fcad23
	    goto Return;
Packit fcad23
	}
Packit fcad23
	if (ioctl(sd, I_PUSH, "udp") == -1) {
Packit fcad23
	    snmp_log_perror("I_PUSH udp");
Packit fcad23
	    ret = -1;
Packit fcad23
	    goto Return;
Packit fcad23
	}
Packit fcad23
	DEBUGMSGTL(("kernel_sunos5", "...... modules pushed OK\n"));
Packit fcad23
    }
Packit fcad23
    if (sd == -1) {
Packit fcad23
	ret = -1;
Packit fcad23
	goto Return;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * First, use bigger buffer, to accelerate skipping unwanted messages
Packit fcad23
     */
Packit fcad23
Packit fcad23
    strbuf.buf = buf;
Packit fcad23
    strbuf.maxlen = BUFSIZE;
Packit fcad23
    
Packit fcad23
    tor->PRIM_type = T_OPTMGMT_REQ;
Packit fcad23
    tor->OPT_offset = sizeof(struct T_optmgmt_req);
Packit fcad23
    tor->OPT_length = sizeof(struct opthdr);
Packit fcad23
#ifdef MI_T_CURRENT
Packit fcad23
    tor->MGMT_flags = MI_T_CURRENT; /* Solaris < 2.6 */
Packit fcad23
#else
Packit fcad23
    tor->MGMT_flags = T_CURRENT;    /* Solaris 2.6 */
Packit fcad23
#endif
Packit fcad23
    req = (struct opthdr *)(tor + 1);
Packit fcad23
    req->level = groupname;
Packit fcad23
    req->name = subgroupname;
Packit fcad23
    /*
Packit fcad23
     * non-zero len field is used to request extended MIB statistics
Packit fcad23
     * on Solaris 10 Update 4 and later. The LEGACY_MIB_SIZE macro is only
Packit fcad23
     * available for S10U4+, so we use that to see what action to take.
Packit fcad23
     */
Packit fcad23
#ifdef LEGACY_MIB_SIZE
Packit fcad23
    req->len = 1;	/* ask for extended MIBs */
Packit fcad23
#else
Packit fcad23
    req->len = 0;
Packit fcad23
#endif
Packit fcad23
    strbuf.len = tor->OPT_length + tor->OPT_offset;
Packit fcad23
    flags = 0;
Packit fcad23
    if ((rc = putmsg(sd, &strbuf, NULL, flags))) {
Packit fcad23
	ret = -2;
Packit fcad23
	goto Return;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    req = (struct opthdr *) (toa + 1);
Packit fcad23
    for (;;) {
Packit fcad23
	flags = 0;
Packit fcad23
	if ((rc = getmsg(sd, &strbuf, NULL, &flags)) == -1) {
Packit fcad23
	    ret = -EIO;
Packit fcad23
	    break;
Packit fcad23
	}
Packit fcad23
	if (rc == 0 && strbuf.len >= sizeof(struct T_optmgmt_ack) &&
Packit fcad23
	    toa->PRIM_type  == T_OPTMGMT_ACK &&
Packit fcad23
	    toa->MGMT_flags == T_SUCCESS && req->len == 0) {
Packit fcad23
	    ret = 2;
Packit fcad23
	    break;
Packit fcad23
	}
Packit fcad23
	if (strbuf.len >= sizeof(struct T_error_ack) &&
Packit fcad23
	    tea->PRIM_type == T_ERROR_ACK) {
Packit fcad23
	    /* Protocol error */
Packit fcad23
	    ret = -((tea->TLI_error == TSYSERR) ? tea->UNIX_error : EPROTO);
Packit fcad23
	    break;
Packit fcad23
	}
Packit fcad23
	if (rc != MOREDATA || strbuf.len < sizeof(struct T_optmgmt_ack) ||
Packit fcad23
	    toa->PRIM_type != T_OPTMGMT_ACK ||
Packit fcad23
	    toa->MGMT_flags != T_SUCCESS) {
Packit fcad23
	    ret = -ENOMSG;  /* No more messages */
Packit fcad23
	    break;
Packit fcad23
	}
Packit fcad23
Packit fcad23
	/*
Packit fcad23
	 * The order in which we get the statistics is determined by the kernel
Packit fcad23
	 * and not by the group name, so we have to loop until we get the
Packit fcad23
	 * required statistics.
Packit fcad23
	 */
Packit fcad23
Packit fcad23
	if (req->level != groupname || req->name != subgroupname) {
Packit fcad23
	    strbuf.maxlen = BUFSIZE;
Packit fcad23
	    strbuf.buf = buf;
Packit fcad23
	    do {
Packit fcad23
		rc = getmsg(sd, NULL, &strbuf, &flags);
Packit fcad23
	    } while (rc == MOREDATA);
Packit fcad23
	    continue;
Packit fcad23
	}
Packit fcad23
        
Packit fcad23
	/*
Packit fcad23
	 * Now when we found our stat, switch buffer to a caller-provided
Packit fcad23
	 * one. Manipulating the size of it one can control performance,
Packit fcad23
	 * reducing the number of getmsg calls
Packit fcad23
	 */
Packit fcad23
Packit fcad23
	strbuf.buf = *statbuf;
Packit fcad23
	strbuf.maxlen = *size;
Packit fcad23
	strbuf.len = 0;
Packit fcad23
	flags = 0;
Packit fcad23
	do {
Packit fcad23
	    rc = getmsg(sd, NULL, &strbuf, &flags);
Packit fcad23
	    switch (rc) {
Packit fcad23
	    case -1:
Packit fcad23
		ret = -ENOSR;
Packit fcad23
		snmp_perror("getmsg");
Packit fcad23
		goto Return;
Packit fcad23
Packit fcad23
	    default:
Packit fcad23
		snmp_log(LOG_ERR, "kernel_sunos5/getmib: getmsg returned %d\n", rc);
Packit fcad23
		ret = -ENODATA;
Packit fcad23
		goto Return;
Packit fcad23
Packit fcad23
	    case MOREDATA:
Packit fcad23
		DEBUGMSGTL(("kernel_sunos5", "...... getmib increased buffer size\n"));
Packit fcad23
		oldsize = ( strbuf.buf - (char *)*statbuf) + strbuf.len;
Packit fcad23
		strbuf.buf = (char *)realloc(*statbuf, oldsize+4096);
Packit fcad23
		if(strbuf.buf != NULL) {
Packit fcad23
		    *statbuf = strbuf.buf;
Packit fcad23
		    *size = oldsize + 4096;
Packit fcad23
		    strbuf.buf = (char *)*statbuf + oldsize;
Packit fcad23
		    strbuf.maxlen = 4096;
Packit fcad23
		    result = NOT_FOUND;
Packit fcad23
		    break;
Packit fcad23
		}
Packit fcad23
		strbuf.buf = (char *)*statbuf + (oldsize - strbuf.len);
Packit fcad23
	    case 0:
Packit fcad23
		/* fix buffer to real size & position */
Packit fcad23
		strbuf.len += strbuf.buf - (char*)*statbuf;
Packit fcad23
		strbuf.buf = *statbuf;
Packit fcad23
		strbuf.maxlen = *size;
Packit fcad23
Packit fcad23
		if (req_type == GET_NEXT && result == NEED_NEXT)
Packit fcad23
		    /*
Packit fcad23
		     * End of buffer, so "next" is the first item in the next
Packit fcad23
		     * buffer  
Packit fcad23
		     */
Packit fcad23
		    req_type = GET_FIRST;
Packit fcad23
		result = getentry(req_type, (void *) strbuf.buf, strbuf.len,
Packit fcad23
				  entrysize, resp, comp, arg);
Packit fcad23
		*length = strbuf.len;       /* To use in caller for cacheing */
Packit fcad23
		break;
Packit fcad23
	    }
Packit fcad23
	} while (rc == MOREDATA && result != FOUND);
Packit fcad23
Packit fcad23
	DEBUGMSGTL(("kernel_sunos5", "...... getmib buffer size is %d\n", (int)*size));
Packit fcad23
Packit fcad23
	if (result == FOUND) {      /* Search is successful */
Packit fcad23
	    if (rc != MOREDATA) {
Packit fcad23
		ret = 0;    /* Found and no more data */
Packit fcad23
	    } else {
Packit fcad23
		ret = 1;    /* Found and there is another unread data block */
Packit fcad23
	    }
Packit fcad23
	    break;
Packit fcad23
	} else {            /* Restore buffers, continue search */
Packit fcad23
	    strbuf.buf = buf;
Packit fcad23
	    strbuf.maxlen = BUFSIZE;
Packit fcad23
	}
Packit fcad23
    }
Packit fcad23
 Return:
Packit fcad23
    if (sd >= 0) ioctl(sd, I_FLUSH, FLUSHRW);
Packit fcad23
    DEBUGMSGTL(("kernel_sunos5", "...... getmib returns %d\n", ret));
Packit fcad23
    return ret;
Packit fcad23
}
Packit fcad23
  
Packit fcad23
/*
Packit fcad23
 * Get info for interfaces group. Mimics getmib interface as much as possible
Packit fcad23
 * to be substituted later if SunSoft decides to extend its mib2 interface.
Packit fcad23
 */
Packit fcad23
Packit fcad23
#if defined(HAVE_IF_NAMEINDEX) && defined(NETSNMP_INCLUDE_IFTABLE_REWRITES)
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * If IFTABLE_REWRITES is enabled, then we will also rely on DLPI to obtain
Packit fcad23
 * information from the NIC.
Packit fcad23
 */
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * Open a DLPI device.
Packit fcad23
 *
Packit fcad23
 * On success the file descriptor is returned.
Packit fcad23
 * On error -1 is returned.
Packit fcad23
 */
Packit fcad23
static int
Packit fcad23
_dlpi_open(const char *devname)
Packit fcad23
{
Packit fcad23
    char *devstr;
Packit fcad23
    int fd = -1;
Packit fcad23
    int ppa = -1;
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("kernel_sunos5", "_dlpi_open called\n"));
Packit fcad23
Packit fcad23
    if (devname == NULL)
Packit fcad23
        return (-1);
Packit fcad23
Packit fcad23
    if ((devstr = malloc(5 + strlen(devname) + 1)) == NULL)
Packit fcad23
        return (-1);
Packit fcad23
    (void) sprintf(devstr, "/dev/%s", devname);
Packit fcad23
    DEBUGMSGTL(("kernel_sunos5:dlpi", "devstr(%s)\n", devstr));
Packit fcad23
    /*
Packit fcad23
     * First try opening the device using style 1, if the device does not
Packit fcad23
     * exist we try style 2. Modules will not be pushed, so something like
Packit fcad23
     * ip tunnels will not work. 
Packit fcad23
     */
Packit fcad23
   
Packit fcad23
    DEBUGMSGTL(("kernel_sunos5:dlpi", "style1 open(%s)\n", devstr));
Packit fcad23
    if ((fd = open(devstr, O_RDWR | O_NONBLOCK)) < 0) {
Packit fcad23
        DEBUGMSGTL(("kernel_sunos5:dlpi", "style1 open failed\n"));
Packit fcad23
        if (_dlpi_parse_devname(devstr, &ppa) == 0) {
Packit fcad23
            DEBUGMSGTL(("kernel_sunos5:dlpi", "style2 parse: %s, %d\n", 
Packit fcad23
                       devstr, ppa));
Packit fcad23
            /* try style 2 */
Packit fcad23
            DEBUGMSGTL(("kernel_sunos5:dlpi", "style2 open(%s)\n", devstr));
Packit fcad23
Packit fcad23
            if ((fd = open(devstr, O_RDWR | O_NONBLOCK)) != -1) {
Packit fcad23
                if (_dlpi_attach(fd, ppa) == 0) {
Packit fcad23
                    DEBUGMSGTL(("kernel_sunos5:dlpi", "attached\n"));
Packit fcad23
                } else {
Packit fcad23
                    DEBUGMSGTL(("kernel_sunos5:dlpi", "attached failed\n"));
Packit fcad23
                    close(fd);
Packit fcad23
                    fd = -1;
Packit fcad23
                }
Packit fcad23
            } else {
Packit fcad23
                DEBUGMSGTL(("kernel_sunos5:dlpi", "style2 open failed\n"));
Packit fcad23
            }
Packit fcad23
        } 
Packit fcad23
    } else {
Packit fcad23
        DEBUGMSGTL(("kernel_sunos5:dlpi", "style1 open succeeded\n"));
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /* clean up */
Packit fcad23
    free(devstr);
Packit fcad23
Packit fcad23
    return (fd);
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * Obtain the physical address of the interface using DLPI
Packit fcad23
 */
Packit fcad23
static int
Packit fcad23
_dlpi_get_phys_address(int fd, char *addr, int maxlen, int *addrlen)
Packit fcad23
{
Packit fcad23
    dl_phys_addr_req_t  paddr_req;
Packit fcad23
    union DL_primitives *dlp;
Packit fcad23
    struct strbuf       ctlbuf;
Packit fcad23
    char                buf[MAX(DL_PHYS_ADDR_ACK_SIZE+64, DL_ERROR_ACK_SIZE)];
Packit fcad23
    int                 flag = 0;
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("kernel_sunos5:dlpi", "_dlpi_get_phys_address\n"));
Packit fcad23
Packit fcad23
    paddr_req.dl_primitive = DL_PHYS_ADDR_REQ;
Packit fcad23
    paddr_req.dl_addr_type = DL_CURR_PHYS_ADDR;
Packit fcad23
    ctlbuf.buf = (char *)&paddr_req;
Packit fcad23
    ctlbuf.len = DL_PHYS_ADDR_REQ_SIZE;
Packit fcad23
    if (putmsg(fd, &ctlbuf, NULL, 0) < 0)
Packit fcad23
        return (-1);
Packit fcad23
    
Packit fcad23
    ctlbuf.maxlen = sizeof(buf);
Packit fcad23
    ctlbuf.len = 0;
Packit fcad23
    ctlbuf.buf = buf;
Packit fcad23
    if (getmsg(fd, &ctlbuf, NULL, &flag) < 0)
Packit fcad23
        return (-1);
Packit fcad23
Packit fcad23
    if (ctlbuf.len < sizeof(uint32_t))
Packit fcad23
        return (-1);
Packit fcad23
    dlp = (union DL_primitives *)buf;
Packit fcad23
    switch (dlp->dl_primitive) {
Packit fcad23
    case DL_PHYS_ADDR_ACK: {
Packit fcad23
        dl_phys_addr_ack_t *phyp = (dl_phys_addr_ack_t *)buf;
Packit fcad23
Packit fcad23
        DEBUGMSGTL(("kernel_sunos5:dlpi", "got ACK\n"));
Packit fcad23
        if (ctlbuf.len < DL_PHYS_ADDR_ACK_SIZE || phyp->dl_addr_length > maxlen)
Packit fcad23
            return (-1); 
Packit fcad23
        (void) memcpy(addr, buf+phyp->dl_addr_offset, phyp->dl_addr_length);
Packit fcad23
        *addrlen = phyp->dl_addr_length;
Packit fcad23
        return (0);
Packit fcad23
    }
Packit fcad23
    case DL_ERROR_ACK: {
Packit fcad23
        dl_error_ack_t *errp = (dl_error_ack_t *)buf;
Packit fcad23
Packit fcad23
        DEBUGMSGTL(("kernel_sunos5:dlpi", "got ERROR ACK\n"));
Packit fcad23
        if (ctlbuf.len < DL_ERROR_ACK_SIZE)
Packit fcad23
            return (-1);
Packit fcad23
        return (errp->dl_errno);
Packit fcad23
    }
Packit fcad23
    default:
Packit fcad23
        DEBUGMSGTL(("kernel_sunos5:dlpi", "got type: %x\n", (unsigned)dlp->dl_primitive));
Packit fcad23
        return (-1);
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * Query the interface about it's type.
Packit fcad23
 */
Packit fcad23
static int
Packit fcad23
_dlpi_get_iftype(int fd, unsigned int *iftype)
Packit fcad23
{
Packit fcad23
    dl_info_req_t info_req;
Packit fcad23
    union DL_primitives *dlp;
Packit fcad23
    struct strbuf       ctlbuf;
Packit fcad23
    char                buf[MAX(DL_INFO_ACK_SIZE, DL_ERROR_ACK_SIZE)];
Packit fcad23
    int                 flag = 0;
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("kernel_sunos5:dlpi", "_dlpi_get_iftype\n"));
Packit fcad23
Packit fcad23
    info_req.dl_primitive = DL_INFO_REQ;
Packit fcad23
    ctlbuf.buf = (char *)&info_req;
Packit fcad23
    ctlbuf.len = DL_INFO_REQ_SIZE;
Packit fcad23
    if (putmsg(fd, &ctlbuf, NULL, 0) < 0) {
Packit fcad23
        DEBUGMSGTL(("kernel_sunos5:dlpi", "putmsg failed: %d\nn", errno));
Packit fcad23
        return (-1);
Packit fcad23
    }
Packit fcad23
    
Packit fcad23
    ctlbuf.maxlen = sizeof(buf);
Packit fcad23
    ctlbuf.len = 0;
Packit fcad23
    ctlbuf.buf = buf;
Packit fcad23
    if (getmsg(fd, &ctlbuf, NULL, &flag) < 0) {
Packit fcad23
        DEBUGMSGTL(("kernel_sunos5:dlpi", "getmsg failed: %d\n", errno));
Packit fcad23
        return (-1);
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (ctlbuf.len < sizeof(uint32_t))
Packit fcad23
        return (-1);
Packit fcad23
    dlp = (union DL_primitives *)buf;
Packit fcad23
    switch (dlp->dl_primitive) {
Packit fcad23
    case DL_INFO_ACK: {
Packit fcad23
        dl_info_ack_t *info = (dl_info_ack_t *)buf;
Packit fcad23
Packit fcad23
        if (ctlbuf.len < DL_INFO_ACK_SIZE)
Packit fcad23
            return (-1); 
Packit fcad23
Packit fcad23
        DEBUGMSGTL(("kernel_sunos5:dlpi", "dl_mac_type: %x\n",
Packit fcad23
	           (unsigned)info->dl_mac_type));
Packit fcad23
	switch (info->dl_mac_type) {
Packit fcad23
	case DL_CSMACD:
Packit fcad23
	case DL_ETHER:
Packit fcad23
	case DL_ETH_CSMA:
Packit fcad23
		*iftype = 6;
Packit fcad23
		break;
Packit fcad23
	case DL_TPB:	/* Token Passing Bus */
Packit fcad23
		*iftype = 8;
Packit fcad23
		break;
Packit fcad23
	case DL_TPR:	/* Token Passing Ring */
Packit fcad23
		*iftype = 9;
Packit fcad23
		break;
Packit fcad23
	case DL_HDLC:
Packit fcad23
		*iftype = 118;
Packit fcad23
		break;
Packit fcad23
	case DL_FDDI:
Packit fcad23
		*iftype = 15;
Packit fcad23
		break;
Packit fcad23
	case DL_FC:	/* Fibre channel */
Packit fcad23
		*iftype = 56;
Packit fcad23
		break;
Packit fcad23
	case DL_ATM:
Packit fcad23
		*iftype = 37;
Packit fcad23
		break;
Packit fcad23
	case DL_X25:
Packit fcad23
	case DL_ISDN:
Packit fcad23
		*iftype = 63;
Packit fcad23
		break;
Packit fcad23
	case DL_HIPPI:
Packit fcad23
		*iftype = 47;
Packit fcad23
		break;
Packit fcad23
#ifdef DL_IB
Packit fcad23
	case DL_IB:
Packit fcad23
		*iftype = 199;
Packit fcad23
		break;
Packit fcad23
#endif
Packit fcad23
	case DL_FRAME:	/* Frame Relay */
Packit fcad23
		*iftype = 32;
Packit fcad23
		break;
Packit fcad23
	case DL_LOOP:
Packit fcad23
		*iftype = 24;
Packit fcad23
		break;
Packit fcad23
#ifdef DL_WIFI
Packit fcad23
	case DL_WIFI:
Packit fcad23
		*iftype = 71;
Packit fcad23
		break;
Packit fcad23
#endif
Packit fcad23
#ifdef DL_IPV4	/* then IPv6 is also defined */
Packit fcad23
	case DL_IPV4:	/* IPv4 Tunnel */
Packit fcad23
	case DL_IPV6:	/* IPv6 Tunnel */
Packit fcad23
		*iftype = 131;
Packit fcad23
		break;
Packit fcad23
#endif
Packit fcad23
	default:
Packit fcad23
		*iftype = 1;	/* Other */
Packit fcad23
		break;
Packit fcad23
	}
Packit fcad23
	
Packit fcad23
        return (0);
Packit fcad23
    }
Packit fcad23
    case DL_ERROR_ACK: {
Packit fcad23
        dl_error_ack_t *errp = (dl_error_ack_t *)buf;
Packit fcad23
Packit fcad23
        DEBUGMSGTL(("kernel_sunos5:dlpi",
Packit fcad23
                    "got DL_ERROR_ACK: dlpi %ld, error %ld\n",
Packit fcad23
		    (long)errp->dl_errno, (long)errp->dl_unix_errno));
Packit fcad23
Packit fcad23
        if (ctlbuf.len < DL_ERROR_ACK_SIZE)
Packit fcad23
            return (-1);
Packit fcad23
        return (errp->dl_errno);
Packit fcad23
    }
Packit fcad23
    default:
Packit fcad23
        DEBUGMSGTL(("kernel_sunos5:dlpi", "got type %x\n", (unsigned)dlp->dl_primitive));
Packit fcad23
        return (-1);
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
static int
Packit fcad23
_dlpi_attach(int fd, int ppa)
Packit fcad23
{
Packit fcad23
    dl_attach_req_t     attach_req;
Packit fcad23
    struct strbuf       ctlbuf;
Packit fcad23
    union DL_primitives *dlp;
Packit fcad23
    char                buf[MAX(DL_OK_ACK_SIZE, DL_ERROR_ACK_SIZE)];
Packit fcad23
    int                 flag = 0;
Packit fcad23
   
Packit fcad23
    attach_req.dl_primitive = DL_ATTACH_REQ;
Packit fcad23
    attach_req.dl_ppa = ppa;
Packit fcad23
    ctlbuf.buf = (char *)&attach_req;
Packit fcad23
    ctlbuf.len = DL_ATTACH_REQ_SIZE;
Packit fcad23
    if (putmsg(fd, &ctlbuf, NULL, 0) != 0)
Packit fcad23
        return (-1);
Packit fcad23
Packit fcad23
    ctlbuf.buf = buf;
Packit fcad23
    ctlbuf.len = 0;
Packit fcad23
    ctlbuf.maxlen = sizeof(buf);
Packit fcad23
    if (getmsg(fd, &ctlbuf, NULL, &flag) != 0)
Packit fcad23
        return (-1);
Packit fcad23
Packit fcad23
    if (ctlbuf.len < sizeof(uint32_t))
Packit fcad23
        return (-1); 
Packit fcad23
Packit fcad23
    dlp = (union DL_primitives *)buf;
Packit fcad23
    if (dlp->dl_primitive == DL_OK_ACK && ctlbuf.len >= DL_OK_ACK_SIZE)
Packit fcad23
        return (0); 
Packit fcad23
    return (-1);
Packit fcad23
}
Packit fcad23
Packit fcad23
static int
Packit fcad23
_dlpi_parse_devname(char *devname, int *ppap)
Packit fcad23
{
Packit fcad23
    int ppa = 0;
Packit fcad23
    int m = 1;
Packit fcad23
    int i = strlen(devname) - 1;
Packit fcad23
Packit fcad23
    while (i >= 0 && isdigit(devname[i] & 0xFF)) {
Packit fcad23
        ppa += m * (devname[i] - '0'); 
Packit fcad23
        m *= 10;
Packit fcad23
        i--;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (m == 1) {
Packit fcad23
        return (-1);
Packit fcad23
    }
Packit fcad23
    *ppap = ppa;
Packit fcad23
    devname[i + 1] = '\0';
Packit fcad23
Packit fcad23
    return (0);
Packit fcad23
}
Packit fcad23
static int
Packit fcad23
getif(mib2_ifEntry_t *ifbuf, size_t size, req_e req_type,
Packit fcad23
      mib2_ifEntry_t *resp,  size_t *length, int (*comp)(void *, void *),
Packit fcad23
      void *arg)
Packit fcad23
{
Packit fcad23
    int             fd, i, ret;
Packit fcad23
    int             ifsd, ifsd6 = -1;
Packit fcad23
    struct lifreq   lifreq, *lifrp;
Packit fcad23
    mib2_ifEntry_t *ifp;
Packit fcad23
    int             nentries = size / sizeof(mib2_ifEntry_t);
Packit fcad23
    found_e         result = NOT_FOUND;
Packit fcad23
    boolean_t       if_isv6;
Packit fcad23
    uint64_t        if_flags;    
Packit fcad23
    struct if_nameindex *ifname, *ifnp;
Packit fcad23
Packit fcad23
    lifrp = &lifreq; 
Packit fcad23
Packit fcad23
    if ((ifsd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Packit fcad23
        return -1;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("kernel_sunos5", "...... using if_nameindex\n"));
Packit fcad23
    if ((ifname = if_nameindex()) == NULL) {
Packit fcad23
        ret = -1;
Packit fcad23
        goto Return;
Packit fcad23
    }
Packit fcad23
    
Packit fcad23
    /*
Packit fcad23
     * Gather information about each interface found. We try to handle errors
Packit fcad23
     * gracefully: if an error occurs while processing an interface we simply
Packit fcad23
     * move along to the next one. Previously, the function returned with an
Packit fcad23
     * error right away. 
Packit fcad23
     *
Packit fcad23
     * if_nameindex() already eliminates duplicate interfaces, so no extra
Packit fcad23
     * checks are needed for interfaces that have both IPv4 and IPv6 plumbed
Packit fcad23
     */
Packit fcad23
 Again:
Packit fcad23
    for (i = 0, ifnp = ifname, ifp = (mib2_ifEntry_t *) ifbuf; 
Packit fcad23
     ifnp->if_index != 0 && (i < nentries); ifnp++) {
Packit fcad23
Packit fcad23
        DEBUGMSGTL(("kernel_sunos5", "...... getif %s\n", ifnp->if_name));
Packit fcad23
        strlcpy(lifrp->lifr_name, ifnp->if_name, LIFNAMSIZ);
Packit fcad23
        if_isv6 = B_FALSE;
Packit fcad23
Packit fcad23
        if (ioctl(ifsd, SIOCGLIFFLAGS, lifrp) < 0) {
Packit fcad23
            if (ifsd6 == -1) {
Packit fcad23
                if ((ifsd6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
Packit fcad23
                    ret = -1;
Packit fcad23
                    goto Return;
Packit fcad23
                }
Packit fcad23
            }
Packit fcad23
            if (ioctl(ifsd6, SIOCGLIFFLAGS, lifrp) < 0) {
Packit fcad23
                snmp_log(LOG_ERR, "SIOCGLIFFLAGS %s: %s\n", 
Packit fcad23
                         lifrp->lifr_name, strerror(errno));
Packit fcad23
                continue;
Packit fcad23
            }
Packit fcad23
            if_isv6 = B_TRUE;
Packit fcad23
        } 
Packit fcad23
        if_flags = lifrp->lifr_flags;
Packit fcad23
            
Packit fcad23
        if (ioctl(if_isv6?ifsd6:ifsd, SIOCGLIFMTU, lifrp) < 0) {
Packit fcad23
            DEBUGMSGTL(("kernel_sunos5", "...... SIOCGLIFMTU failed\n"));
Packit fcad23
            continue;
Packit fcad23
        }
Packit fcad23
Packit fcad23
        memset(ifp, 0, sizeof(mib2_ifEntry_t));
Packit fcad23
Packit fcad23
        if ((fd = _dlpi_open(ifnp->if_name)) != -1) {
Packit fcad23
            /* Could open DLPI... now try to grab some info */
Packit fcad23
            (void) _dlpi_get_phys_address(fd, ifp->ifPhysAddress.o_bytes,
Packit fcad23
                                sizeof(ifp->ifPhysAddress.o_bytes),
Packit fcad23
                                &ifp->ifPhysAddress.o_length);
Packit fcad23
            (void) _dlpi_get_iftype(fd, &ifp->ifType);
Packit fcad23
            close(fd);
Packit fcad23
        }
Packit fcad23
Packit fcad23
        set_if_info(ifp, ifnp->if_index, ifnp->if_name, if_flags, 
Packit fcad23
                    lifrp->lifr_metric);
Packit fcad23
Packit fcad23
        if (get_if_stats(ifp) < 0) {
Packit fcad23
            DEBUGMSGTL(("kernel_sunos5", "...... get_if_stats failed\n"));
Packit fcad23
            continue;
Packit fcad23
        }
Packit fcad23
Packit fcad23
        /*
Packit fcad23
         * Once we reach here we know that all went well, so move to
Packit fcad23
         * the next ifEntry. 
Packit fcad23
         */
Packit fcad23
        i++;
Packit fcad23
        ifp++;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if ((req_type == GET_NEXT) && (result == NEED_NEXT)) {
Packit fcad23
            /*
Packit fcad23
             * End of buffer, so "next" is the first item in the next buffer 
Packit fcad23
             */
Packit fcad23
        req_type = GET_FIRST;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    result = getentry(req_type, (void *) ifbuf, size, sizeof(mib2_ifEntry_t),
Packit fcad23
              (void *)resp, comp, arg);
Packit fcad23
Packit fcad23
    if ((result != FOUND) && (i == nentries) && ifnp->if_index != 0) { 
Packit fcad23
    /*
Packit fcad23
     * We reached the end of supplied buffer, but there is
Packit fcad23
     * some more stuff to read, so continue.
Packit fcad23
     */
Packit fcad23
        goto Again;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (result != FOUND) {
Packit fcad23
        ret = 2;
Packit fcad23
    } else {
Packit fcad23
        if (ifnp->if_index != 0) {
Packit fcad23
            ret = 1;        /* Found and more data to fetch */
Packit fcad23
        } else {
Packit fcad23
            ret = 0;        /* Found and no more data */
Packit fcad23
        }
Packit fcad23
        *length = i * sizeof(mib2_ifEntry_t);       /* Actual cache length */
Packit fcad23
    }
Packit fcad23
Packit fcad23
 Return:
Packit fcad23
    if (ifname)
Packit fcad23
        if_freenameindex(ifname);
Packit fcad23
    close(ifsd);
Packit fcad23
    if (ifsd6 != -1)
Packit fcad23
        close(ifsd6);
Packit fcad23
    return ret;
Packit fcad23
}
Packit fcad23
#else /* only rely on SIOCGIFCONF to get interface information */ 
Packit fcad23
Packit fcad23
static int
Packit fcad23
getif(mib2_ifEntry_t *ifbuf, size_t size, req_e req_type,
Packit fcad23
      mib2_ifEntry_t *resp,  size_t *length, int (*comp)(void *, void *),
Packit fcad23
      void *arg)
Packit fcad23
{
Packit fcad23
    int             i, ret, idx = 1;
Packit fcad23
    int             ifsd;
Packit fcad23
    static char    *buf = NULL;
Packit fcad23
    static int      bufsize = 0;
Packit fcad23
    struct ifconf   ifconf;
Packit fcad23
    struct ifreq   *ifrp;
Packit fcad23
    mib2_ifEntry_t *ifp;
Packit fcad23
    mib2_ipNetToMediaEntry_t Media;
Packit fcad23
    int             nentries = size / sizeof(mib2_ifEntry_t);
Packit fcad23
    int             if_flags = 0;
Packit fcad23
    found_e         result = NOT_FOUND;
Packit fcad23
Packit fcad23
    if ((ifsd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Packit fcad23
	return -1;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (!buf) {
Packit fcad23
	bufsize = 10240;
Packit fcad23
	buf = malloc(bufsize);
Packit fcad23
	if (!buf) {
Packit fcad23
	    ret = -1;
Packit fcad23
	    goto Return;
Packit fcad23
	}
Packit fcad23
    }
Packit fcad23
Packit fcad23
    ifconf.ifc_buf = buf;
Packit fcad23
    ifconf.ifc_len = bufsize;
Packit fcad23
    while (ioctl(ifsd, SIOCGIFCONF, &ifconf) == -1) {
Packit fcad23
	bufsize += 10240;
Packit fcad23
	free(buf);
Packit fcad23
	buf = malloc(bufsize);
Packit fcad23
	if (!buf) {
Packit fcad23
	    ret = -1;
Packit fcad23
	    goto Return;
Packit fcad23
	}
Packit fcad23
	ifconf.ifc_buf = buf;
Packit fcad23
	ifconf.ifc_len = bufsize;
Packit fcad23
    }
Packit fcad23
Packit fcad23
 Again:
Packit fcad23
    for (i = 0, ifp = (mib2_ifEntry_t *) ifbuf, ifrp = ifconf.ifc_req;
Packit fcad23
	 ((char *) ifrp < ((char *) ifconf.ifc_buf + ifconf.ifc_len))
Packit fcad23
             && (i < nentries); i++, ifp++, ifrp++, idx++) {
Packit fcad23
Packit fcad23
	DEBUGMSGTL(("kernel_sunos5", "...... getif %s\n", ifrp->ifr_name));
Packit fcad23
Packit fcad23
	if (ioctl(ifsd, SIOCGIFFLAGS, ifrp) < 0) {
Packit fcad23
	    ret = -1;
Packit fcad23
	    snmp_log(LOG_ERR, "SIOCGIFFLAGS %s: %s\n", ifrp->ifr_name,
Packit fcad23
                     strerror(errno));
Packit fcad23
	    goto Return;
Packit fcad23
	}
Packit fcad23
        if_flags = ifrp->ifr_flags;
Packit fcad23
Packit fcad23
	if (ioctl(ifsd, SIOCGIFMTU, ifrp) < 0) {
Packit fcad23
	    ret = -1;
Packit fcad23
	    DEBUGMSGTL(("kernel_sunos5", "...... SIOCGIFMTU failed\n"));
Packit fcad23
	    goto Return;
Packit fcad23
	}
Packit fcad23
Packit fcad23
	memset(ifp, 0, sizeof(mib2_ifEntry_t));
Packit fcad23
	set_if_info(ifp, idx, ifrp->ifr_name, if_flags, ifrp->ifr_metric);
Packit fcad23
	
Packit fcad23
        if (get_if_stats(ifp) < 0) {
Packit fcad23
            ret = -1;
Packit fcad23
            goto Return;
Packit fcad23
        }
Packit fcad23
	/*
Packit fcad23
	 * An attempt to determine the physical address of the interface.
Packit fcad23
	 * There should be a more elegant solution using DLPI, but "the margin
Packit fcad23
	 * is too small to put it here ..."
Packit fcad23
	 */
Packit fcad23
Packit fcad23
	if (ioctl(ifsd, SIOCGIFADDR, ifrp) < 0) {
Packit fcad23
	    ret = -1;
Packit fcad23
	    goto Return;
Packit fcad23
	}
Packit fcad23
Packit fcad23
	if (getMibstat(MIB_IP_NET, &Media, sizeof(mib2_ipNetToMediaEntry_t),
Packit fcad23
		       GET_EXACT, &Name_cmp, ifrp) == 0) {
Packit fcad23
	    ifp->ifPhysAddress = Media.ipNetToMediaPhysAddress;
Packit fcad23
	}
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if ((req_type == GET_NEXT) && (result == NEED_NEXT)) {
Packit fcad23
            /*
Packit fcad23
             * End of buffer, so "next" is the first item in the next buffer 
Packit fcad23
             */
Packit fcad23
            req_type = GET_FIRST;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    result = getentry(req_type, (void *) ifbuf, size, sizeof(mib2_ifEntry_t),
Packit fcad23
		      (void *)resp, comp, arg);
Packit fcad23
Packit fcad23
    if ((result != FOUND) && (i == nentries) && 
Packit fcad23
	((char *)ifrp < (char *)ifconf.ifc_buf + ifconf.ifc_len)) {
Packit fcad23
	/*
Packit fcad23
	 * We reached the end of supplied buffer, but there is
Packit fcad23
	 * some more stuff to read, so continue.
Packit fcad23
	 */
Packit fcad23
	ifconf.ifc_len -= i * sizeof(struct ifreq);
Packit fcad23
	ifconf.ifc_req = ifrp;
Packit fcad23
	goto Again;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (result != FOUND) {
Packit fcad23
            ret = 2;
Packit fcad23
    } else {
Packit fcad23
	if ((char *)ifrp < (char *)ifconf.ifc_buf + ifconf.ifc_len) {
Packit fcad23
	    ret = 1;        /* Found and more data to fetch */
Packit fcad23
	} else {
Packit fcad23
	    ret = 0;        /* Found and no more data */
Packit fcad23
	}
Packit fcad23
	*length = i * sizeof(mib2_ifEntry_t);       /* Actual cache length */
Packit fcad23
    }
Packit fcad23
Packit fcad23
 Return:
Packit fcad23
    close(ifsd);
Packit fcad23
    return ret;
Packit fcad23
}
Packit fcad23
#endif /*defined(HAVE_IF_NAMEINDEX)&&defined(NETSNMP_INCLUDE_IFTABLE_REWRITES)*/
Packit fcad23
Packit fcad23
static void
Packit fcad23
set_if_info(mib2_ifEntry_t *ifp, unsigned index, char *name, uint64_t flags,
Packit fcad23
            int mtu)
Packit fcad23
{ 
Packit fcad23
    boolean_t havespeed = B_FALSE;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * Set basic information 
Packit fcad23
     */
Packit fcad23
    ifp->ifIndex = index;
Packit fcad23
    ifp->ifDescr.o_length = strlen(name);
Packit fcad23
    strcpy(ifp->ifDescr.o_bytes, name);
Packit fcad23
    ifp->ifAdminStatus = (flags & IFF_UP) ? 1 : 2;
Packit fcad23
    ifp->ifOperStatus = ((flags & IFF_UP) && (flags & IFF_RUNNING)) ? 1 : 2;
Packit fcad23
    ifp->ifLastChange = 0;      /* Who knows ...  */
Packit fcad23
    ifp->flags = flags;
Packit fcad23
    ifp->ifMtu = mtu;
Packit fcad23
    ifp->ifSpeed = 0;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * Get link speed
Packit fcad23
     */
Packit fcad23
    if ((getKstatInt(NULL, name, "ifspeed", &ifp->ifSpeed) == 0)) {
Packit fcad23
        /*
Packit fcad23
         * check for SunOS patch with half implemented ifSpeed 
Packit fcad23
         */
Packit fcad23
        if (ifp->ifSpeed > 0 && ifp->ifSpeed < 10000) {
Packit fcad23
            ifp->ifSpeed *= 1000000;
Packit fcad23
        }
Packit fcad23
	havespeed = B_TRUE;
Packit fcad23
    } else if (getKstatInt(NULL, name, "ifSpeed", &ifp->ifSpeed) == 0) {
Packit fcad23
        /*
Packit fcad23
         * this is good 
Packit fcad23
         */
Packit fcad23
	havespeed = B_TRUE;
Packit fcad23
    } else if (getKstatInt("link", name, "ifspeed", &ifp->ifSpeed) == 0) {
Packit fcad23
	havespeed = B_TRUE;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /* make ifOperStatus depend on link status if available */
Packit fcad23
    if (ifp->ifAdminStatus == 1) {
Packit fcad23
        int i_tmp;
Packit fcad23
        /* only UPed interfaces get correct link status - if any */
Packit fcad23
        if (getKstatInt(NULL, name,"link_up",&i_tmp) == 0) {
Packit fcad23
            ifp->ifOperStatus = i_tmp ? 1 : 2;
Packit fcad23
#ifdef IFF_FAILED
Packit fcad23
        } else if (flags & IFF_FAILED) {
Packit fcad23
            /*
Packit fcad23
	     * If IPMP is used, and if the daemon marks the interface
Packit fcad23
	     * as 'failed', then we know for sure something is amiss.
Packit fcad23
             */
Packit fcad23
            ifp->ifOperStatus = 2;
Packit fcad23
#endif
Packit fcad23
	} else if (havespeed == B_TRUE && ifp->ifSpeed == 0) {
Packit fcad23
	    /* Heuristic */
Packit fcad23
	    ifp->ifOperStatus = 2;
Packit fcad23
	}
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * Set link Type and Speed (if it could not be determined from kstat)
Packit fcad23
     */
Packit fcad23
    if (ifp->ifType == 24) {
Packit fcad23
        ifp->ifSpeed = 127000000;
Packit fcad23
    } else if (ifp->ifType == 1 || ifp->ifType == 0) {
Packit fcad23
        /*
Packit fcad23
	 * Could not get the type from DLPI, so lets fall back to the hardcoded
Packit fcad23
	 * values.
Packit fcad23
	 */
Packit fcad23
        switch (name[0]) {
Packit fcad23
        case 'a':          /* ath (802.11) */
Packit fcad23
            if (name[1] == 't' && name[2] == 'h')
Packit fcad23
                ifp->ifType = 71;
Packit fcad23
            break;
Packit fcad23
        case 'l':          /* le / lo / lane (ATM LAN Emulation) */
Packit fcad23
            if (name[1] == 'o') {
Packit fcad23
            if (!ifp->ifSpeed)
Packit fcad23
                ifp->ifSpeed = 127000000;
Packit fcad23
            ifp->ifType = 24;
Packit fcad23
            } else if (name[1] == 'e') {
Packit fcad23
            if (!ifp->ifSpeed)
Packit fcad23
                ifp->ifSpeed = 10000000;
Packit fcad23
            ifp->ifType = 6;
Packit fcad23
            } else if (name[1] == 'a') {
Packit fcad23
            if (!ifp->ifSpeed)
Packit fcad23
                ifp->ifSpeed = 155000000;
Packit fcad23
            ifp->ifType = 37;
Packit fcad23
            }
Packit fcad23
            break;
Packit fcad23
    
Packit fcad23
        case 'g':          /* ge (gigabit ethernet card)  */
Packit fcad23
        case 'c':          /* ce (Cassini Gigabit-Ethernet (PCI) */
Packit fcad23
            if (!ifp->ifSpeed)
Packit fcad23
            ifp->ifSpeed = 1000000000;
Packit fcad23
            ifp->ifType = 6;
Packit fcad23
            break;
Packit fcad23
    
Packit fcad23
        case 'h':          /* hme (SBus card) */
Packit fcad23
        case 'e':          /* eri (PCI card) */
Packit fcad23
        case 'b':          /* be */
Packit fcad23
        case 'd':          /* dmfe -- found on netra X1 */
Packit fcad23
            if (!ifp->ifSpeed)
Packit fcad23
            ifp->ifSpeed = 100000000;
Packit fcad23
            ifp->ifType = 6;
Packit fcad23
            break;
Packit fcad23
    
Packit fcad23
        case 'f':          /* fa (Fore ATM) */
Packit fcad23
            if (!ifp->ifSpeed)
Packit fcad23
            ifp->ifSpeed = 155000000;
Packit fcad23
            ifp->ifType = 37;
Packit fcad23
            break;
Packit fcad23
    
Packit fcad23
        case 'q':         /* qe (QuadEther)/qa (Fore ATM)/qfe (QuadFastEther) */
Packit fcad23
            if (name[1] == 'a') {
Packit fcad23
            if (!ifp->ifSpeed)
Packit fcad23
                ifp->ifSpeed = 155000000;
Packit fcad23
            ifp->ifType = 37;
Packit fcad23
            } else if (name[1] == 'e') {
Packit fcad23
                if (!ifp->ifSpeed)
Packit fcad23
                    ifp->ifSpeed = 10000000;
Packit fcad23
                ifp->ifType = 6;
Packit fcad23
            } else if (name[1] == 'f') {
Packit fcad23
                if (!ifp->ifSpeed)
Packit fcad23
                    ifp->ifSpeed = 100000000;
Packit fcad23
                ifp->ifType = 6;
Packit fcad23
            }
Packit fcad23
            break;
Packit fcad23
    
Packit fcad23
        case 'i':          /* ibd (Infiniband)/ip.tun (IP tunnel) */
Packit fcad23
            if (name[1] == 'b')
Packit fcad23
                ifp->ifType = 199;
Packit fcad23
            else if (name[1] == 'p')
Packit fcad23
                ifp->ifType = 131;
Packit fcad23
            break;
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
static int 
Packit fcad23
get_if_stats(mib2_ifEntry_t *ifp)
Packit fcad23
{
Packit fcad23
    Counter l_tmp;
Packit fcad23
    char *name = ifp->ifDescr.o_bytes;
Packit fcad23
Packit fcad23
    if (strchr(name, ':'))
Packit fcad23
        return (0); 
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * First try to grab 64-bit counters; if they are not available,
Packit fcad23
     * fall back to 32-bit.
Packit fcad23
     */
Packit fcad23
    if (getKstat(name, "ipackets64", &ifp->ifHCInUcastPkts) != 0) {
Packit fcad23
        if (getKstatInt(NULL, name, "ipackets", &ifp->ifInUcastPkts) != 0) {
Packit fcad23
            return (-1);
Packit fcad23
        }
Packit fcad23
    } else { 
Packit fcad23
            ifp->ifInUcastPkts = (uint32_t)(ifp->ifHCInUcastPkts & 0xffffffff); 
Packit fcad23
    }
Packit fcad23
    
Packit fcad23
    if (getKstat(name, "rbytes64", &ifp->ifHCInOctets) != 0) {
Packit fcad23
        if (getKstatInt(NULL, name, "rbytes", &ifp->ifInOctets) != 0) {
Packit fcad23
            ifp->ifInOctets = ifp->ifInUcastPkts * 308; 
Packit fcad23
        }
Packit fcad23
    } else {
Packit fcad23
            ifp->ifInOctets = (uint32_t)(ifp->ifHCInOctets & 0xffffffff);
Packit fcad23
    }
Packit fcad23
   
Packit fcad23
    if (getKstat(name, "opackets64", &ifp->ifHCOutUcastPkts) != 0) {
Packit fcad23
        if (getKstatInt(NULL, name, "opackets", &ifp->ifOutUcastPkts) != 0) {
Packit fcad23
            return (-1);
Packit fcad23
        }
Packit fcad23
    } else {
Packit fcad23
         ifp->ifOutUcastPkts = (uint32_t)(ifp->ifHCOutUcastPkts & 0xffffffff);
Packit fcad23
    }
Packit fcad23
    
Packit fcad23
    if (getKstat(name, "obytes64", &ifp->ifHCOutOctets) != 0) {
Packit fcad23
        if (getKstatInt(NULL, name, "obytes", &ifp->ifOutOctets) != 0) { 
Packit fcad23
            ifp->ifOutOctets = ifp->ifOutUcastPkts * 308;    /* XXX */
Packit fcad23
        }
Packit fcad23
    } else {
Packit fcad23
        ifp->ifOutOctets = (uint32_t)(ifp->ifHCOutOctets & 0xffffffff);
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (ifp->ifType == 24)  /* Loopback */
Packit fcad23
        return (0);
Packit fcad23
Packit fcad23
    /* some? VLAN interfaces don't have error counters, so ignore failure */
Packit fcad23
    getKstatInt(NULL, name, "ierrors", &ifp->ifInErrors);
Packit fcad23
    getKstatInt(NULL, name, "oerrors", &ifp->ifOutErrors);
Packit fcad23
Packit fcad23
    /* Try to grab some additional information */
Packit fcad23
    getKstatInt(NULL, name, "collisions", &ifp->ifCollisions); 
Packit fcad23
    getKstatInt(NULL, name, "unknowns", &ifp->ifInUnknownProtos); 
Packit fcad23
                
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * TODO some NICs maintain 64-bit counters for multi/broadcast
Packit fcad23
     * packets; should try to get that information.
Packit fcad23
     */
Packit fcad23
    if (getKstatInt(NULL, name, "brdcstrcv", &l_tmp) == 0) 
Packit fcad23
        ifp->ifHCInBroadcastPkts = l_tmp;
Packit fcad23
Packit fcad23
    if (getKstatInt(NULL, name, "multircv", &l_tmp) == 0)
Packit fcad23
        ifp->ifHCInMulticastPkts = l_tmp;
Packit fcad23
Packit fcad23
    ifp->ifInNUcastPkts = (uint32_t)(ifp->ifHCInBroadcastPkts + 
Packit fcad23
                                     ifp->ifHCInMulticastPkts);
Packit fcad23
Packit fcad23
    if (getKstatInt(NULL, name, "brdcstxmt", &l_tmp) == 0)
Packit fcad23
        ifp->ifHCOutBroadcastPkts = l_tmp;
Packit fcad23
Packit fcad23
    if (getKstatInt(NULL, name, "multixmt", &l_tmp) == 0)
Packit fcad23
        ifp->ifHCOutMulticastPkts = l_tmp;
Packit fcad23
Packit fcad23
    ifp->ifOutNUcastPkts = (uint32_t)(ifp->ifHCOutBroadcastPkts + 
Packit fcad23
                                      ifp->ifHCOutMulticastPkts);
Packit fcad23
    return(0);
Packit fcad23
}
Packit fcad23
/*
Packit fcad23
 * Always TRUE. May be used as a comparison function in getMibstat
Packit fcad23
 * to obtain the whole table (GET_FIRST should be used) 
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
Get_everything(void *x, void *y)
Packit fcad23
{
Packit fcad23
    return 0;             /* Always TRUE */
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * Compare name and IP address of the interface to ARP table entry.
Packit fcad23
 * Needed to obtain the physical address of the interface in getif.
Packit fcad23
 */
Packit fcad23
static int
Packit fcad23
Name_cmp(void *ifrp, void *ep)
Packit fcad23
{
Packit fcad23
    struct sockaddr_in *s = (struct sockaddr_in *)
Packit fcad23
	                                   &(((struct ifreq *)ifrp)->ifr_addr);
Packit fcad23
    mib2_ipNetToMediaEntry_t *Ep = (mib2_ipNetToMediaEntry_t *)ep;
Packit fcad23
Packit fcad23
    if ((strncmp(Ep->ipNetToMediaIfIndex.o_bytes,
Packit fcad23
		 ((struct ifreq *)ifrp)->ifr_name,
Packit fcad23
		 Ep->ipNetToMediaIfIndex.o_length) == 0) &&
Packit fcad23
	(s->sin_addr.s_addr == Ep->ipNetToMediaNetAddress)) {
Packit fcad23
	return 0;
Packit fcad23
    } else {
Packit fcad23
	return 1;
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * Try to determine the index of a particular interface. If mfd-rewrites is
Packit fcad23
 * specified, then this function would only be used when the system does not
Packit fcad23
 * have if_nametoindex(3SOCKET).
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
solaris2_if_nametoindex(const char *Name, int Len)
Packit fcad23
{
Packit fcad23
    int             i, sd, lastlen = 0, interfaces = 0;
Packit fcad23
    struct ifconf   ifc;
Packit fcad23
    struct ifreq   *ifrp = NULL;
Packit fcad23
    char           *buf = NULL;
Packit fcad23
Packit fcad23
    if (Name == 0) {
Packit fcad23
        return 0;
Packit fcad23
    }
Packit fcad23
    if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Packit fcad23
        return 0;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * Cope with lots of interfaces and brokenness of ioctl SIOCGIFCONF
Packit fcad23
     * on some platforms; see W. R. Stevens, ``Unix Network Programming
Packit fcad23
     * Volume I'', p.435.  
Packit fcad23
     */
Packit fcad23
Packit fcad23
    for (i = 8;; i += 8) {
Packit fcad23
        buf = calloc(i, sizeof(struct ifreq));
Packit fcad23
        if (buf == NULL) {
Packit fcad23
            close(sd);
Packit fcad23
            return 0;
Packit fcad23
        }
Packit fcad23
        ifc.ifc_len = i * sizeof(struct ifreq);
Packit fcad23
        ifc.ifc_buf = (caddr_t) buf;
Packit fcad23
Packit fcad23
        if (ioctl(sd, SIOCGIFCONF, (char *) &ifc) < 0) {
Packit fcad23
            if (errno != EINVAL || lastlen != 0) {
Packit fcad23
                /*
Packit fcad23
                 * Something has gone genuinely wrong.  
Packit fcad23
                 */
Packit fcad23
                free(buf);
Packit fcad23
                close(sd);
Packit fcad23
                return 0;
Packit fcad23
            }
Packit fcad23
            /*
Packit fcad23
             * Otherwise, it could just be that the buffer is too small.  
Packit fcad23
             */
Packit fcad23
        } else {
Packit fcad23
            if (ifc.ifc_len == lastlen) {
Packit fcad23
                /*
Packit fcad23
                 * The length is the same as the last time; we're done.  
Packit fcad23
                 */
Packit fcad23
                break;
Packit fcad23
            }
Packit fcad23
            lastlen = ifc.ifc_len;
Packit fcad23
        }
Packit fcad23
        free(buf);
Packit fcad23
    }
Packit fcad23
Packit fcad23
    ifrp = ifc.ifc_req;
Packit fcad23
    interfaces = (ifc.ifc_len / sizeof(struct ifreq)) + 1;
Packit fcad23
Packit fcad23
    for (i = 1; i < interfaces; i++, ifrp++) {
Packit fcad23
        if (strncmp(ifrp->ifr_name, Name, Len) == 0) {
Packit fcad23
            free(buf);
Packit fcad23
            close(sd);
Packit fcad23
            return i;
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
Packit fcad23
    free(buf);
Packit fcad23
    close(sd);
Packit fcad23
    return 0;
Packit fcad23
}
Packit fcad23
Packit fcad23
#ifdef _STDC_COMPAT
Packit fcad23
#ifdef __cplusplus
Packit fcad23
}
Packit fcad23
#endif
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#ifdef _GETKSTAT_TEST
Packit fcad23
Packit fcad23
int
Packit fcad23
main(int argc, char **argv)
Packit fcad23
{
Packit fcad23
    int             rc = 0;
Packit fcad23
    u_long          val = 0;
Packit fcad23
Packit fcad23
    if (argc != 3) {
Packit fcad23
        snmp_log(LOG_ERR, "Usage: %s stat_name var_name\n", argv[0]);
Packit fcad23
        exit(1);
Packit fcad23
    }
Packit fcad23
Packit fcad23
    snmp_set_do_debugging(1);
Packit fcad23
    rc = getKstat(argv[1], argv[2], &val;;
Packit fcad23
Packit fcad23
    if (rc == 0)
Packit fcad23
        snmp_log(LOG_ERR, "%s = %lu\n", argv[2], val);
Packit fcad23
    else
Packit fcad23
        snmp_log(LOG_ERR, "rc =%d\n", rc);
Packit fcad23
    return 0;
Packit fcad23
}
Packit fcad23
#endif /*_GETKSTAT_TEST */
Packit fcad23
Packit fcad23
#ifdef _GETMIBSTAT_TEST
Packit fcad23
Packit fcad23
int
Packit fcad23
ip20comp(void *ifname, void *ipp)
Packit fcad23
{
Packit fcad23
    return (strncmp((char *) ifname,
Packit fcad23
                    ((mib2_ipAddrEntry_t *) ipp)->ipAdEntIfIndex.o_bytes,
Packit fcad23
                    ((mib2_ipAddrEntry_t *) ipp)->ipAdEntIfIndex.
Packit fcad23
                    o_length));
Packit fcad23
}
Packit fcad23
Packit fcad23
int
Packit fcad23
ARP_Cmp_Addr(void *addr, void *ep)
Packit fcad23
{
Packit fcad23
    DEBUGMSGTL(("kernel_sunos5", "ARP: %lx <> %lx\n",
Packit fcad23
                ((mib2_ipNetToMediaEntry_t *) ep)->ipNetToMediaNetAddress,
Packit fcad23
                *(IpAddress *) addr));
Packit fcad23
    if (((mib2_ipNetToMediaEntry_t *) ep)->ipNetToMediaNetAddress ==
Packit fcad23
        *(IpAddress *)addr) {
Packit fcad23
        return 0;
Packit fcad23
    } else {
Packit fcad23
        return 1;
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
int
Packit fcad23
IF_cmp(void *addr, void *ep)
Packit fcad23
{
Packit fcad23
    if (((mib2_ifEntry_t *)ep)->ifIndex ==((mib2_ifEntry_t *)addr)->ifIndex) {
Packit fcad23
        return 0;
Packit fcad23
    } else {
Packit fcad23
        return 1;
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
int
Packit fcad23
main(int argc, char **argv)
Packit fcad23
{
Packit fcad23
    int             rc = 0, i, idx;
Packit fcad23
    mib2_ipAddrEntry_t ipbuf, *ipp = &ipbuf;
Packit fcad23
    mib2_ipNetToMediaEntry_t entry, *ep = &entry;
Packit fcad23
    mib2_ifEntry_t  ifstat;
Packit fcad23
    req_e           req_type;
Packit fcad23
    IpAddress       LastAddr = 0;
Packit fcad23
Packit fcad23
    if (argc != 3) {
Packit fcad23
        snmp_log(LOG_ERR,
Packit fcad23
                 "Usage: %s if_name req_type (0 first, 1 exact, 2 next) \n",
Packit fcad23
                 argv[0]);
Packit fcad23
        exit(1);
Packit fcad23
    }
Packit fcad23
Packit fcad23
    switch (atoi(argv[2])) {
Packit fcad23
    case 0:
Packit fcad23
        req_type = GET_FIRST;
Packit fcad23
        break;
Packit fcad23
    case 1:
Packit fcad23
        req_type = GET_EXACT;
Packit fcad23
        break;
Packit fcad23
    case 2:
Packit fcad23
        req_type = GET_NEXT;
Packit fcad23
        break;
Packit fcad23
    };
Packit fcad23
Packit fcad23
    snmp_set_do_debugging(0);
Packit fcad23
    while ((rc =
Packit fcad23
            getMibstat(MIB_INTERFACES, &ifstat, sizeof(mib2_ifEntry_t),
Packit fcad23
                       req_type, &IF_cmp, &idx)) == 0) {
Packit fcad23
        idx = ifstat.ifIndex;
Packit fcad23
        DEBUGMSGTL(("kernel_sunos5", "Ifname = %s\n",
Packit fcad23
                    ifstat.ifDescr.o_bytes));
Packit fcad23
        req_type = GET_NEXT;
Packit fcad23
    }
Packit fcad23
    rc = getMibstat(MIB_IP_ADDR, &ipbuf, sizeof(mib2_ipAddrEntry_t),
Packit fcad23
                    req_type, ip20comp, argv[1]);
Packit fcad23
Packit fcad23
    if (rc == 0)
Packit fcad23
        DEBUGMSGTL(("kernel_sunos5", "mtu = %ld\n",
Packit fcad23
                    ipp->ipAdEntInfo.ae_mtu));
Packit fcad23
    else
Packit fcad23
        DEBUGMSGTL(("kernel_sunos5", "rc =%d\n", rc));
Packit fcad23
Packit fcad23
    while ((rc =
Packit fcad23
            getMibstat(MIB_IP_NET, &entry,
Packit fcad23
                       sizeof(mib2_ipNetToMediaEntry_t), req_type,
Packit fcad23
                       &ARP_Cmp_Addr, &LastAddr)) == 0) {
Packit fcad23
        LastAddr = ep->ipNetToMediaNetAddress;
Packit fcad23
        DEBUGMSGTL(("kernel_sunos5", "Ipaddr = %lX\n", (u_long) LastAddr));
Packit fcad23
        req_type = GET_NEXT;
Packit fcad23
    }
Packit fcad23
    return 0;
Packit fcad23
}
Packit fcad23
#endif /*_GETMIBSTAT_TEST */
Packit fcad23
#endif                          /* SUNOS5 */