/*
 *  Interfaces MIB group implementation - interfaces.c
 *
 */

/* Portions of this file are subject to the following copyright(s).  See
 * the Net-SNMP's COPYING file for more details and other copyrights
 * that may apply:
 */
/*
 * Portions of this file are copyrighted by:
 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
 * Use is subject to license terms specified in the COPYING file
 * distributed with the Net-SNMP package.
 */

#include <net-snmp/net-snmp-config.h>

#if defined(IFNET_NEEDS_KERNEL) && !defined(_KERNEL) && !defined(IFNET_NEEDS_KERNEL_LATE)
#define _KERNEL 1
#define _I_DEFINED_KERNEL
#endif

#if HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif

#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#include <sys/types.h>
#if HAVE_WINSOCK_H
#include <winsock.h>
#endif
#if defined(IFNET_NEEDS_KERNEL) && !defined(_KERNEL) && defined(IFNET_NEEDS_KERNEL_LATE)
#define _KERNEL 1
#define _I_DEFINED_KERNEL
#endif
#if HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifndef STREAM_NEEDS_KERNEL_ISLANDS
#if HAVE_SYS_STREAM_H
#include <sys/stream.h>
#endif
#endif
#if HAVE_SYS_SOCKETVAR_H
#include <sys/socketvar.h>
#endif

#if TIME_WITH_SYS_TIME
# if defined (WIN32) || defined (cygwin)
#  include <sys/timeb.h>
# else
# include <sys/time.h>
# endif
# include <time.h>
#else
# if HAVE_SYS_TIME_H
#  include <sys/time.h>
# else
#  include <time.h>
# endif
#endif
#if HAVE_SYS_SOCKIO_H
#include <sys/sockio.h>
#endif
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
#if HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#if HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#if HAVE_NET_IF_H
#include <net/if.h>
#endif
#if HAVE_NETINET_IN_VAR_H
#include <netinet/in_var.h>
#endif
#if HAVE_NET_IF_VAR_H
#include <net/if_var.h>
#endif
#ifdef _I_DEFINED_KERNEL
#undef _KERNEL
#endif
#ifdef STREAM_NEEDS_KERNEL_ISLANDS
#if HAVE_SYS_STREAM_H
#include <sys/stream.h>
#endif
#endif
#if HAVE_NET_ROUTE_H
#include <net/route.h>
#endif
#if HAVE_NETINET_IN_SYSTM_H
#include <netinet/in_systm.h>
#endif
#if HAVE_SYS_HASHING_H
#include <sys/hashing.h>
#endif
#if HAVE_NETINET_IN_VAR_H
#include <netinet/in_var.h>
#endif
#if HAVE_NETINET_IP_H
#include <netinet/ip.h>
#endif
#ifdef NETSNMP_ENABLE_IPV6
#if HAVE_NETINET_IP6_H
#include <netinet/ip6.h>
#endif
#endif
#if HAVE_SYS_QUEUE_H
#include <sys/queue.h>
#endif
#if HAVE_NETINET_IP_VAR_H
#include <netinet/ip_var.h>
#endif
#ifdef NETSNMP_ENABLE_IPV6
#if HAVE_NETNETSNMP_ENABLE_IPV6_IP6_VAR_H
#include <netinet6/ip6_var.h>
#endif
#endif
#if HAVE_NETINET_IN_PCB_H
#include <netinet/in_pcb.h>
#endif
#if HAVE_NETINET_IF_ETHER_H
#include <netinet/if_ether.h>
#endif
#if HAVE_NET_IF_TYPES_H
#include <net/if_types.h>
#endif
#if HAVE_NET_IF_DL_H
#ifndef dynix
#include <net/if_dl.h>
#else
#include <sys/net/if_dl.h>
#endif
#endif
#if HAVE_INET_MIB2_H
#include <inet/mib2.h>
#endif
#if HAVE_IOCTLS_H
#include <ioctls.h>
#endif

#ifdef solaris2
# include <errno.h>
#include "kernel_sunos5.h"
#else
#include "kernel.h"
#endif

#ifdef hpux
#include <sys/mib.h>
#include <netinet/mib_kern.h>
#endif                          /* hpux */

#ifdef cygwin
#include <windows.h>
#endif

#if HAVE_SYS_SYSCTL_H
#include <sys/sysctl.h>

#if defined(freebsd3) || defined(freebsd4) || defined(freebsd5)
#    define USE_SYSCTL_IFLIST
#else
# if defined(CTL_NET) && !defined(freebsd2) && !defined(netbsd1)
#  ifdef PF_ROUTE
#   ifdef NET_RT_IFLIST
#    ifndef netbsd1
#     define USE_SYSCTL_IFLIST
#    endif
#   endif
#  endif
# endif
#endif                          /* defined(freebsd3) */
#endif                          /* HAVE_SYS_SYSCTL_H */

#if HAVE_OSRELDATE_H
#include <osreldate.h>
#endif
#ifdef NETSNMP_CAN_USE_SYSCTL
#include <sys/sysctl.h>
#endif

#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include <net-snmp/agent/auto_nlist.h>
#include <net-snmp/data_access/interface.h>

#include "interfaces.h"
#include "struct.h"
#include "util_funcs.h"
#include "sysORTable.h"

/* if you want caching enabled for speed retrival purposes, set this to 5?*/
#define MINLOADFREQ 0                     /* min reload frequency in seconds */
#ifdef linux
static unsigned long LastLoad = 0;        /* ET in secs at last table load */
#endif

extern struct timeval starttime;

struct variable3 interfaces_variables[] = {
    {IFNUMBER, ASN_INTEGER, RONLY, var_interfaces, 1, {1}},
    {IFINDEX, ASN_INTEGER, RONLY, var_ifEntry, 3, {2, 1, 1}},
    {IFDESCR, ASN_OCTET_STR, RONLY, var_ifEntry, 3, {2, 1, 2}},
    {NETSNMP_IFTYPE, ASN_INTEGER, RONLY, var_ifEntry, 3, {2, 1, 3}},
    {IFMTU, ASN_INTEGER, RONLY, var_ifEntry, 3, {2, 1, 4}},
    {IFSPEED, ASN_GAUGE, RONLY, var_ifEntry, 3, {2, 1, 5}},
    {IFPHYSADDRESS, ASN_OCTET_STR, RONLY, var_ifEntry, 3, {2, 1, 6}},
#if defined (WIN32) || defined (cygwin)
    {IFADMINSTATUS, ASN_INTEGER, RWRITE, var_ifEntry, 3, {2, 1, 7}},
#else
    {IFADMINSTATUS, ASN_INTEGER, RONLY, var_ifEntry, 3, {2, 1, 7}},
#endif
    {IFOPERSTATUS, ASN_INTEGER, RONLY, var_ifEntry, 3, {2, 1, 8}},
    {IFLASTCHANGE, ASN_TIMETICKS, RONLY, var_ifEntry, 3, {2, 1, 9}},
    {IFINOCTETS, ASN_COUNTER, RONLY, var_ifEntry, 3, {2, 1, 10}},
    {IFINUCASTPKTS, ASN_COUNTER, RONLY, var_ifEntry, 3, {2, 1, 11}},
    {IFINNUCASTPKTS, ASN_COUNTER, RONLY, var_ifEntry, 3, {2, 1, 12}},
    {IFINDISCARDS, ASN_COUNTER, RONLY, var_ifEntry, 3, {2, 1, 13}},
    {IFINERRORS, ASN_COUNTER, RONLY, var_ifEntry, 3, {2, 1, 14}},
    {IFINUNKNOWNPROTOS, ASN_COUNTER, RONLY, var_ifEntry, 3, {2, 1, 15}},
    {IFOUTOCTETS, ASN_COUNTER, RONLY, var_ifEntry, 3, {2, 1, 16}},
    {IFOUTUCASTPKTS, ASN_COUNTER, RONLY, var_ifEntry, 3, {2, 1, 17}},
    {IFOUTNUCASTPKTS, ASN_COUNTER, RONLY, var_ifEntry, 3, {2, 1, 18}},
    {IFOUTDISCARDS, ASN_COUNTER, RONLY, var_ifEntry, 3, {2, 1, 19}},
    {IFOUTERRORS, ASN_COUNTER, RONLY, var_ifEntry, 3, {2, 1, 20}},
    {IFOUTQLEN, ASN_GAUGE, RONLY, var_ifEntry, 3, {2, 1, 21}},
    {IFSPECIFIC, ASN_OBJECT_ID, RONLY, var_ifEntry, 3, {2, 1, 22}}
};

/*
 * Define the OID pointer to the top of the mib tree that we're
 * registering underneath, and the OID of the MIB module 
 */
oid             interfaces_variables_oid[] = { SNMP_OID_MIB2, 2 };
oid             interfaces_module_oid[] = { SNMP_OID_MIB2, 31 };

void
init_interfaces(void)
{
    /*
     * register ourselves with the agent to handle our mib tree 
     */
    REGISTER_MIB("mibII/interfaces", interfaces_variables, variable3,
                 interfaces_variables_oid);
    REGISTER_SYSOR_ENTRY(interfaces_module_oid,
                         "The MIB module to describe generic objects for network interface sub-layers");

#ifndef USE_SYSCTL_IFLIST
#if HAVE_NET_IF_MIB_H
    init_interfaces_setup();
#endif
#endif
#ifdef solaris2
    init_kernel_sunos5();
#endif
}

#ifdef linux
/*
 * if_type_from_name
 * Return interface type using the interface name as a clue.
 * Returns 1 to imply "other" type if name not recognized. 
 */
static int
if_type_from_name(const char *pcch)
{
    typedef struct _match_if {
        int             mi_type;
        const char     *mi_name;
    }              *pmatch_if, match_if;

    static match_if lmatch_if[] = {
        {24, "lo"},
        {6, "eth"},
        {9, "tr"},
        {23, "ppp"},
        {28, "sl"},
        {0, 0}                  /* end of list */
    };

    int             ii, len;
    register pmatch_if pm;

    for (ii = 0, pm = lmatch_if; pm->mi_name; pm++) {
        len = strlen(pm->mi_name);
        if (0 == strncmp(pcch, pm->mi_name, len)) {
            return (pm->mi_type);
        }
    }
    return (1);                 /* in case search fails */
}
#endif


#ifdef linux
static struct ifnet *ifnetaddr_list;
#endif


/*
 * header_ifEntry(...
 * Arguments:
 * vp     IN      - pointer to variable entry that points here
 * name    IN/OUT  - IN/name requested, OUT/name found
 * length  IN/OUT  - length of IN/OUT oid's 
 * exact   IN      - TRUE if an exact match was requested
 * var_len OUT     - length of variable or 0 if function returned
 * write_method
 * 
 */
#if !defined (WIN32) && !defined (cygwin)
static int
header_ifEntry(struct variable *vp,
               oid * name,
               size_t * length,
               int exact, size_t * var_len, WriteMethod ** write_method)
{
#define IFENTRY_NAME_LENGTH	10
    oid             newname[MAX_OID_LEN];
    register int    interface;
    int             result, count;

    DEBUGMSGTL(("mibII/interfaces", "var_ifEntry: "));
    DEBUGMSGOID(("mibII/interfaces", name, *length));
    DEBUGMSG(("mibII/interfaces", " %d\n", exact));

    memcpy((char *) newname, (char *) vp->name,
           (int) vp->namelen * sizeof(oid));
    /*
     * find "next" interface 
     */
    count = Interface_Scan_Get_Count();
    for (interface = 1; interface <= count; interface++) {
        newname[IFENTRY_NAME_LENGTH] = (oid) interface;
        result =
            snmp_oid_compare(name, *length, newname,
                             (int) vp->namelen + 1);
        if ((exact && (result == 0)) || (!exact && (result < 0)))
            break;
    }
    if (interface > count) {
        DEBUGMSGTL(("mibII/interfaces", "... index out of range\n"));
        return MATCH_FAILED;
    }


    memcpy((char *) name, (char *) newname,
           ((int) vp->namelen + 1) * sizeof(oid));
    *length = vp->namelen + 1;
    *write_method = 0;
    *var_len = sizeof(long);    /* default to 'long' results */

    DEBUGMSGTL(("mibII/interfaces", "... get I/F stats "));
    DEBUGMSGOID(("mibII/interfaces", name, *length));
    DEBUGMSG(("mibII/interfaces", "\n"));

    return interface;
}



u_char         *
var_interfaces(struct variable * vp,
               oid * name,
               size_t * length,
               int exact, size_t * var_len, WriteMethod ** write_method)
{
    if (header_generic(vp, name, length, exact, var_len, write_method) ==
        MATCH_FAILED)
        return NULL;

    switch (vp->magic) {
    case IFNUMBER:
        long_return = Interface_Scan_Get_Count();
        return (u_char *) & long_return;
    default:
        DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_interfaces\n",
                    vp->magic));
    }
    return NULL;
}

#ifdef USE_SYSCTL_IFLIST

static u_char  *if_list = 0;
static const u_char *if_list_end;
static size_t   if_list_size = 0;

struct small_ifaddr {
    struct in_addr  sifa_addr;
    struct in_addr  sifa_netmask;
    struct in_addr  sifa_broadcast;
};

extern const struct sockaddr *get_address(const void *, int, int);
extern const struct in_addr *get_in_address(const void *, int, int);
static int      Interface_Scan_By_Index(int, struct if_msghdr *, char *,
                                        struct small_ifaddr *);
static int      Interface_Get_Ether_By_Index(int, u_char *);

static int
Interface_Scan_By_Index(int iindex,
                        struct if_msghdr *if_msg,
                        char *if_name, struct small_ifaddr *sifa)
{
    u_char         *cp;
    struct if_msghdr *ifp;
    int             have_ifinfo = 0, have_addr = 0;

    if (NULL != sifa)
        memset(sifa, 0, sizeof(*sifa));
    for (cp = if_list; cp < if_list_end; cp += ifp->ifm_msglen) {
        ifp = (struct if_msghdr *) cp;
        DEBUGMSGTL(("mibII/interfaces", "ifm_type = %d, ifm_index = %d\n",
                    ifp->ifm_type, ifp->ifm_index));

        switch (ifp->ifm_type) {
        case RTM_IFINFO:
            {
                const struct sockaddr *a;

                if (ifp->ifm_index == iindex) {
                    a = get_address(ifp + 1, ifp->ifm_addrs, RTA_IFP);
                    if (a == NULL)
                        return 0;
                    strncpy(if_name,
                            ((const struct sockaddr_in *) a)->sin_zero,
                            ((const u_char *) a)[5]);
                    if_name[((const u_char *) a)[5]] = 0;
                    *if_msg = *ifp;
                    ++have_ifinfo;
                }
            }
            break;
        case RTM_NEWADDR:
            {
                struct ifa_msghdr *ifap = (struct ifa_msghdr *) cp;

                if ((NULL != sifa) && (ifap->ifam_index == iindex)) {
                    const struct in_addr *ia;

                    /*
                     * I don't know why the normal get_address() doesn't
                     * work on IRIX 6.2.  Maybe this has to do with the
                     * existence of struct sockaddr_new.  Hopefully, on
                     * other systems we can simply use get_in_address
                     * three times, with (ifap+1) as the starting
                     * address. 
                     */

                    sifa->sifa_netmask =
                        *((struct in_addr *) ((char *) (ifap + 1) + 4));
                    ia = get_in_address((char *) (ifap + 1) + 8,
                                        ifap->ifam_addrs &=
                                        ~RTA_NETMASK, RTA_IFA);
                    if (ia == NULL)
                        return 0;

                    sifa->sifa_addr = *ia;
                    ia = get_in_address((char *) (ifap + 1) + 8,
                                        ifap->ifam_addrs &= ~RTA_NETMASK,
                                        RTA_BRD);
                    if (ia == NULL)
                        return 0;

                    sifa->sifa_broadcast = *ia;
                    ++have_addr;
                }
            }
            break;
        default:
            DEBUGMSGTL(("mibII/interfaces",
                        "routing socket: unknown message type %d\n",
                        ifp->ifm_type));
        }
    }
    if (have_ifinfo && (NULL == sifa) || (have_addr)) {
        return 0;
    } else if (have_ifinfo && !(if_msg->ifm_flags & IFF_UP))
        return 0;
    else {
        return -1;
    }
}

int
Interface_Scan_Get_Count(void)
{
    u_char         *cp;
    struct if_msghdr *ifp;
    long            n = 0;

    Interface_Scan_Init();

    if (if_list_size) {
        for (cp = if_list, n = 0; cp < if_list_end; cp += ifp->ifm_msglen) {
            ifp = (struct if_msghdr *) cp;
    
            if (ifp->ifm_type == RTM_IFINFO) {
                ++n;
            }
        }
    }
    return n;
}

void
Interface_Scan_Init(void)
{
    int             name[] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0 };
    size_t          size;

    if (sysctl(name, sizeof(name) / sizeof(int), 0, &size, 0, 0) == -1) {
        snmp_log(LOG_ERR, "sysctl size fail\n");
    } else {
        if (if_list == 0 || if_list_size < size) {
            if (if_list != 0) {
                free(if_list);
            }
            if_list      = NULL;
            if_list_size = 0;
            if_list_end  = 0;
            if ((if_list = malloc(size)) == NULL) {
                snmp_log(LOG_ERR,
                         "out of memory allocating route table (size = %d)\n", size);
                return;
            }
            if_list_size = size;
        } else {
            size = if_list_size;
        }
        if (sysctl(name, sizeof(name) / sizeof(int),
                   if_list, &size, 0, 0) == -1) {
            snmp_log(LOG_ERR, "sysctl get fail\n");
        }
        if_list_end = if_list + size;
    }
}

u_char         *
var_ifEntry(struct variable *vp,
            oid * name,
            size_t * length,
            int exact, size_t * var_len, WriteMethod ** write_method)
{
    int             interface;
    struct if_msghdr if_msg;
    static char     if_name[100];
    conf_if_list   *if_ptr;
    char           *cp;

    interface =
        header_ifEntry(vp, name, length, exact, var_len, write_method);
    if (interface == MATCH_FAILED)
        return NULL;

    if (Interface_Scan_By_Index(interface, &if_msg, if_name, NULL) != 0)
        return NULL;
    if_ptr = netsnmp_access_interface_entry_overrides_get(if_name);

    switch (vp->magic) {
    case IFINDEX:
        long_return = interface;
        return (u_char *) & long_return;
    case IFDESCR:
        cp = if_name;
        *var_len = strlen(if_name);
        return (u_char *) cp;
    case NETSNMP_IFTYPE:
        if (if_ptr)
            long_return = if_ptr->type;
        else
        long_return = (long) if_msg.ifm_data.ifi_type;
        return (u_char *) & long_return;
    case IFMTU:
        long_return = (long) if_msg.ifm_data.ifi_mtu;
        return (u_char *) & long_return;
    case IFSPEED:
        if (if_ptr)
            long_return = if_ptr->speed;
        else {
#if STRUCT_IFNET_HAS_IF_BAUDRATE_IFS_VALUE
        long_return = (u_long) if_msg.ifm_data.ifi_baudrate.ifs_value <<
            if_msg.ifm_data.ifi_baudrate.ifs_log2;
#else
        long_return = (u_long) if_msg.ifm_data.ifi_baudrate;
#endif
        }
        return (u_char *) & long_return;
    case IFPHYSADDRESS:
        /*
         * XXX 
         */
        return NULL;
    case IFADMINSTATUS:
        long_return = if_msg.ifm_flags & IFF_UP ? 1 : 2;
        return (u_char *) & long_return;
    case IFOPERSTATUS:
        long_return = if_msg.ifm_flags & IFF_RUNNING ? 1 : 2;
        return (u_char *) & long_return;
        /*
         * ifLastChange 
         */
    case IFINOCTETS:
        long_return = (u_long) if_msg.ifm_data.ifi_ibytes;
        return (u_char *) & long_return;
    case IFINUCASTPKTS:
        long_return =
            (u_long) if_msg.ifm_data.ifi_ipackets -
            if_msg.ifm_data.ifi_imcasts;
        return (u_char *) & long_return;
    case IFINNUCASTPKTS:
        long_return = (u_long) if_msg.ifm_data.ifi_imcasts;
        return (u_char *) & long_return;
    case IFINDISCARDS:
        long_return = (u_long) if_msg.ifm_data.ifi_iqdrops;
        return (u_char *) & long_return;
    case IFINERRORS:
        long_return = (u_long) if_msg.ifm_data.ifi_ierrors;
        return (u_char *) & long_return;
    case IFINUNKNOWNPROTOS:
        long_return = (u_long) if_msg.ifm_data.ifi_noproto;
        return (u_char *) & long_return;
    case IFOUTOCTETS:
        long_return = (u_long) if_msg.ifm_data.ifi_obytes;
        return (u_char *) & long_return;
    case IFOUTUCASTPKTS:
        long_return =
            (u_long) if_msg.ifm_data.ifi_opackets -
            if_msg.ifm_data.ifi_omcasts;
        return (u_char *) & long_return;
    case IFOUTNUCASTPKTS:
        long_return = (u_long) if_msg.ifm_data.ifi_omcasts;
        return (u_char *) & long_return;
    case IFOUTDISCARDS:
#ifdef if_odrops
        long_return = (u_long) if_msg.ifm_data.ifi_odrops;
#else
#if NETSNMP_NO_DUMMY_VALUES
        return NULL;
#endif
        long_return = 0;
#endif
        return (u_char *) & long_return;
    case IFOUTERRORS:
        long_return = (u_long) if_msg.ifm_data.ifi_oerrors;
        return (u_char *) & long_return;
    case IFLASTCHANGE:
#ifdef irix6
        long_return = 0;
#else
        if (if_msg.ifm_data.ifi_lastchange.tv_sec == 0 &&
#if STRUCT_IFNET_HAS_IF_LASTCHANGE_TV_NSEC
            if_msg.ifm_data.ifi_lastchange.tv_nsec == 0
#else
            if_msg.ifm_data.ifi_lastchange.tv_usec == 0
#endif
           )
            long_return = 0;
        else if (if_msg.ifm_data.ifi_lastchange.tv_sec < starttime.tv_sec)
            long_return = 0;
        else {
            long_return = (u_long)
                ((if_msg.ifm_data.ifi_lastchange.tv_sec -
                  starttime.tv_sec) * 100 +
                 (
#if STRUCT_IFNET_HAS_IF_LASTCHANGE_TV_NSEC
                  if_msg.ifm_data.ifi_lastchange.tv_nsec / 1000
#else
                  if_msg.ifm_data.ifi_lastchange.tv_usec
#endif
                  - starttime.tv_usec) / 10000);
        }
#endif
        return (u_char *) & long_return;
    default:
        return 0;
    }
}

int
Interface_Scan_Next(short *Index,
                    char *Name,
                    struct ifnet *Retifnet, struct in_ifaddr *Retin_ifaddr)
{
    return 0;
}

#else                           /* not USE_SYSCTL_IFLIST */

        /*********************
	 *
	 *  Kernel & interface information,
	 *   and internal forward declarations
	 *
	 *********************/

#ifndef HAVE_NET_IF_MIB_H

#ifndef solaris2
#ifndef hpux11
static int      Interface_Scan_By_Index(int, char *, struct ifnet *,
                                        struct in_ifaddr *);
static int      Interface_Get_Ether_By_Index(int, u_char *);
#else
static int      Interface_Scan_By_Index(int, char *, nmapi_phystat *);
#endif
#endif



        /*********************
	 *
	 *  System specific implementation functions
	 *
	 *********************/


#ifndef solaris2
#ifndef hpux

u_char         *
var_ifEntry(struct variable *vp,
            oid * name,
            size_t * length,
            int exact, size_t * var_len, WriteMethod ** write_method)
{
    static struct ifnet ifnet;
    int             interface;
    static struct in_ifaddr in_ifaddr;
    static char     Name[16];
    char           *cp;
    conf_if_list   *if_ptr;
#if STRUCT_IFNET_HAS_IF_LASTCHANGE_TV_SEC
    struct timeval  now;
#endif

    interface =
        header_ifEntry(vp, name, length, exact, var_len, write_method);
    if (interface == MATCH_FAILED)
        return NULL;

    Interface_Scan_By_Index(interface, Name, &ifnet, &in_ifaddr);
    if_ptr = netsnmp_access_interface_entry_overrides_get(Name);

    switch (vp->magic) {
    case IFINDEX:
        long_return = interface;
        return (u_char *) & long_return;
    case IFDESCR:
        cp = Name;
        *var_len = strlen(cp);
        return (u_char *) cp;
    case NETSNMP_IFTYPE:
        if (if_ptr)
            long_return = if_ptr->type;
        else {
#if STRUCT_IFNET_HAS_IF_TYPE
            long_return = ifnet.if_type;
#else
            long_return = 1;    /* OTHER */
#endif
        }
        return (u_char *) & long_return;
    case IFMTU:{
            long_return = (long) ifnet.if_mtu;
            return (u_char *) & long_return;
        }
    case IFSPEED:
        if (if_ptr)
            long_return = if_ptr->speed;
        else {
#if STRUCT_IFNET_HAS_IF_BAUDRATE
            long_return = ifnet.if_baudrate;
#elif STRUCT_IFNET_HAS_IF_SPEED
            long_return = ifnet.if_speed;
#elif STRUCT_IFNET_HAS_IF_TYPE && defined(IFT_ETHER)
            if (ifnet.if_type == IFT_ETHER)
                long_return = 10000000;
            if (ifnet.if_type == IFT_P10)
                long_return = 10000000;
            if (ifnet.if_type == IFT_P80)
                long_return = 80000000;
            if (ifnet.if_type == IFT_ISDNBASIC)
                long_return = 64000;    /* EDSS1 only */
            if (ifnet.if_type == IFT_ISDNPRIMARY)
                long_return = 64000 * 30;
#else
#if NETSNMP_NO_DUMMY_VALUES
            return NULL;
#endif
            long_return = (u_long) 10000000;
#endif
        }
        return (u_char *) & long_return;
    case IFPHYSADDRESS:
        Interface_Get_Ether_By_Index(interface, return_buf);
#if defined(aix4) || defined(aix5) || defined(aix6)
	*var_len = 0;
#else
        if ((return_buf[0] == 0) && (return_buf[1] == 0) &&
            (return_buf[2] == 0) && (return_buf[3] == 0) &&
            (return_buf[4] == 0) && (return_buf[5] == 0))
            *var_len = 0;
        else
            *var_len = 6;
#endif
        return (u_char *) return_buf;
    case IFADMINSTATUS:
        long_return = ifnet.if_flags & IFF_UP ? 1 : 2;
        return (u_char *) & long_return;
    case IFOPERSTATUS:
        long_return = ifnet.if_flags & IFF_RUNNING ? 1 : 2;
        return (u_char *) & long_return;
    case IFLASTCHANGE:
#if defined(STRUCT_IFNET_HAS_IF_LASTCHANGE_TV_SEC) && !(defined(freebsd2) && __FreeBSD_version < 199607)
        /*
         * XXX - SNMP's ifLastchange is time when op. status changed
         * * FreeBSD's if_lastchange is time when packet was input or output
         * * (at least in 2.1.0-RELEASE. Changed in later versions of the kernel?)
         */
        /*
         * FreeBSD's if_lastchange before the 2.1.5 release is the time when
         * * a packet was last input or output.  In the 2.1.5 and later releases,
         * * this is fixed, thus the 199607 comparison.
         */
        if (ifnet.if_lastchange.tv_sec == 0 &&
            ifnet.if_lastchange.tv_usec == 0)
            long_return = 0;
        else if (ifnet.if_lastchange.tv_sec < starttime.tv_sec)
            long_return = 0;
        else {
            long_return = (u_long)
                ((ifnet.if_lastchange.tv_sec - starttime.tv_sec) * 100
                 + (ifnet.if_lastchange.tv_usec -
                    starttime.tv_usec) / 10000);
        }
#else
#if NETSNMP_NO_DUMMY_VALUES
        return NULL;
#endif
        long_return = 0;        /* XXX */
#endif
        return (u_char *) & long_return;
    case IFINOCTETS:
#ifdef STRUCT_IFNET_HAS_IF_IBYTES
#if defined(aix4) || defined(aix5) || defined(aix6)
        long_return = (u_long) ifnet.if_ibytes & 0xffffffff;
#else
        long_return = (u_long) ifnet.if_ibytes;
#endif
#else
#if NETSNMP_NO_DUMMY_VALUES
        return NULL;
#endif
        long_return = (u_long) ifnet.if_ipackets * 308; /* XXX */
#endif
        return (u_char *) & long_return;
    case IFINUCASTPKTS:
        {
#if defined(aix4) || defined(aix5) || defined(aix6)
            long_return = (u_long) ifnet.if_ipackets & 0xffffffff;
#else
            long_return = (u_long) ifnet.if_ipackets;
#endif
#if STRUCT_IFNET_HAS_IF_IMCASTS
#if defined(aix4) || defined(aix5) || defined(aix6)
            long_return -= (u_long) ifnet.if_imcasts & 0xffffffff;
#else
            long_return -= (u_long) ifnet.if_imcasts;
#endif
#endif
        }
        return (u_char *) & long_return;
    case IFINNUCASTPKTS:
#if STRUCT_IFNET_HAS_IF_IMCASTS
#if defined(aix4) || defined(aix5) || defined(aix6)
        long_return = (u_long) ifnet.if_imcasts & 0xffffffff;
#else
        long_return = (u_long) ifnet.if_imcasts;
#endif
#else
#if NETSNMP_NO_DUMMY_VALUES
        return NULL;
#endif
        long_return = (u_long) 0;       /* XXX */
#endif
        return (u_char *) & long_return;
    case IFINDISCARDS:
#if STRUCT_IFNET_HAS_IF_IQDROPS
#if defined(aix4) || defined(aix5) || defined(aix6)
        long_return = (u_long) ifnet.if_iqdrops & 0xffffffff;
#else
        long_return = (u_long) ifnet.if_iqdrops;
#endif
#else
#if NETSNMP_NO_DUMMY_VALUES
        return NULL;
#endif
        long_return = (u_long) 0;       /* XXX */
#endif
        return (u_char *) & long_return;
    case IFINERRORS:
#if defined(aix4) || defined(aix5) || defined(aix6)
        long_return = (u_long) ifnet.if_ierrors & 0xffffffff;
#else
        long_return = (u_long) ifnet.if_ierrors;
#endif
        return (u_char *) & long_return;
    case IFINUNKNOWNPROTOS:
#if STRUCT_IFNET_HAS_IF_NOPROTO
#if defined(aix4) || defined(aix5) || defined(aix6)
        long_return = (u_long) ifnet.if_noproto & 0xffffffff;
#else
        long_return = (u_long) ifnet.if_noproto;
#endif
#else
#if NETSNMP_NO_DUMMY_VALUES
        return NULL;
#endif
        long_return = (u_long) 0;       /* XXX */
#endif
        return (u_char *) & long_return;
    case IFOUTOCTETS:
#ifdef STRUCT_IFNET_HAS_IF_OBYTES
#if defined(aix4) || defined(aix5) || defined(aix6)
        long_return = (u_long) ifnet.if_obytes & 0xffffffff;
#else
        long_return = (u_long) ifnet.if_obytes;
#endif
#else
#if NETSNMP_NO_DUMMY_VALUES
        return NULL;
#endif
        long_return = (u_long) ifnet.if_opackets * 308; /* XXX */
#endif
        return (u_char *) & long_return;
    case IFOUTUCASTPKTS:
        {
#if defined(aix4) || defined(aix5) || defined(aix6)
            long_return = (u_long) ifnet.if_opackets & 0xffffffff;
#else
            long_return = (u_long) ifnet.if_opackets;
#endif
#if STRUCT_IFNET_HAS_IF_OMCASTS
#if defined(aix4) || defined(aix5) || defined(aix6)
            long_return -= (u_long) ifnet.if_omcasts & 0xffffffff;
#else
            long_return -= (u_long) ifnet.if_omcasts;
#endif
#endif
        }
        return (u_char *) & long_return;
    case IFOUTNUCASTPKTS:
#if STRUCT_IFNET_HAS_IF_OMCASTS
#if defined(aix4) || defined(aix5) || defined(aix6)
        long_return = (u_long) ifnet.if_omcasts & 0xffffffff;
#else
        long_return = (u_long) ifnet.if_omcasts;
#endif
#else
#if NETSNMP_NO_DUMMY_VALUES
        return NULL;
#endif
        long_return = (u_long) 0;       /* XXX */
#endif
        return (u_char *) & long_return;
    case IFOUTDISCARDS:
#if defined(aix4) || defined(aix5) || defined(aix6)
        long_return = ifnet.if_snd.ifq_drops & 0xffffffff;
#else
        long_return = ifnet.if_snd.ifq_drops;
#endif
        return (u_char *) & long_return;
    case IFOUTERRORS:
#if defined(aix4) || defined(aix5) || defined(aix6)
        long_return = ifnet.if_oerrors & 0xffffffff;
#else
        long_return = ifnet.if_oerrors;
#endif
        return (u_char *) & long_return;
    case IFOUTQLEN:
#if defined(aix4) || defined(aix5) || defined(aix6)
        long_return = ifnet.if_snd.ifq_len & 0xffffffff;
#else
        long_return = ifnet.if_snd.ifq_len;
#endif
        return (u_char *) & long_return;
    case IFSPECIFIC:
        *var_len = nullOidLen;
        return (u_char *) nullOid;
    default:
        DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ifEntry\n",
                    vp->magic));
    }
    return NULL;
}

#else                           /* hpux */

u_char         *
var_ifEntry(struct variable *vp,
            oid * name,
            size_t * length,
            int exact, size_t * var_len, WriteMethod ** write_method)
{
#if defined(hpux11)
    static nmapi_phystat ifnet;
#else
    static struct ifnet ifnet;
#endif
    register int    interface;
#if !defined(hpux11)
    static struct in_ifaddr in_ifaddrVar;
#endif
#if defined(hpux11)
    static char     Name[MAX_PHYSADDR_LEN];
#else
    static char     Name[16];
#endif
    register char  *cp;
#if STRUCT_IFNET_HAS_IF_LASTCHANGE_TV_SEC
    struct timeval  now;
#endif
#if !defined(hpux11)
    struct nmparms  hp_nmparms;
    static mib_ifEntry hp_ifEntry;
    int             hp_fd;
    int             hp_len = sizeof(hp_ifEntry);
#endif
    conf_if_list   *if_ptr;

    interface =
        header_ifEntry(vp, name, length, exact, var_len, write_method);
    if (interface == MATCH_FAILED)
        return NULL;

#if defined(hpux11)
    Interface_Scan_By_Index(interface, Name, &ifnet);
#else
    Interface_Scan_By_Index(interface, Name, &ifnet, &in_ifaddrVar);
#endif

#if !defined(hpux11)
    /*
     * Additional information about the interfaces is available under
     * HP-UX through the network management interface '/dev/netman'
     */
    hp_ifEntry.ifIndex = interface;
    hp_nmparms.objid = ID_ifEntry;
    hp_nmparms.buffer = (char *) &hp_ifEntry;
    hp_nmparms.len = &hp_len;
    if ((hp_fd = open("/dev/netman", O_RDONLY)) != -1) {
        if (ioctl(hp_fd, NMIOGET, &hp_nmparms) != -1) {
            close(hp_fd);
        } else {
            close(hp_fd);
            hp_fd = -1;         /* failed */
        }
    }
#endif
    if_ptr = netsnmp_access_interface_entry_overrides_get(Name);

    switch (vp->magic) {
    case IFINDEX:
        long_return = interface;
        return (u_char *) & long_return;
    case IFDESCR:
#if defined(hpux11)
        cp = ifnet.if_entry.ifDescr;
#else
        if (hp_fd != -1)
            cp = hp_ifEntry.ifDescr;
        else
            cp = Name;
#endif
        *var_len = strlen(cp);
        return (u_char *) cp;
    case NETSNMP_IFTYPE:
        if (if_ptr)
            long_return = if_ptr->type;
        else {
#if defined(hpux11)
        long_return = ifnet.if_entry.ifType;
#else
        if (hp_fd != -1)
            long_return = hp_ifEntry.ifType;
        else
            long_return = 1;    /* OTHER */
#endif
        }
        return (u_char *) & long_return;
    case IFMTU:{
#if defined(hpux11)
            long_return = (long) ifnet.if_entry.ifMtu;
#else
            long_return = (long) ifnet.if_mtu;
#endif
            return (u_char *) & long_return;
        }
    case IFSPEED:
        if (if_ptr)
            long_return = if_ptr->speed;
        else {
#if defined(hpux11)
        long_return = ifnet.if_entry.ifSpeed;
#else
        if (hp_fd != -1)
            long_return = hp_ifEntry.ifSpeed;
        else
            long_return = (u_long) 1;   /* OTHER */
#endif
        }
        return (u_char *) & long_return;
    case IFPHYSADDRESS:
#if defined(hpux11)
        *var_len = ifnet.if_entry.ifPhysAddress.o_length;
        return (u_char *) ifnet.if_entry.ifPhysAddress.o_bytes;
#else
        Interface_Get_Ether_By_Index(interface, return_buf);
        if ((return_buf[0] == 0) && (return_buf[1] == 0) &&
            (return_buf[2] == 0) && (return_buf[3] == 0) &&
            (return_buf[4] == 0) && (return_buf[5] == 0))
            *var_len = 0;
        else
            *var_len = 6;
        return (u_char *) return_buf;
#endif
    case IFADMINSTATUS:
#if defined(hpux11)
        long_return = ifnet.if_entry.ifAdmin;
#else
        long_return = ifnet.if_flags & IFF_UP ? 1 : 2;
#endif
        return (u_char *) & long_return;
    case IFOPERSTATUS:
#if defined(hpux11)
        long_return = ifnet.if_entry.ifOper;
#else
        long_return = ifnet.if_flags & IFF_RUNNING ? 1 : 2;
#endif
        return (u_char *) & long_return;
    case IFLASTCHANGE:
#if defined(hpux11)
        long_return = ifnet.if_entry.ifLastChange;
#else
        if (hp_fd != -1)
            long_return = hp_ifEntry.ifLastChange;
        else
            long_return = 0;    /* XXX */
#endif
        return (u_char *) & long_return;
    case IFINOCTETS:
#if defined(hpux11)
        long_return = ifnet.if_entry.ifInOctets;
#else
        if (hp_fd != -1)
            long_return = hp_ifEntry.ifInOctets;
        else
            long_return = (u_long) ifnet.if_ipackets * 308;     /* XXX */
#endif
        return (u_char *) & long_return;
    case IFINUCASTPKTS:
#if defined(hpux11)
        long_return = ifnet.if_entry.ifInUcastPkts;
#else
        if (hp_fd != -1)
            long_return = hp_ifEntry.ifInUcastPkts;
        else
            long_return = (u_long) ifnet.if_ipackets;
#endif
        return (u_char *) & long_return;
    case IFINNUCASTPKTS:
#if defined(hpux11)
        long_return = ifnet.if_entry.ifInNUcastPkts;
#else
        if (hp_fd != -1)
            long_return = hp_ifEntry.ifInNUcastPkts;
        else
            long_return = (u_long) 0;   /* XXX */
#endif
        return (u_char *) & long_return;
    case IFINDISCARDS:
#if defined(hpux11)
        long_return = ifnet.if_entry.ifInDiscards;
#else
        if (hp_fd != -1)
            long_return = hp_ifEntry.ifInDiscards;
        else
            long_return = (u_long) 0;   /* XXX */
#endif
        return (u_char *) & long_return;
    case IFINERRORS:
#if defined(hpux11)
        long_return = ifnet.if_entry.ifInErrors;
#else
        long_return = ifnet.if_ierrors;
#endif
        return (u_char *) & long_return;
    case IFINUNKNOWNPROTOS:
#if defined(hpux11)
        long_return = ifnet.if_entry.ifInUnknownProtos;
#else
        if (hp_fd != -1)
            long_return = hp_ifEntry.ifInUnknownProtos;
        else
            long_return = (u_long) 0;   /* XXX */
#endif
        return (u_char *) & long_return;
    case IFOUTOCTETS:
#if defined(hpux11)
        long_return = ifnet.if_entry.ifOutOctets;
#else
        if (hp_fd != -1)
            long_return = hp_ifEntry.ifOutOctets;
        else
            long_return = (u_long) ifnet.if_opackets * 308;     /* XXX */
#endif
        return (u_char *) & long_return;
    case IFOUTUCASTPKTS:
#if defined(hpux11)
        long_return = ifnet.if_entry.ifOutUcastPkts;
#else
        if (hp_fd != -1)
            long_return = hp_ifEntry.ifOutUcastPkts;
        else
            long_return = (u_long) ifnet.if_opackets;
#endif
        return (u_char *) & long_return;
    case IFOUTNUCASTPKTS:
#if defined(hpux11)
        long_return = ifnet.if_entry.ifOutNUcastPkts;
#else
        if (hp_fd != -1)
            long_return = hp_ifEntry.ifOutNUcastPkts;
        else
            long_return = (u_long) 0;   /* XXX */
#endif
        return (u_char *) & long_return;
    case IFOUTDISCARDS:
#if defined(hpux11)
        long_return = ifnet.if_entry.ifOutDiscards;
#else
        long_return = ifnet.if_snd.ifq_drops;
#endif
        return (u_char *) & long_return;
    case IFOUTERRORS:
#if defined(hpux11)
        long_return = ifnet.if_entry.ifOutErrors;
#else
        long_return = ifnet.if_oerrors;
#endif
        return (u_char *) & long_return;
    case IFOUTQLEN:
#if defined(hpux11)
        long_return = ifnet.if_entry.ifOutQlen;
#else
        long_return = ifnet.if_snd.ifq_len;
#endif
        return (u_char *) & long_return;
    case IFSPECIFIC:
        *var_len = nullOidLen;
        return (u_char *) nullOid;
    default:
        DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ifEntry\n",
                    vp->magic));
    }
    return NULL;
}

#endif                          /* hpux */
#else                           /* solaris2 */

static int
IF_cmp(void *addr, void *ep)
{
    DEBUGMSGTL(("mibII/interfaces", "... IF_cmp %d %d\n",
                ((mib2_ifEntry_t *) ep)->ifIndex,
                ((mib2_ifEntry_t *) addr)->ifIndex));
    if (((mib2_ifEntry_t *) ep)->ifIndex ==
        ((mib2_ifEntry_t *) addr)->ifIndex)
        return (0);
    else
        return (1);
}

u_char         *
var_ifEntry(struct variable * vp,
            oid * name,
            size_t * length,
            int exact, size_t * var_len, WriteMethod ** write_method)
{
    int             interface;
    mib2_ifEntry_t  ifstat;
    conf_if_list   *if_ptr = NULL;

    interface =
        header_ifEntry(vp, name, length, exact, var_len, write_method);
    if (interface == MATCH_FAILED)
        return NULL;

    if (getMibstat(MIB_INTERFACES, &ifstat, sizeof(mib2_ifEntry_t),
                   GET_EXACT, &IF_cmp, &interface) != 0) {
        DEBUGMSGTL(("mibII/interfaces", "... no mib stats\n"));
        return NULL;
    }
    /*
     * hmmm.. where to get the interface name to check overrides?
     *
     * if_ptr = netsnmp_access_interface_entry_overrides_get(Name);
     */
    switch (vp->magic) {
    case IFINDEX:
        long_return = ifstat.ifIndex;
        return (u_char *) & long_return;
    case IFDESCR:
        *var_len = ifstat.ifDescr.o_length;
        (void) memcpy(return_buf, ifstat.ifDescr.o_bytes, *var_len);
        return (u_char *) return_buf;
    case NETSNMP_IFTYPE:
        if (if_ptr)
            long_return = if_ptr->type;
        else
        long_return = (u_long) ifstat.ifType;
        return (u_char *) & long_return;
    case IFMTU:
        long_return = (u_long) ifstat.ifMtu;
        return (u_char *) & long_return;
    case IFSPEED:
        if (if_ptr)
            long_return = if_ptr->speed;
        else
        long_return = (u_long) ifstat.ifSpeed;
        return (u_char *) & long_return;
    case IFPHYSADDRESS:
        *var_len = ifstat.ifPhysAddress.o_length;
        (void) memcpy(return_buf, ifstat.ifPhysAddress.o_bytes, *var_len);
        return (u_char *) return_buf;
    case IFADMINSTATUS:
        long_return = (u_long) ifstat.ifAdminStatus;
        return (u_char *) & long_return;
    case IFOPERSTATUS:
        long_return = (u_long) ifstat.ifOperStatus;
        return (u_char *) & long_return;
    case IFLASTCHANGE:
        long_return = (u_long) ifstat.ifLastChange;
        return (u_char *) & long_return;
    case IFINOCTETS:
        long_return = (u_long) ifstat.ifInOctets;
        return (u_char *) & long_return;
    case IFINUCASTPKTS:
        long_return = (u_long) ifstat.ifInUcastPkts;
        return (u_char *) & long_return;
    case IFINNUCASTPKTS:
        long_return = (u_long) ifstat.ifInNUcastPkts;
        return (u_char *) & long_return;
    case IFINDISCARDS:
        long_return = (u_long) ifstat.ifInDiscards;
        return (u_char *) & long_return;
    case IFINERRORS:
        long_return = (u_long) ifstat.ifInErrors;
        return (u_char *) & long_return;
    case IFINUNKNOWNPROTOS:
        long_return = (u_long) ifstat.ifInUnknownProtos;
        return (u_char *) & long_return;
    case IFOUTOCTETS:
        long_return = (u_long) ifstat.ifOutOctets;
        return (u_char *) & long_return;
    case IFOUTUCASTPKTS:
        long_return = (u_long) ifstat.ifOutUcastPkts;
        return (u_char *) & long_return;
    case IFOUTNUCASTPKTS:
        long_return = (u_long) ifstat.ifOutNUcastPkts;
        return (u_char *) & long_return;
    case IFOUTDISCARDS:
        long_return = (u_long) ifstat.ifOutDiscards;
        return (u_char *) & long_return;
    case IFOUTERRORS:
        long_return = (u_long) ifstat.ifOutErrors;
        return (u_char *) & long_return;
    case IFOUTQLEN:
        long_return = (u_long) ifstat.ifOutQLen;
        return (u_char *) & long_return;
    case IFSPECIFIC:
	long_return = (u_long) ifstat.ifSpecific;
	return (u_char *) & long_return;
    default:
        DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ifEntry\n",
                    vp->magic));
    }
    return NULL;
}

#endif                          /* solaris2 */



        /*********************
	 *
	 *  Internal implementation functions
	 *
	 *********************/


#ifndef solaris2

#if !defined(sunV3) && !defined(linux) && !defined(hpux11)
static struct in_ifaddr savein_ifaddr;
#endif
#if !defined(hpux11)
static struct ifnet *ifnetaddr, saveifnet, *saveifnetaddr;
static char     saveName[16];
#endif
static int      saveIndex = 0;

/**
* Determines network interface speed. It is system specific. Only linux
* realization is made. 
*/
unsigned int getIfSpeed(int fd, struct ifreq ifr, unsigned int defaultspeed)
{
#ifdef linux
    /** temporary expose internal until this module can be re-written */
    extern unsigned int
        netsnmp_linux_interface_get_if_speed(int fd, const char *name,
                unsigned long long defaultspeed);

    return netsnmp_linux_interface_get_if_speed(fd, ifr.ifr_name, defaultspeed);
#else /*!linux*/			   
    return defaultspeed;
#endif 
}

void
Interface_Scan_Init(void)
{
#ifdef linux
    char            line[256], ifname_buf[64], *ifname, *ptr;
    struct ifreq    ifrq;
    struct ifnet  **ifnetaddr_ptr;
    FILE           *devin;
    int             i, fd;
    conf_if_list   *if_ptr;
    /*
     * scanline_2_2:
     *  [               IN                        ]
     *   byte pkts errs drop fifo frame cmprs mcst |
     *  [               OUT                               ]
     *   byte pkts errs drop fifo colls carrier compressed
     */
#ifdef SCNuMAX
    uintmax_t       rec_pkt, rec_oct, rec_err, rec_drop;
    uintmax_t       snd_pkt, snd_oct, snd_err, snd_drop, coll;
    const char     *scan_line_2_2 =
        "%"   SCNuMAX " %"  SCNuMAX " %"  SCNuMAX " %"  SCNuMAX
        " %*" SCNuMAX " %*" SCNuMAX " %*" SCNuMAX " %*" SCNuMAX
        " %"  SCNuMAX " %"  SCNuMAX " %"  SCNuMAX " %"  SCNuMAX
        " %*" SCNuMAX " %"  SCNuMAX;
    const char     *scan_line_2_0 =
        "%"   SCNuMAX " %"  SCNuMAX " %*" SCNuMAX " %*" SCNuMAX
        " %*" SCNuMAX " %"  SCNuMAX " %"  SCNuMAX " %*" SCNuMAX
        " %*" SCNuMAX " %"  SCNuMAX;
#else
    unsigned long   rec_pkt, rec_oct, rec_err, rec_drop;
    unsigned long   snd_pkt, snd_oct, snd_err, snd_drop, coll;
    const char     *scan_line_2_2 =
        "%lu %lu %lu %lu %*lu %*lu %*lu %*lu %lu %lu %lu %lu %*lu %lu";
    const char     *scan_line_2_0 =
        "%lu %lu %*lu %*lu %*lu %lu %lu %*lu %*lu %lu";
#endif
    const char     *scan_line_to_use;
    struct timeval et;                              /* elapsed time */

#endif

#if !defined(hpux11) && defined(IFNET_SYMBOL)
    auto_nlist(IFNET_SYMBOL, (char *) &ifnetaddr, sizeof(ifnetaddr));
#endif
    saveIndex = 0;


#ifdef linux
    /*  disallow reloading of structures too often */
    gettimeofday ( &et, ( struct timezone * ) 0 );  /*  get time-of-day */
    if ( et.tv_sec < LastLoad + MINLOADFREQ ) {     /*  only reload so often */
      ifnetaddr = ifnetaddr_list;                   /*  initialize pointer */
      return;
    }
    LastLoad = et.tv_sec;

    /*
     * free old list: 
     */
    while (ifnetaddr_list) {
        struct ifnet   *old = ifnetaddr_list;
        ifnetaddr_list = ifnetaddr_list->if_next;
        free(old->if_name);
        free(old->if_unit);
        free(old);
    }

    ifnetaddr = 0;
    ifnetaddr_ptr = &ifnetaddr_list;

    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        DEBUGMSGTL(("snmpd",
                    "socket open failure in Interface_Scan_Init\n"));
        return; /** exit (1); **/
    }

    /*
     * build up ifnetaddr list by hand: 
     */

    /*
     * at least linux v1.3.53 says EMFILE without reason... 
     */
    if (!(devin = fopen("/proc/net/dev", "r"))) {
        close(fd);
        snmp_log(LOG_ERR, "cannot open /proc/net/dev - continuing...\n");
        return; /** exit (1); **/
    }

    i = 0;

    /*
     * read the second line (a header) and determine the fields we
     * should read from.  This should be done in a better way by
     * actually looking for the field names we want.  But thats too
     * much work for today.  -- Wes 
     */
    fgets(line, sizeof(line), devin);
    fgets(line, sizeof(line), devin);
    if (strstr(line, "compressed")) {
        scan_line_to_use = scan_line_2_2;
        DEBUGMSGTL(("mibII/interfaces",
                    "using linux 2.2 kernel /proc/net/dev\n"));
    } else {
        scan_line_to_use = scan_line_2_0;
        DEBUGMSGTL(("mibII/interfaces",
                    "using linux 2.0 kernel /proc/net/dev\n"));
    }


    while (fgets(line, sizeof(line), devin)) {
        struct ifnet   *nnew;
        char           *stats, *ifstart = line;

        if (line[strlen(line) - 1] == '\n')
            line[strlen(line) - 1] = '\0';

        while (*ifstart && *ifstart == ' ')
            ifstart++;

        if (!*ifstart || ((stats = strrchr(ifstart, ':')) == NULL)) {
            snmp_log(LOG_ERR,
                     "/proc/net/dev data format error, line ==|%s|", line);
            continue;
        }
        if ((scan_line_to_use == scan_line_2_2) && ((stats - line) < 6)) {
            snmp_log(LOG_ERR,
                     "/proc/net/dev data format error, line ==|%s|", line);
        }

        *stats   = 0;
        strncpy(ifname_buf, ifstart, sizeof(ifname_buf));
        ifname_buf[ sizeof(ifname_buf)-1 ] = 0;
        *stats++ = ':';
        while (*stats == ' ')
            stats++;

        if ((scan_line_to_use == scan_line_2_2 &&
             sscanf(stats, scan_line_to_use, &rec_oct, &rec_pkt, &rec_err,
                    &rec_drop, &snd_oct, &snd_pkt, &snd_err, &snd_drop,
                    &coll) != 9) || (scan_line_to_use == scan_line_2_0
                                     && sscanf(stats, scan_line_to_use,
                                               &rec_pkt, &rec_err,
                                               &snd_pkt, &snd_err,
                                               &coll) != 5)) {
            if ((scan_line_to_use == scan_line_2_2)
                && !strstr(line, "No statistics available"))
                snmp_log(LOG_ERR,
                         "/proc/net/dev data format error, line ==|%s|",
                         line);
            continue;
        }

        nnew = (struct ifnet *) calloc(1, sizeof(struct ifnet));
        if (nnew == NULL)
            break;              /* alloc error */

        /*
         * chain in: 
         */
        *ifnetaddr_ptr = nnew;
        ifnetaddr_ptr = &nnew->if_next;
        i++;

        /*
         * linux previous to 1.3.~13 may miss transmitted loopback pkts: 
         */
        if (!strcmp(ifname_buf, "lo") && rec_pkt > 0 && !snd_pkt)
            snd_pkt = rec_pkt;

        nnew->if_ipackets = rec_pkt & 0xffffffff;
        nnew->if_ierrors = rec_err;
        nnew->if_opackets = snd_pkt & 0xffffffff;
        nnew->if_oerrors = snd_err;
        nnew->if_collisions = coll;
        if (scan_line_to_use == scan_line_2_2) {
            nnew->if_ibytes = rec_oct & 0xffffffff;
            nnew->if_obytes = snd_oct & 0xffffffff;
            nnew->if_iqdrops = rec_drop;
            nnew->if_snd.ifq_drops = snd_drop;
        } else {
            nnew->if_ibytes = (rec_pkt * 308) & 0xffffffff;
            nnew->if_obytes = (snd_pkt * 308) & 0xffffffff;
        }

        /*
         * ifnames are given as ``   eth0'': split in ``eth'' and ``0'': 
         */
        for (ifname = ifname_buf; *ifname && *ifname == ' '; ifname++);

        /*
         * set name and interface# : 
         */
        nnew->if_name = (char *) strdup(ifname);
        for (ptr = nnew->if_name; *ptr && (*ptr < '0' || *ptr > '9');
             ptr++);
        nnew->if_unit = strdup(*ptr ? ptr : "");
        *ptr = 0;

        strncpy(ifrq.ifr_name, ifname, sizeof(ifrq.ifr_name));
        ifrq.ifr_name[ sizeof(ifrq.ifr_name)-1 ] = 0;
        if (ioctl(fd, SIOCGIFADDR, &ifrq) < 0)
            memset((char *) &nnew->if_addr, 0, sizeof(nnew->if_addr));
        else
            nnew->if_addr = ifrq.ifr_addr;

        strncpy(ifrq.ifr_name, ifname, sizeof(ifrq.ifr_name));
        ifrq.ifr_name[ sizeof(ifrq.ifr_name)-1 ] = 0;
        if (ioctl(fd, SIOCGIFBRDADDR, &ifrq) < 0)
            memset((char *) &nnew->ifu_broadaddr, 0,
                   sizeof(nnew->ifu_broadaddr));
        else
            nnew->ifu_broadaddr = ifrq.ifr_broadaddr;

        strncpy(ifrq.ifr_name, ifname, sizeof(ifrq.ifr_name));
        ifrq.ifr_name[ sizeof(ifrq.ifr_name)-1 ] = 0;
        if (ioctl(fd, SIOCGIFNETMASK, &ifrq) < 0)
            memset((char *) &nnew->ia_subnetmask, 0,
                   sizeof(nnew->ia_subnetmask));
        else
            nnew->ia_subnetmask = ifrq.ifr_netmask;

        strncpy(ifrq.ifr_name, ifname, sizeof(ifrq.ifr_name));
        ifrq.ifr_name[ sizeof(ifrq.ifr_name)-1 ] = 0;
        nnew->if_flags = ioctl(fd, SIOCGIFFLAGS, &ifrq) < 0
            ? 0 : ifrq.ifr_flags;

        nnew->if_type = 0;

        /*
         * NOTE: this ioctl does not guarantee 6 bytes of a physaddr.
         * In particular, a 'sit0' interface only appears to get back
         * 4 bytes of sa_data.
         */
        memset(ifrq.ifr_hwaddr.sa_data, (0), IFHWADDRLEN);
        strncpy(ifrq.ifr_name, ifname, sizeof(ifrq.ifr_name));
        ifrq.ifr_name[ sizeof(ifrq.ifr_name)-1 ] = 0;
        if (ioctl(fd, SIOCGIFHWADDR, &ifrq) < 0)
            memset(nnew->if_hwaddr, (0), IFHWADDRLEN);
        else {
            memcpy(nnew->if_hwaddr, ifrq.ifr_hwaddr.sa_data, IFHWADDRLEN);

#ifdef ARPHRD_LOOPBACK
            switch (ifrq.ifr_hwaddr.sa_family) {
            case ARPHRD_ETHER:
                nnew->if_type = 6;
                break;
            case ARPHRD_TUNNEL:
            case ARPHRD_TUNNEL6:
#ifdef ARPHRD_IPGRE
            case ARPHRD_IPGRE:
#endif
            case ARPHRD_SIT:
                nnew->if_type = 131;
                break;          /* tunnel */
            case ARPHRD_SLIP:
            case ARPHRD_CSLIP:
            case ARPHRD_SLIP6:
            case ARPHRD_CSLIP6:
                nnew->if_type = 28;
                break;          /* slip */
            case ARPHRD_PPP:
                nnew->if_type = 23;
                break;          /* ppp */
            case ARPHRD_LOOPBACK:
                nnew->if_type = 24;
                break;          /* softwareLoopback */
            case ARPHRD_FDDI:
                nnew->if_type = 15;
                break;
            case ARPHRD_ARCNET:
                nnew->if_type = 35;
                break;
            case ARPHRD_LOCALTLK:
                nnew->if_type = 42;
                break;
#ifdef ARPHRD_HIPPI
            case ARPHRD_HIPPI:
                nnew->if_type = 47;
                break;
#endif
#ifdef ARPHRD_ATM
            case ARPHRD_ATM:
                nnew->if_type = 37;
                break;
#endif
                /*
                 * XXX: more if_arp.h:ARPHDR_xxx to IANAifType mappings... 
                 */
            }
#endif
        }

        strncpy(ifrq.ifr_name, ifname, sizeof(ifrq.ifr_name));
        ifrq.ifr_name[ sizeof(ifrq.ifr_name)-1 ] = 0;
        nnew->if_metric = ioctl(fd, SIOCGIFMETRIC, &ifrq) < 0
            ? 0 : ifrq.ifr_metric;

#ifdef SIOCGIFMTU
        strncpy(ifrq.ifr_name, ifname, sizeof(ifrq.ifr_name));
        ifrq.ifr_name[ sizeof(ifrq.ifr_name)-1 ] = 0;
        nnew->if_mtu = (ioctl(fd, SIOCGIFMTU, &ifrq) < 0)
            ? 0 : ifrq.ifr_mtu;
#else
        nnew->if_mtu = 0;
#endif

        if_ptr = netsnmp_access_interface_entry_overrides_get(ifname);
        if (if_ptr) {
            nnew->if_type = if_ptr->type;
            nnew->if_speed = if_ptr->speed;
        } else {
            /*
             * do only guess if_type from name, if we could not read
             * * it before from SIOCGIFHWADDR 
             */
            unsigned int defaultspeed = NOMINAL_LINK_SPEED;
                if (!(nnew->if_flags & IFF_RUNNING)) {
                    /* 
                     * use speed 0 if the if speed cannot be determined *and* the
                     * interface is down
                     */
                    defaultspeed = 0;
                }

            if (!nnew->if_type)
                nnew->if_type = if_type_from_name(nnew->if_name);
            switch(nnew->if_type) {
            case 6:
                nnew->if_speed = getIfSpeed(fd, ifrq, defaultspeed);
                break;
            case 24:
                nnew->if_speed = 10000000;
                break;
            case 9:
                nnew->if_speed = 4000000;
                break;
            default:
                nnew->if_speed = 0;
            }
            /*Zero speed means link problem*/
            if(nnew->if_speed == 0 && nnew->if_flags & IFF_UP){
                nnew->if_flags &= ~IFF_RUNNING;
            }
        }

    }                           /* while (fgets ... */

    ifnetaddr = ifnetaddr_list;

    if (snmp_get_do_debugging()) {
        {
            struct ifnet   *x = ifnetaddr;
            DEBUGMSGTL(("mibII/interfaces", "* see: known interfaces:"));
            while (x) {
                DEBUGMSG(("mibII/interfaces", " %s", x->if_name));
                x = x->if_next;
            }
            DEBUGMSG(("mibII/interfaces", "\n"));
        }                       /* XXX */
    }

    fclose(devin);
    close(fd);
#endif                          /* linux */
}



#if defined(sunV3) || defined(linux)
/*
 * **  4.2 BSD doesn't have ifaddr
 * **  
 */
int
Interface_Scan_Next(short *Index,
                    char *Name,
                    struct ifnet *Retifnet, struct in_ifaddr *dummy)
{
    struct ifnet    ifnet;
    register char  *cp;

    while (ifnetaddr) {
        /*
         *      Get the "ifnet" structure and extract the device name
         */
#ifndef linux
        if (!NETSNMP_KLOOKUP(ifnetaddr, (char *) &ifnet, sizeof ifnet)) {
            DEBUGMSGTL(("mibII/interfaces:Interface_Scan_Next", "klookup failed\n"));
            break;
        }

        if (!NETSNMP_KLOOKUP(ifnet.if_name, (char *) saveName, sizeof saveName)) {
            DEBUGMSGTL(("mibII/interfaces:Interface_Scan_Next", "klookup failed\n"));
            break;
        }

       /*
        * The purpose of this comparison is lost in the mists of time.
        * It's been around at least cmu-snmp 2.1.2 for SUNv3 systems and
        * was applied to linux systems during the cmu-snmp-linux project.
        * No-one now knows what it was intended for, and it breaks IPv6
        * tunnel interfaces, so it's been moved out of the Linux code block.
        */
        if (strcmp(saveName, "ip") == 0) {
            ifnetaddr = ifnet.if_next;
            continue;
        }
#else
        ifnet = *ifnetaddr;
        strncpy(saveName, ifnet.if_name, sizeof(saveName));
#endif

        saveName[sizeof(saveName) - 1] = '\0';
        cp = (char *) strchr(saveName, '\0');
#ifdef linux
        strncat(cp, ifnet.if_unit, sizeof(saveName)-strlen(saveName)-1);
        saveName[sizeof(saveName) - 1] = '\0';
#else
        string_append_int(cp, ifnet.if_unit);
#endif
        if (1 || strcmp(saveName, "lo0") != 0) {        /* XXX */

            if (Index)
                *Index = ++saveIndex;
            if (Retifnet)
                *Retifnet = ifnet;
            if (Name)
                strcpy(Name, saveName);
            saveifnet = ifnet;
            saveifnetaddr = ifnetaddr;
            ifnetaddr = ifnet.if_next;

            return (1);         /* DONE */
        }
        ifnetaddr = ifnet.if_next;
    }
    return (0);                 /* EOF */
}

#ifdef linux
int
Interface_Index_By_Name(char *Name, int Len)
{
    short           ifIndex = 0;
    char            ifName[20];

    Interface_Scan_Init();
    while (Interface_Scan_Next(&ifIndex, ifName, NULL, NULL)
           && strcmp(Name, ifName));
    return ifIndex;
}
#endif


#else                           /* sunV3 || linux */

#if defined(netbsd1) || defined(openbsd2)
#define ia_next ia_list.tqe_next
#define if_next if_list.tqe_next
#endif

#if defined(hpux11)

int
Interface_Scan_Next(short *Index, char *Name, nmapi_phystat * Retifnet)
{
    static nmapi_phystat *if_ptr = (nmapi_phystat *) 0;
    int             count = Interface_Scan_Get_Count();
    unsigned int    ulen;
    int             ret;

    if (!if_ptr) {
        if (count)
            if_ptr =
                (nmapi_phystat *) malloc(sizeof(nmapi_phystat) * count);
        else
            return (0);         /* EOF */
    }

    if (saveIndex >= count)
        return (0);             /* EOF */

    ulen = (unsigned int) count *sizeof(nmapi_phystat);
    if ((ret = get_physical_stat(if_ptr, &ulen)) < 0)
        return (0);             /* EOF */

    if (Retifnet)
        *Retifnet = if_ptr[saveIndex];
    if (Name)
        strcpy(Name, if_ptr[saveIndex].nm_device);
    saveIndex++;
    if (Index)
        *Index = saveIndex;
    return (1);                 /* DONE */
}

#else                           /* hpux11 */

int
Interface_Scan_Next(short *Index,
                    char *Name,
                    struct ifnet *Retifnet, struct in_ifaddr *Retin_ifaddr)
{
    struct ifnet    ifnet;
    struct in_ifaddr *ia, in_ifaddr;
    short           has_ipaddr = 0;
#if !STRUCT_IFNET_HAS_IF_XNAME
    register char  *cp;
#endif

    while (ifnetaddr) {
        /*
         *      Get the "ifnet" structure and extract the device name
         */
        if (!NETSNMP_KLOOKUP(ifnetaddr, (char *) &ifnet, sizeof ifnet)) {
            DEBUGMSGTL(("mibII/interfaces:Interface_Scan_Next", "klookup failed\n"));
            break;
        }
#if STRUCT_IFNET_HAS_IF_XNAME
#if defined(netbsd1) || defined(openbsd2)
        strncpy(saveName, ifnet.if_xname, sizeof saveName);
#else
        if (!NETSNMP_KLOOKUP(ifnet.if_xname, (char *) saveName, sizeof saveName)) {
            DEBUGMSGTL(("mibII/interfaces:Interface_Scan_Next", "klookup failed\n"));
            break;
        }
#endif
        saveName[sizeof(saveName) - 1] = '\0';
#else
        if (!NETSNMP_KLOOKUP(ifnet.if_name, (char *) saveName, sizeof saveName)) {
            DEBUGMSGTL(("mibII/interfaces:Interface_Scan_Next", "klookup failed\n"));
            break;
        }

        saveName[sizeof(saveName) - 1] = '\0';
        cp = strchr(saveName, '\0');
        string_append_int(cp, ifnet.if_unit);
#endif
        if (1 || strcmp(saveName, "lo0") != 0) {        /* XXX */
            /*
             *  Try to find an address for this interface
             */

#ifdef netbsd1
            ia = (struct in_ifaddr *) ifnet.if_addrlist.tqh_first;
#elif defined(IFADDR_SYMBOL)
            auto_nlist(IFADDR_SYMBOL, (char *) &ia, sizeof(ia));
#endif
            while (ia) {
                if (!NETSNMP_KLOOKUP(ia, (char *) &in_ifaddr, sizeof(in_ifaddr))) {
                    DEBUGMSGTL(("mibII/interfaces:Interface_Scan_Next", "klookup failed\n"));
                    break;
                }
                {
#ifdef netbsd1
#define CP(x)	((char *)(x))
                    char           *cp;
                    struct sockaddr *sa;
                    cp = (CP(in_ifaddr.ia_ifa.ifa_addr) - CP(ia)) +
                        CP(&in_ifaddr);
                    sa = (struct sockaddr *) cp;

                    if (sa->sa_family == AF_INET)
#endif
                        if (in_ifaddr.ia_ifp == ifnetaddr) {
                            has_ipaddr = 1;     /* this IF has IP-address */
                            break;
                        }
                }
#ifdef netbsd1
                ia = (struct in_ifaddr *) in_ifaddr.ia_ifa.ifa_list.
                    tqe_next;
#else
                ia = in_ifaddr.ia_next;
#endif
            }

#if !defined(netbsd1) && !defined(freebsd2) && !defined(openbsd2) && !defined(STRUCT_IFNET_HAS_IF_ADDRLIST)
            ifnet.if_addrlist = (struct ifaddr *) ia;   /* WRONG DATA TYPE; ONLY A FLAG */
#endif
            /*
             * ifnet.if_addrlist = (struct ifaddr *)&ia->ia_ifa;   
             *
             * WRONG DATA TYPE; ONLY A FLAG 
             */

            if (Index)
                *Index = ++saveIndex;
            if (Retifnet)
                *Retifnet = ifnet;
            if (Retin_ifaddr && has_ipaddr)     /* assign the in_ifaddr only
                                                 * if the IF has IP-address */
                *Retin_ifaddr = in_ifaddr;
            if (Name)
                strcpy(Name, saveName);
            saveifnet = ifnet;
            saveifnetaddr = ifnetaddr;
            savein_ifaddr = in_ifaddr;
            ifnetaddr = ifnet.if_next;

            return (1);         /* DONE */
        }
        ifnetaddr = ifnet.if_next;
    }
    return (0);                 /* EOF */
}

#endif                          /* hpux11 */

#endif                          /* sunV3 || linux */

#if defined(hpux11)

static int
Interface_Scan_By_Index(int Index, char *Name, nmapi_phystat * Retifnet)
{
    short           i;

    Interface_Scan_Init();
    while (Interface_Scan_Next(&i, Name, Retifnet)) {
        if (i == Index)
            break;
    }
    if (i != Index)
        return (-1);            /* Error, doesn't exist */
    return (0);                 /* DONE */
}

#else                           /* hpux11 */

static int
Interface_Scan_By_Index(int Index,
                        char *Name,
                        struct ifnet *Retifnet,
                        struct in_ifaddr *Retin_ifaddr)
{
    short           i;

    Interface_Scan_Init();
    while (Interface_Scan_Next(&i, Name, Retifnet, Retin_ifaddr)) {
        if (i == Index)
            break;
    }
    if (i != Index)
        return (-1);            /* Error, doesn't exist */
    return (0);                 /* DONE */
}

#endif                          /* hpux11 */

static int      Interface_Count = 0;

#if defined(hpux11)

int
Interface_Scan_Get_Count(void)
{
    if (!Interface_Count) {
        int             fd;
        struct nmparms  p;
        int             val;
        unsigned int    ulen;
        int             ret;

        if ((fd = open_mib("/dev/ip", O_RDONLY, 0, NM_ASYNC_OFF)) >= 0) {
            p.objid = ID_ifNumber;
            p.buffer = (void *) &val;
            ulen = sizeof(int);
            p.len = &ulen;
            if ((ret = get_mib_info(fd, &p)) == 0)
                Interface_Count = val;
            close_mib(fd);
        }
    }
    return (Interface_Count);
}

#else                           /* hpux11 */

int
Interface_Scan_Get_Count(void)
{
    static time_t   scan_time = 0;
    time_t          time_now = time(NULL);

    if (!Interface_Count || (time_now > scan_time + 60)) {
        scan_time = time_now;
        Interface_Scan_Init();
        Interface_Count = 0;
        while (Interface_Scan_Next(NULL, NULL, NULL, NULL) != 0) {
            Interface_Count++;
        }
    }
    return (Interface_Count);
}


static int
Interface_Get_Ether_By_Index(int Index, u_char * EtherAddr)
{
    short           i;
#if !(defined(linux) || defined(netbsd1) || defined(bsdi2) || defined(openbsd2))
    struct arpcom   arpcom;
#else                           /* is linux or netbsd1 */
    struct arpcom {
        char            ac_enaddr[6];
    } arpcom;
#if defined(netbsd1) || defined(bsdi2) || defined(openbsd2)
    struct sockaddr_dl sadl;
    struct ifaddr   ifaddr;
    u_long          ifaddraddr;
#endif
#endif

#if defined(mips) || defined(hpux) || defined(osf4) || defined(osf3) || defined(osf5)
    memset(arpcom.ac_enaddr, 0, sizeof(arpcom.ac_enaddr));
#else
    memset(&arpcom.ac_enaddr, 0, sizeof(arpcom.ac_enaddr));
#endif
    memset(EtherAddr, 0, sizeof(arpcom.ac_enaddr));

    if (saveIndex != Index) {   /* Optimization! */

        Interface_Scan_Init();

        while (Interface_Scan_Next((short *) &i, NULL, NULL, NULL) != 0) {
            if (i == Index)
                break;
        }
        if (i != Index)
            return (-1);        /* Error, doesn't exist */
    }
#ifdef freebsd2
    if (saveifnet.if_type != IFT_ETHER) {
        return (0);             /* Not an ethernet if */
    }
#endif
    /*
     *  the arpcom structure is an extended ifnet structure which
     *  contains the ethernet address.
     */
#ifndef linux
#if !(defined(netbsd1) || defined(bsdi2) || defined(openbsd2))
    if (!NETSNMP_KLOOKUP(saveifnetaddr, (char *) &arpcom, sizeof arpcom)) {
        DEBUGMSGTL(("mibII/interfaces:Interface_Get_Ether_By_Index", "klookup failed\n"));
        return 0;
    }
#else                           /* netbsd1 or bsdi2 or openbsd2 */

#if defined(netbsd1) || defined(openbsd2)
#define if_addrlist if_addrlist.tqh_first
#define ifa_next    ifa_list.tqe_next
#endif

    ifaddraddr = (unsigned long) saveifnet.if_addrlist;
    while (ifaddraddr) {
        if (!NETSNMP_KLOOKUP(ifaddraddr, (char *) &ifaddr, sizeof ifaddr)) {
            DEBUGMSGTL(("mibII/interfaces:Interface_Get_Ether_By_Index", "klookup failed\n"));
            break;
        }
        if (!NETSNMP_KLOOKUP(ifaddr.ifa_addr, (char *) &sadl, sizeof sadl)) {
            DEBUGMSGTL(("mibII/interfaces:Interface_Get_Ether_By_Index", "klookup failed\n"));
            break;
        }
        if (sadl.sdl_family == AF_LINK
            && (saveifnet.if_type == IFT_ETHER
                || saveifnet.if_type == IFT_ISO88025
                || saveifnet.if_type == IFT_FDDI)) {
            memcpy(arpcom.ac_enaddr, sadl.sdl_data + sadl.sdl_nlen,
                   sizeof(arpcom.ac_enaddr));
            break;
        }
        ifaddraddr = (unsigned long) ifaddr.ifa_next;
    }
#endif                          /* netbsd1 or bsdi2 or openbsd2 */

#else                           /* linux */
    memcpy(arpcom.ac_enaddr, saveifnetaddr->if_hwaddr, 6);
#endif
    if (strncmp("lo", saveName, 2) == 0) {
        /*
         *  Loopback doesn't have a HW addr, so return 00:00:00:00:00:00
         */
        memset(EtherAddr, 0, sizeof(arpcom.ac_enaddr));

    } else {

#if defined(mips) || defined(hpux) || defined(osf4) || defined(osf3)
        memcpy(EtherAddr, (char *) arpcom.ac_enaddr,
               sizeof(arpcom.ac_enaddr));
#else
        memcpy(EtherAddr, (char *) &arpcom.ac_enaddr,
               sizeof(arpcom.ac_enaddr));
#endif


    }
    return (0);                 /* DONE */
}

#endif                          /* hpux11 */

#else                           /* solaris2 */

int
Interface_Scan_Get_Count(void)
{
    int             i, sd;

    if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        return (0);
    if (ioctl(sd, SIOCGIFNUM, &i) == -1) {
        close(sd);
        return (0);
    } else {
        close(sd);
        return (i);
    }
}

int
Interface_Index_By_Name(char *Name, int Len)
{
    return (solaris2_if_nametoindex(Name, Len));
}

#endif                          /* solaris2 */

#else                           /* HAVE_NET_IF_MIB_H */

/*
 * This code attempts to do the right thing for FreeBSD.  Note that
 * the statistics could be gathered through use of of the
 * net.route.0.link.iflist.0 sysctl (which we already use to get the
 * hardware address of the interfaces), rather than using the ifmib
 * code, but eventually I will implement dot3Stats and we will have to
 * use the ifmib interface.  ifmib is also a much more natural way of
 * mapping the SNMP MIB onto sysctl(3).
 */

#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_mib.h>
#include <net/route.h>

static int      header_interfaces(struct variable *, oid *, size_t *, int,
                                  size_t *, WriteMethod ** write);
static int      header_ifEntry(struct variable *, oid *, size_t *, int,
                               size_t *, WriteMethod ** write);
u_char         *var_ifEntry(struct variable *, oid *, size_t *, int,
                            size_t *, WriteMethod ** write);

static char    *physaddrbuf;
static int      nphysaddrs;
struct sockaddr_dl **physaddrs;

void
init_interfaces_setup(void)
{
    int             naddrs, ilen, bit;
    static int      mib[6]
    = { CTL_NET, PF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
    char           *cp;
    size_t          len;
    struct rt_msghdr *rtm;
    struct if_msghdr *ifm;
    struct ifa_msghdr *ifam;
    struct sockaddr *sa;

    DEBUGMSGTL(("mibII:freebsd", "init_interfaces_setup\n"));

    naddrs = 0;
    if (physaddrs)
        free(physaddrs);
    if (physaddrbuf)
        free(physaddrbuf);
    physaddrbuf = 0;
    physaddrs = 0;
    nphysaddrs = 0;
    len = 0;
    if (sysctl(mib, 6, 0, &len, 0, 0) < 0) {
        DEBUGMSGTL(("mibII:freebsd", "sysctl 1 < 0\n"));
        return;
    }

    cp = physaddrbuf = malloc(len);
    if (physaddrbuf == 0)
        return;
    if (sysctl(mib, 6, physaddrbuf, &len, 0, 0) < 0) {
        free(physaddrbuf);
        physaddrbuf = 0;
        DEBUGMSGTL(("mibII:freebsd", "sysctl 2 < 0\n"));
        return;
    }

  loop:
    ilen = len;
    cp = physaddrbuf;
    while (ilen > 0) {
        rtm = (struct rt_msghdr *) cp;
        if (rtm->rtm_version != RTM_VERSION || rtm->rtm_type != RTM_IFINFO) {
            DEBUGMSGTL(("mibII:freebsd", "version:%d/%d type:%d/%d\n",
                        rtm->rtm_version, RTM_VERSION, rtm->rtm_type, RTM_IFINFO));
            free(physaddrs);
            physaddrs = 0;
            free(physaddrbuf);
            physaddrbuf = 0;
        }
        ifm = (struct if_msghdr *) rtm;
#if defined(freebsd3) || defined(freebsd4) || defined(freebsd5)
        if (physaddrs != 0)
            physaddrs[naddrs] = (void *) (ifm + 1);
        naddrs++;
#endif
        ilen -= ifm->ifm_msglen;
        cp += ifm->ifm_msglen;
        rtm = (struct rt_msghdr *) cp;
        while (ilen > 0 && rtm->rtm_type == RTM_NEWADDR) {
#if defined(freebsd3) || defined(freebsd4) || defined(freebsd5)
            ilen -= rtm->rtm_msglen;
            cp += rtm->rtm_msglen;
#else
            int             is_alias = 0;
            ifam = (struct ifa_msghdr *) rtm;
            ilen -= sizeof(*ifam);
            cp += sizeof(*ifam);
            sa = (struct sockaddr *) cp;
#define ROUND(x) (((x) + sizeof(long) - 1) & ~sizeof(long))
            for (bit = 1; bit && ilen > 0; bit <<= 1) {
                if (!(ifam->ifam_addrs & bit))
                    continue;
                ilen -= ROUND(sa->sa_len);
                cp += ROUND(sa->sa_len);

                if (bit == RTA_IFA) {
                    if (physaddrs)
#define satosdl(sa) ((struct sockaddr_dl *)(sa))
                        physaddrs[naddrs++]
                            = satosdl(sa);
                    else
                        naddrs++;
                }
                sa = (struct sockaddr *) cp;
            }
#endif
            rtm = (struct rt_msghdr *) cp;
        }
    }
    DEBUGMSGTL(("mibII:freebsd", "found %d addrs\n", naddrs));
    if (physaddrs) {
        nphysaddrs = naddrs;
        return;
    }
    physaddrs = malloc(naddrs * sizeof(*physaddrs));
    if (physaddrs == 0)
        return;
    naddrs = 0;
    goto loop;

}

static int
get_phys_address(int iindex, char **ap, int *len)
{
    int             i;
    int             once = 1;

    do {
        for (i = 0; i < nphysaddrs; i++) {
            if (physaddrs[i]->sdl_index == iindex)
                break;
        }
        if (i < nphysaddrs)
            break;
        init_interfaces_setup();
    } while (once--);

    DEBUGMSGTL(("mibII:freebsd", "get_phys_address %d/%d\n", i, nphysaddrs));
    if (i < nphysaddrs) {
        *ap = LLADDR(physaddrs[i]);
        *len = physaddrs[i]->sdl_alen;
        return 0;
    }
    return -1;
}

int
Interface_Scan_Get_Count(void)
{
    static int      count_oid[5] = { CTL_NET, PF_LINK, NETLINK_GENERIC,
        IFMIB_SYSTEM, IFMIB_IFCOUNT
    };
    size_t          len;
    int             count;

    len = sizeof count;
    if (sysctl(count_oid, 5, &count, &len, (void *) 0, (size_t) 0) < 0) {
        DEBUGMSGTL(("mibII:freebsd", "Interface_Scan_Get_Count err\n"));
        return -1;
    }
    DEBUGMSGTL(("mibII:freebsd", "Interface_Scan_Get_Count %d\n", count));
    return count;
}


u_char         *
var_ifEntry(struct variable * vp,
            oid * name,
            size_t * length,
            int exact, size_t * var_len, WriteMethod ** write_method)
{
    int             interface;
    static int      sname[6] = { CTL_NET, PF_LINK, NETLINK_GENERIC,
        IFMIB_IFDATA, 0, IFDATA_GENERAL
    };
    static struct ifmibdata ifmd;
    size_t          len;
    char           *cp;
    conf_if_list   *if_ptr = NULL;

    interface = header_ifEntry(vp, name, length, exact, var_len,
                               write_method);
    if (interface == MATCH_FAILED)
        return NULL;

    sname[4] = interface;
    len = sizeof ifmd;
    if (sysctl(sname, 6, &ifmd, &len, 0, 0) < 0) {
        DEBUGMSGTL(("mibII:freebsd", "var_ifEntry sysctl err\n"));
        return NULL;
    }
    /*
     * hmmm.. where to get the interface name to check overrides?
     *
     * if_ptr = netsnmp_access_interface_entry_overrides_get(Name);
     */

    switch (vp->magic) {
    case IFINDEX:
        long_return = interface;
        return (u_char *) & long_return;
    case IFDESCR:
        cp = ifmd.ifmd_name;
        *var_len = strlen(cp);
        return (u_char *) cp;
    case NETSNMP_IFTYPE:
        if (if_ptr)
            long_return = if_ptr->type;
        else
        long_return = ifmd.ifmd_data.ifi_type;
        return (u_char *) & long_return;
    case IFMTU:
        long_return = (long) ifmd.ifmd_data.ifi_mtu;
        return (u_char *) & long_return;
    case IFSPEED:
        if (if_ptr)
            long_return = if_ptr->speed;
        else
        long_return = ifmd.ifmd_data.ifi_baudrate;
        return (u_char *) & long_return;
    case IFPHYSADDRESS:
        {
            char           *cp;
            if (get_phys_address(interface, &cp, var_len))
                return NULL;
            else
                return cp;
        }
    case IFADMINSTATUS:
        long_return = ifmd.ifmd_flags & IFF_UP ? 1 : 2;
        return (u_char *) & long_return;
    case IFOPERSTATUS:
        long_return = ifmd.ifmd_flags & IFF_RUNNING ? 1 : 2;
        return (u_char *) & long_return;
    case IFLASTCHANGE:
        if (ifmd.ifmd_data.ifi_lastchange.tv_sec == 0 &&
            ifmd.ifmd_data.ifi_lastchange.tv_usec == 0) {
            long_return = 0;
        } else if (ifmd.ifmd_data.ifi_lastchange.tv_sec < starttime.tv_sec) {
            long_return = 0;
        } else {
            long_return = (u_long)
                ((ifmd.ifmd_data.ifi_lastchange.tv_sec -
                  starttime.tv_sec) * 100 +
                 ((ifmd.ifmd_data.ifi_lastchange.tv_usec -
                   starttime.tv_usec) / 10000));
        }
        return (u_char *) & long_return;
    case IFINOCTETS:
        long_return = (u_long) ifmd.ifmd_data.ifi_ibytes;
        return (u_char *) & long_return;
    case IFINUCASTPKTS:
        long_return = (u_long) ifmd.ifmd_data.ifi_ipackets;
        long_return -= (u_long) ifmd.ifmd_data.ifi_imcasts;
        return (u_char *) & long_return;
    case IFINNUCASTPKTS:
        long_return = (u_long) ifmd.ifmd_data.ifi_imcasts;
        return (u_char *) & long_return;
    case IFINDISCARDS:
        long_return = (u_long) ifmd.ifmd_data.ifi_iqdrops;
        return (u_char *) & long_return;
    case IFINERRORS:
        long_return = ifmd.ifmd_data.ifi_ierrors;
        return (u_char *) & long_return;
    case IFINUNKNOWNPROTOS:
        long_return = (u_long) ifmd.ifmd_data.ifi_noproto;
        return (u_char *) & long_return;
    case IFOUTOCTETS:
        long_return = (u_long) ifmd.ifmd_data.ifi_obytes;
        return (u_char *) & long_return;
    case IFOUTUCASTPKTS:
        long_return = (u_long) ifmd.ifmd_data.ifi_opackets;
        long_return -= (u_long) ifmd.ifmd_data.ifi_omcasts;
        return (u_char *) & long_return;
    case IFOUTNUCASTPKTS:
        long_return = (u_long) ifmd.ifmd_data.ifi_omcasts;
        return (u_char *) & long_return;
    case IFOUTDISCARDS:
        long_return = ifmd.ifmd_snd_drops;
        return (u_char *) & long_return;
    case IFOUTERRORS:
        long_return = ifmd.ifmd_data.ifi_oerrors;
        return (u_char *) & long_return;
    case IFOUTQLEN:
        long_return = ifmd.ifmd_snd_len;
        return (u_char *) & long_return;
    case IFSPECIFIC:
        *var_len = nullOidLen;
        return (u_char *) nullOid;
    default:
        DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ifEntry\n",
                    vp->magic));
    }
    return NULL;
}

#endif                          /* HAVE_NET_IF_MIB_H */
#endif                          /* !USE_SYSCTL_IFLIST */

#else                           /* WIN32 cygwin */
#include <iphlpapi.h>

WriteMethod     writeIfEntry;
long            admin_status = 0;
long            oldadmin_status = 0;

static int
header_ifEntry(struct variable *vp,
               oid * name,
               size_t * length,
               int exact, size_t * var_len, WriteMethod ** write_method)
{
#define IFENTRY_NAME_LENGTH	10
    oid             newname[MAX_OID_LEN];
    register int    ifIndex;
    int             result, count;
    DWORD           status = NO_ERROR;
    DWORD           statusRetry = NO_ERROR;
    DWORD           dwActualSize = 0;
    PMIB_IFTABLE    pIfTable = NULL;

    DEBUGMSGTL(("mibII/interfaces", "var_ifEntry: "));
    DEBUGMSGOID(("mibII/interfaces", name, *length));
    DEBUGMSG(("mibII/interfaces", " %d\n", exact));

    memcpy((char *) newname, (char *) vp->name,
           (int) vp->namelen * sizeof(oid));
    /*
     * find "next" ifIndex 
     */


    /*
     * query for buffer size needed 
     */
    status = GetIfTable(pIfTable, &dwActualSize, TRUE);

    if (status == ERROR_INSUFFICIENT_BUFFER) {
        /*
         * need more space 
         */
        pIfTable = (PMIB_IFTABLE) malloc(dwActualSize);
        if (pIfTable != NULL) {
            /*
             * Get the sorted IF table 
             */
            GetIfTable(pIfTable, &dwActualSize, TRUE);
        }
    }
    count = pIfTable->dwNumEntries;
    for (ifIndex = 0; ifIndex < count; ifIndex++) {
        newname[IFENTRY_NAME_LENGTH] =
            (oid) pIfTable->table[ifIndex].dwIndex;
        result =
            snmp_oid_compare(name, *length, newname,
                             (int) vp->namelen + 1);
        if ((exact && (result == 0)) || (!exact && (result < 0)))
            break;
    }
    if (ifIndex >= count) {
        DEBUGMSGTL(("mibII/interfaces", "... index out of range\n"));
        return MATCH_FAILED;
    }


    memcpy((char *) name, (char *) newname,
           ((int) vp->namelen + 1) * sizeof(oid));
    *length = vp->namelen + 1;
    *write_method = 0;
    *var_len = sizeof(long);    /* default to 'long' results */

    DEBUGMSGTL(("mibII/interfaces", "... get I/F stats "));
    DEBUGMSGOID(("mibII/interfaces", name, *length));
    DEBUGMSG(("mibII/interfaces", "\n"));

    count = pIfTable->table[ifIndex].dwIndex;
    free(pIfTable);
    return count;
}



u_char         *
var_interfaces(struct variable * vp,
               oid * name,
               size_t * length,
               int exact, size_t * var_len, WriteMethod ** write_method)
{
    if (header_generic(vp, name, length, exact, var_len, write_method) ==
        MATCH_FAILED)
        return NULL;

    switch (vp->magic) {
    case IFNUMBER:
        GetNumberOfInterfaces(&long_return);
        return (u_char *) & long_return;
    default:
        DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_interfaces\n",
                    vp->magic));
    }
    return NULL;
}

u_char         *
var_ifEntry(struct variable * vp,
            oid * name,
            size_t * length,
            int exact, size_t * var_len, WriteMethod ** write_method)
{
    int             ifIndex;
    static MIB_IFROW ifRow;
    conf_if_list   *if_ptr = NULL;
    
    ifIndex =
        header_ifEntry(vp, name, length, exact, var_len, write_method);
    if (ifIndex == MATCH_FAILED)
        return NULL;
    /*
     * hmmm.. where to get the interface name to check overrides?
     *
     * if_ptr = netsnmp_access_interface_entry_overrides_get(Name);
     */

    /*
     * Get the If Table Row by passing index as argument 
     */
    ifRow.dwIndex = ifIndex;
    if (GetIfEntry(&ifRow) != NO_ERROR)
        return NULL;
    switch (vp->magic) {
    case IFINDEX:
        long_return = ifIndex;
        return (u_char *) & long_return;
    case IFDESCR:
        *var_len = ifRow.dwDescrLen;
        return (u_char *) ifRow.bDescr;
    case NETSNMP_IFTYPE:
        if (if_ptr)
            long_return = if_ptr->type;
        else
        long_return = ifRow.dwType;
        return (u_char *) & long_return;
    case IFMTU:
        long_return = (long) ifRow.dwMtu;
        return (u_char *) & long_return;
    case IFSPEED:
        if (if_ptr)
            long_return = if_ptr->speed;
        else
        long_return = (long) ifRow.dwSpeed;
        return (u_char *) & long_return;
    case IFPHYSADDRESS:
        *var_len = ifRow.dwPhysAddrLen;
        memcpy(return_buf, ifRow.bPhysAddr, *var_len);
        return (u_char *) return_buf;
    case IFADMINSTATUS:
        long_return = ifRow.dwAdminStatus;
        admin_status = long_return;
        *write_method = writeIfEntry;
        return (u_char *) & long_return;
    case IFOPERSTATUS:
        long_return =
           (MIB_IF_OPER_STATUS_OPERATIONAL == ifRow.dwOperStatus) ? 1 : 2;
        return (u_char *) & long_return;
    case IFLASTCHANGE:
        long_return = 0 /* XXX not a UNIX epochal time ifRow.dwLastChange */ ;
        return (u_char *) & long_return;
    case IFINOCTETS:
        long_return = ifRow.dwInOctets;
        return (u_char *) & long_return;
    case IFINUCASTPKTS:
        long_return = ifRow.dwInUcastPkts;
        return (u_char *) & long_return;
    case IFINNUCASTPKTS:
        long_return = ifRow.dwInNUcastPkts;
        return (u_char *) & long_return;
    case IFINDISCARDS:
        long_return = ifRow.dwInDiscards;
        return (u_char *) & long_return;
    case IFINERRORS:
        long_return = ifRow.dwInErrors;
        return (u_char *) & long_return;
    case IFINUNKNOWNPROTOS:
        long_return = ifRow.dwInUnknownProtos;
        return (u_char *) & long_return;
    case IFOUTOCTETS:
        long_return = ifRow.dwOutOctets;
        return (u_char *) & long_return;
    case IFOUTUCASTPKTS:
        long_return = ifRow.dwOutUcastPkts;
        return (u_char *) & long_return;
    case IFOUTNUCASTPKTS:
        long_return = ifRow.dwOutNUcastPkts;
        return (u_char *) & long_return;
    case IFOUTDISCARDS:
        long_return = ifRow.dwOutDiscards;
        return (u_char *) & long_return;
    case IFOUTERRORS:
        long_return = ifRow.dwOutErrors;
        return (u_char *) & long_return;
    case IFOUTQLEN:
        long_return = ifRow.dwOutQLen;
        return (u_char *) & long_return;
    case IFSPECIFIC:
        *var_len = nullOidLen;
        return (u_char *) nullOid;
    default:
        DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ifEntry\n",
                    vp->magic));
    }
    return NULL;
}


int
writeIfEntry(int action,
             u_char * var_val,
             u_char var_val_type,
             size_t var_val_len,
             u_char * statP, oid * name, size_t name_len)
{
    MIB_IFROW       ifEntryRow;
    if ((char) name[9] != IFADMINSTATUS) {
        return SNMP_ERR_NOTWRITABLE;
    }

    switch (action) {
    case RESERVE1:             /* Check values for acceptability */
        if (var_val_type != ASN_INTEGER) {
            snmp_log(LOG_ERR, "not integer\n");
            return SNMP_ERR_WRONGTYPE;
        }
        if (var_val_len > sizeof(int)) {
            snmp_log(LOG_ERR, "bad length\n");
            return SNMP_ERR_WRONGLENGTH;
        }

        /*
         * The dwAdminStatus member can be MIB_IF_ADMIN_STATUS_UP or MIB_IF_ADMIN_STATUS_DOWN 
         */
        if (!(((int) (*var_val) == MIB_IF_ADMIN_STATUS_UP) ||
              ((int) (*var_val) == MIB_IF_ADMIN_STATUS_DOWN))) {
            snmp_log(LOG_ERR, "not supported admin state\n");
            return SNMP_ERR_WRONGVALUE;
        }
        break;

    case RESERVE2:             /* Allocate memory and similar resources */
        break;

    case ACTION:
        /*
         * Save the old value, in case of UNDO 
         */

        oldadmin_status = admin_status;
        admin_status = (int) *var_val;
        break;

    case UNDO:                 /* Reverse the SET action and free resources */
        admin_status = oldadmin_status;
        break;

    case COMMIT:               /* Confirm the SET, performing any irreversible actions,
                                 * and free resources */
        ifEntryRow.dwIndex = (int) name[10];
        ifEntryRow.dwAdminStatus = admin_status;
        /*
         * Only UP and DOWN status are supported. Thats why done in COMMIT 
         */
        if (SetIfEntry(&ifEntryRow) != NO_ERROR) {
            snmp_log(LOG_ERR,
                     "Error in writeIfEntry case COMMIT with index: %d & adminStatus %d\n",
                     ifEntryRow.dwIndex, ifEntryRow.dwAdminStatus);
            return SNMP_ERR_COMMITFAILED;
        }

    case FREE:                 /* Free any resources allocated */
        /*
         * No resources have been allocated 
         */
        break;
    }
    return SNMP_ERR_NOERROR;
}                               /* end of writeIfEntry */
#endif                          /* WIN32 cygwin */
