summaryrefslogtreecommitdiff
path: root/agent/mibgroup/if-mib/data_access
diff options
context:
space:
mode:
Diffstat (limited to 'agent/mibgroup/if-mib/data_access')
-rw-r--r--agent/mibgroup/if-mib/data_access/interface.c873
-rw-r--r--agent/mibgroup/if-mib/data_access/interface.h58
-rw-r--r--agent/mibgroup/if-mib/data_access/interface_ioctl.c506
-rw-r--r--agent/mibgroup/if-mib/data_access/interface_ioctl.h52
-rw-r--r--agent/mibgroup/if-mib/data_access/interface_linux.c1213
-rw-r--r--agent/mibgroup/if-mib/data_access/interface_openbsd.c407
-rw-r--r--agent/mibgroup/if-mib/data_access/interface_solaris2.c363
-rw-r--r--agent/mibgroup/if-mib/data_access/interface_sysctl.c581
-rw-r--r--agent/mibgroup/if-mib/data_access/interface_sysctl.h31
9 files changed, 4084 insertions, 0 deletions
diff --git a/agent/mibgroup/if-mib/data_access/interface.c b/agent/mibgroup/if-mib/data_access/interface.c
new file mode 100644
index 0000000..8cb73e8
--- /dev/null
+++ b/agent/mibgroup/if-mib/data_access/interface.c
@@ -0,0 +1,873 @@
+/*
+ * Interface MIB architecture support
+ *
+ * $Id$
+ */
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-features.h>
+#include <net-snmp/net-snmp-includes.h>
+
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#include <net-snmp/library/snmp_enum.h>
+#include <net-snmp/data_access/interface.h>
+
+#include "mibII/mibII_common.h"
+#include "if-mib/ifTable/ifTable.h"
+#include "if-mib/data_access/interface.h"
+
+netsnmp_feature_child_of(interface_all, libnetsnmpmibs)
+netsnmp_feature_child_of(interface, interface_all)
+netsnmp_feature_child_of(interface_access_entry_set_admin_status, interface_all)
+netsnmp_feature_child_of(interface_legacy, interface_all)
+
+#ifdef NETSNMP_FEATURE_REQUIRE_INTERFACE_ACCESS_ENTRY_SET_ADMIN_STATUS
+netsnmp_feature_require(interface_arch_set_admin_status)
+#endif /* NETSNMP_FEATURE_REQUIRE_INTERFACE_ACCESS_ENTRY_SET_ADMIN_STATUS */
+
+/**---------------------------------------------------------------------*/
+/*
+ * local static vars
+ */
+static netsnmp_conf_if_list *conf_list = NULL;
+static int need_wrap_check = -1;
+static int _access_interface_init = 0;
+
+/*
+ * local static prototypes
+ */
+static int _access_interface_entry_compare_name(const void *lhs,
+ const void *rhs);
+#ifndef NETSNMP_ACCESS_INTERFACE_NOARCH
+static void _access_interface_entry_release(netsnmp_interface_entry * entry,
+ void *unused);
+#endif
+static void _access_interface_entry_save_name(const char *name, oid index);
+static void _parse_interface_config(const char *token, char *cptr);
+static void _free_interface_config(void);
+
+/**---------------------------------------------------------------------*/
+/*
+ * external per-architecture functions prototypes
+ *
+ * These shouldn't be called by the general public, so they aren't in
+ * the header file.
+ */
+#ifndef NETSNMP_ACCESS_INTERFACE_NOARCH
+extern void netsnmp_arch_interface_init(void);
+extern int
+netsnmp_arch_interface_container_load(netsnmp_container* container,
+ u_int load_flags);
+extern int
+netsnmp_arch_set_admin_status(netsnmp_interface_entry * entry,
+ int ifAdminStatus);
+extern int netsnmp_arch_interface_index_find(const char*name);
+#endif
+
+
+/**
+ * initialization
+ */
+void
+init_interface(void)
+{
+ snmpd_register_config_handler("interface", _parse_interface_config,
+ _free_interface_config,
+ "name type speed");
+}
+
+
+void
+netsnmp_access_interface_init(void)
+{
+ netsnmp_assert(0 == _access_interface_init); /* who is calling twice? */
+
+ if (1 == _access_interface_init)
+ return;
+
+ _access_interface_init = 1;
+
+#ifndef NETSNMP_ACCESS_INTERFACE_NOARCH
+ {
+ netsnmp_container * ifcontainer;
+
+ netsnmp_arch_interface_init();
+
+ /*
+ * load once to set up ifIndexes
+ */
+ ifcontainer = netsnmp_access_interface_container_load(NULL, 0);
+ if(NULL != ifcontainer)
+ netsnmp_access_interface_container_free(ifcontainer, 0);
+ }
+#endif
+}
+
+/**---------------------------------------------------------------------*/
+/*
+ * container functions
+ */
+/**
+ * initialize interface container
+ */
+netsnmp_container *
+netsnmp_access_interface_container_init(u_int flags)
+{
+ netsnmp_container *container1;
+
+ DEBUGMSGTL(("access:interface:container", "init\n"));
+
+ /*
+ * create the containers. one indexed by ifIndex, the other
+ * indexed by ifName.
+ */
+ container1 = netsnmp_container_find("access_interface:table_container");
+ if (NULL == container1)
+ return NULL;
+
+ container1->container_name = strdup("interface container");
+ if (flags & NETSNMP_ACCESS_INTERFACE_INIT_ADDL_IDX_BY_NAME) {
+ netsnmp_container *container2 =
+ netsnmp_container_find("access_interface_by_name:access_interface:table_container");
+ if (NULL == container2)
+ return NULL;
+
+ container2->container_name = strdup("interface name container");
+ container2->compare = _access_interface_entry_compare_name;
+
+ netsnmp_container_add_index(container1, container2);
+ }
+
+ return container1;
+}
+
+/**
+ * load interface information in specified container
+ *
+ * @param container empty container, or NULL to have one created for you
+ * @param load_flags flags to modify behaviour. Examples:
+ * NETSNMP_ACCESS_INTERFACE_INIT_ADDL_IDX_BY_NAME
+ *
+ * @retval NULL error
+ * @retval !NULL pointer to container
+ */
+#ifndef NETSNMP_ACCESS_INTERFACE_NOARCH
+netsnmp_container*
+netsnmp_access_interface_container_load(netsnmp_container* container, u_int load_flags)
+{
+ int rc;
+
+ DEBUGMSGTL(("access:interface:container", "load\n"));
+ netsnmp_assert(1 == _access_interface_init);
+
+ if (NULL == container)
+ container = netsnmp_access_interface_container_init(load_flags);
+ if (NULL == container) {
+ snmp_log(LOG_ERR, "no container specified/found for access_interface\n");
+ return NULL;
+ }
+
+ rc = netsnmp_arch_interface_container_load(container, load_flags);
+ if (0 != rc) {
+ netsnmp_access_interface_container_free(container,
+ NETSNMP_ACCESS_INTERFACE_FREE_NOFLAGS);
+ container = NULL;
+ }
+
+ return container;
+}
+
+void
+netsnmp_access_interface_container_free(netsnmp_container *container, u_int free_flags)
+{
+ DEBUGMSGTL(("access:interface:container", "free\n"));
+
+ if (NULL == container) {
+ snmp_log(LOG_ERR, "invalid container for netsnmp_access_interface_free\n");
+ return;
+ }
+
+ if(! (free_flags & NETSNMP_ACCESS_INTERFACE_FREE_DONT_CLEAR)) {
+ /*
+ * free all items.
+ */
+ CONTAINER_CLEAR(container,
+ (netsnmp_container_obj_func*)_access_interface_entry_release,
+ NULL);
+ }
+
+ CONTAINER_FREE(container);
+}
+
+/**
+ * @retval 0 interface not found
+ */
+oid
+netsnmp_access_interface_index_find(const char *name)
+{
+ DEBUGMSGTL(("access:interface:find", "index\n"));
+ netsnmp_assert(1 == _access_interface_init);
+
+ return netsnmp_arch_interface_index_find(name);
+}
+#endif
+
+/**---------------------------------------------------------------------*/
+/*
+ * ifentry functions
+ */
+/**
+ */
+netsnmp_interface_entry *
+netsnmp_access_interface_entry_get_by_index(netsnmp_container *container, oid index)
+{
+ netsnmp_index tmp;
+
+ DEBUGMSGTL(("access:interface:entry", "by_index\n"));
+ netsnmp_assert(1 == _access_interface_init);
+
+ if (NULL == container) {
+ snmp_log(LOG_ERR,
+ "invalid container for netsnmp_access_interface_entry_get_by_index\n");
+ return NULL;
+ }
+
+ tmp.len = 1;
+ tmp.oids = &index;
+
+ return (netsnmp_interface_entry *) CONTAINER_FIND(container, &tmp);
+}
+
+/**
+ */
+netsnmp_interface_entry *
+netsnmp_access_interface_entry_get_by_name(netsnmp_container *container,
+ const char *name)
+{
+ netsnmp_interface_entry tmp;
+
+ DEBUGMSGTL(("access:interface:entry", "by_name\n"));
+ netsnmp_assert(1 == _access_interface_init);
+
+ if (NULL == container) {
+ snmp_log(LOG_ERR,
+ "invalid container for netsnmp_access_interface_entry_get_by_name\n");
+ return NULL;
+ }
+
+ if (NULL == container->next) {
+ snmp_log(LOG_ERR,
+ "secondary index missing for netsnmp_access_interface_entry_get_by_name\n");
+ return NULL;
+ }
+
+ tmp.name = NETSNMP_REMOVE_CONST(char *, name);
+ return (netsnmp_interface_entry*)CONTAINER_FIND(container->next, &tmp);
+}
+
+/**
+ * @retval NULL index not found
+ */
+const char *
+netsnmp_access_interface_name_find(oid index)
+{
+ DEBUGMSGTL(("access:interface:find", "name\n"));
+ netsnmp_assert(1 == _access_interface_init);
+
+ return se_find_label_in_slist("interfaces", index);
+}
+
+/**
+ */
+netsnmp_interface_entry *
+netsnmp_access_interface_entry_create(const char *name, oid if_index)
+{
+ netsnmp_interface_entry *entry =
+ SNMP_MALLOC_TYPEDEF(netsnmp_interface_entry);
+
+ DEBUGMSGTL(("access:interface:entry", "create\n"));
+ netsnmp_assert(1 == _access_interface_init);
+
+ if(NULL == entry)
+ return NULL;
+
+ if(NULL != name)
+ entry->name = strdup(name);
+
+ /*
+ * get if index, and save name for reverse lookup
+ */
+#ifndef NETSNMP_ACCESS_INTERFACE_NOARCH
+ if (0 == if_index)
+ entry->index = netsnmp_access_interface_index_find(name);
+ else
+#endif
+ entry->index = if_index;
+ _access_interface_entry_save_name(name, entry->index);
+
+ entry->descr = strdup(name);
+
+ /*
+ * make some assumptions
+ */
+ entry->connector_present = 1;
+
+ entry->oid_index.len = 1;
+ entry->oid_index.oids = (oid *) & entry->index;
+
+ return entry;
+}
+
+/**
+ */
+void
+netsnmp_access_interface_entry_free(netsnmp_interface_entry * entry)
+{
+ DEBUGMSGTL(("access:interface:entry", "free\n"));
+
+ if (NULL == entry)
+ return;
+
+ /*
+ * SNMP_FREE not needed, for any of these,
+ * since the whole entry is about to be freed
+ */
+
+ if (NULL != entry->old_stats)
+ free(entry->old_stats);
+
+ if (NULL != entry->name)
+ free(entry->name);
+
+ if (NULL != entry->descr)
+ free(entry->descr);
+
+ if (NULL != entry->paddr)
+ free(entry->paddr);
+
+ free(entry);
+}
+
+#ifndef NETSNMP_FEATURE_REMOVE_INTERFACE_LEGACY
+/*
+ * Blech - backwards compatible mibII/interfaces style interface
+ * functions, so we don't have to update older modules to use
+ * the new code to get correct ifIndex values.
+ */
+#if defined( USING_IF_MIB_IFTABLE_IFTABLE_DATA_ACCESS_MODULE ) && \
+ ! defined( NETSNMP_NO_BACKWARDS_COMPATABILITY )
+
+static netsnmp_iterator *it = NULL;
+static ifTable_rowreq_ctx *row = NULL;
+
+/**
+ * Setup an iterator for scanning the interfaces using the cached entry
+ * from if-mib/ifTable.
+ */
+void
+Interface_Scan_Init(void)
+{
+ netsnmp_container *cont = NULL;
+ netsnmp_cache *cache = NULL;
+
+ cache = netsnmp_cache_find_by_oid(ifTable_oid, ifTable_oid_size);
+ if (NULL != cache) {
+ netsnmp_cache_check_and_reload(cache);
+ cont = (netsnmp_container*) cache->magic;
+ }
+
+ if (NULL != cont) {
+ if (NULL != it)
+ ITERATOR_RELEASE(it);
+
+ it = CONTAINER_ITERATOR(cont);
+ }
+
+ if (NULL != it)
+ row = (ifTable_rowreq_ctx*)ITERATOR_FIRST(it);
+}
+
+int
+Interface_Scan_Next(short *index, char *name, netsnmp_interface_entry **entry,
+ void *dc)
+{
+ int returnIndex = 0;
+ int ret;
+ if (index)
+ returnIndex = *index;
+
+ ret = Interface_Scan_NextInt( &returnIndex, name, entry, dc );
+ if (index)
+ *index = (returnIndex & 0x8fff);
+ return ret;
+}
+
+int
+Interface_Scan_NextInt(int *index, char *name, netsnmp_interface_entry **entry,
+ void *dc)
+{
+ netsnmp_interface_entry* e = NULL;
+
+ if (NULL == row)
+ return 0;
+
+ e = row->data.ifentry;
+ if(index)
+ *index = e->index;
+
+ if(name)
+ strcpy(name, e->name);
+
+ if (entry)
+ *entry = e;
+
+ row = (ifTable_rowreq_ctx*) ITERATOR_NEXT(it);
+
+ return 1;
+}
+#endif /* NETSNMP_NO_BACKWARDS_COMPATABILITY */
+#endif /* NETSNMP_FEATURE_REMOVE_INTERFACE_LEGACY */
+
+#ifndef NETSNMP_FEATURE_REMOVE_INTERFACE_ACCESS_ENTRY_SET_ADMIN_STATUS
+/**
+ *
+ * @retval 0 : success
+ * @retval < 0 : error
+ */
+#ifndef NETSNMP_ACCESS_INTERFACE_NOARCH
+int
+netsnmp_access_interface_entry_set_admin_status(netsnmp_interface_entry * entry,
+ int ifAdminStatus)
+{
+ int rc;
+
+ DEBUGMSGTL(("access:interface:entry", "set_admin_status\n"));
+
+ if (NULL == entry)
+ return -1;
+
+ if ((ifAdminStatus < IFADMINSTATUS_UP) ||
+ (ifAdminStatus > IFADMINSTATUS_TESTING))
+ return -2;
+
+ rc = netsnmp_arch_set_admin_status(entry, ifAdminStatus);
+ if (0 == rc) /* success */
+ entry->admin_status = ifAdminStatus;
+
+ return rc;
+}
+#endif
+#endif /* NETSNMP_FEATURE_REMOVE_INTERFACE_ACCESS_ENTRY_SET_ADMIN_STATUS */
+
+/**---------------------------------------------------------------------*/
+/*
+ * Utility routines
+ */
+
+/**
+ */
+static int
+_access_interface_entry_compare_name(const void *lhs, const void *rhs)
+{
+ return strcmp(((const netsnmp_interface_entry *) lhs)->name,
+ ((const netsnmp_interface_entry *) rhs)->name);
+}
+
+/**
+ */
+static void
+_access_interface_entry_release(netsnmp_interface_entry * entry, void *context)
+{
+ netsnmp_access_interface_entry_free(entry);
+}
+
+/**
+ */
+static void
+_access_interface_entry_save_name(const char *name, oid index)
+{
+ int tmp;
+
+ if(NULL == name)
+ return;
+
+ tmp = se_find_value_in_slist("interfaces", name);
+ if (tmp == SE_DNE) {
+ se_add_pair_to_slist("interfaces", strdup(name), index);
+ DEBUGMSGTL(("access:interface:ifIndex",
+ "saved ifIndex %" NETSNMP_PRIo "u for %s\n",
+ index, name));
+ }
+ else
+ if (index != (oid)tmp) {
+ NETSNMP_LOGONCE((LOG_ERR, "IfIndex of an interface changed. Such " \
+ "interfaces will appear multiple times in IF-MIB.\n"));
+ DEBUGMSGTL(("access:interface:ifIndex",
+ "index %" NETSNMP_PRIo "u != tmp for %s\n",
+ index, name));
+ }
+}
+
+/**
+ * update stats
+ *
+ * @retval 0 : success
+ * @retval -1 : error
+ */
+int
+netsnmp_access_interface_entry_update_stats(netsnmp_interface_entry * prev_vals,
+ netsnmp_interface_entry * new_vals)
+{
+ DEBUGMSGTL(("access:interface", "check_wrap\n"));
+
+ /*
+ * sanity checks
+ */
+ if ((NULL == prev_vals) || (NULL == new_vals) ||
+ (NULL == prev_vals->name) || (NULL == new_vals->name) ||
+ (0 != strncmp(prev_vals->name, new_vals->name, strlen(prev_vals->name))))
+ return -1;
+
+ /*
+ * if we've determined that we have 64 bit counters, just copy them.
+ */
+ if (0 == need_wrap_check) {
+ memcpy(&prev_vals->stats, &new_vals->stats, sizeof(new_vals->stats));
+ return 0;
+ }
+
+ if (NULL == prev_vals->old_stats) {
+ /*
+ * if we don't have old stats, copy previous stats
+ */
+ prev_vals->old_stats = SNMP_MALLOC_TYPEDEF(netsnmp_interface_stats);
+ if (NULL == prev_vals->old_stats) {
+ return -2;
+ }
+ memcpy(prev_vals->old_stats, &prev_vals->stats, sizeof(prev_vals->stats));
+ }
+
+ if (0 != netsnmp_c64_check32_and_update(&prev_vals->stats.ibytes,
+ &new_vals->stats.ibytes,
+ &prev_vals->old_stats->ibytes,
+ &need_wrap_check))
+ DEBUGMSGTL(("access:interface",
+ "Error expanding ifHCInOctets to 64bits\n"));
+
+ if (new_vals->ns_flags & NETSNMP_INTERFACE_FLAGS_CALCULATE_UCAST) {
+ if (0 != netsnmp_c64_check32_and_update(&prev_vals->stats.iall,
+ &new_vals->stats.iall,
+ &prev_vals->old_stats->iall,
+ &need_wrap_check))
+ DEBUGMSGTL(("access:interface",
+ "Error expanding packet count to 64bits\n"));
+ } else {
+ if (0 != netsnmp_c64_check32_and_update(&prev_vals->stats.iucast,
+ &new_vals->stats.iucast,
+ &prev_vals->old_stats->iucast,
+ &need_wrap_check))
+ DEBUGMSGTL(("access:interface",
+ "Error expanding ifHCInUcastPkts to 64bits\n"));
+ }
+
+ if (0 != netsnmp_c64_check32_and_update(&prev_vals->stats.iucast,
+ &new_vals->stats.iucast,
+ &prev_vals->old_stats->iucast,
+ &need_wrap_check))
+ DEBUGMSGTL(("access:interface",
+ "Error expanding ifHCInUcastPkts to 64bits\n"));
+
+ if (0 != netsnmp_c64_check32_and_update(&prev_vals->stats.imcast,
+ &new_vals->stats.imcast,
+ &prev_vals->old_stats->imcast,
+ &need_wrap_check))
+ DEBUGMSGTL(("access:interface",
+ "Error expanding ifHCInMulticastPkts to 64bits\n"));
+
+ if (0 != netsnmp_c64_check32_and_update(&prev_vals->stats.ibcast,
+ &new_vals->stats.ibcast,
+ &prev_vals->old_stats->ibcast,
+ &need_wrap_check))
+ DEBUGMSGTL(("access:interface",
+ "Error expanding ifHCInBroadcastPkts to 64bits\n"));
+
+ if (0 != netsnmp_c64_check32_and_update(&prev_vals->stats.obytes,
+ &new_vals->stats.obytes,
+ &prev_vals->old_stats->obytes,
+ &need_wrap_check))
+ DEBUGMSGTL(("access:interface",
+ "Error expanding ifHCOutOctets to 64bits\n"));
+
+ if (0 != netsnmp_c64_check32_and_update(&prev_vals->stats.oucast,
+ &new_vals->stats.oucast,
+ &prev_vals->old_stats->oucast,
+ &need_wrap_check))
+ DEBUGMSGTL(("access:interface",
+ "Error expanding ifHCOutUcastPkts to 64bits\n"));
+
+ if (0 != netsnmp_c64_check32_and_update(&prev_vals->stats.omcast,
+ &new_vals->stats.omcast,
+ &prev_vals->old_stats->omcast,
+ &need_wrap_check))
+ DEBUGMSGTL(("access:interface",
+ "Error expanding ifHCOutMulticastPkts to 64bits\n"));
+
+ if (0 != netsnmp_c64_check32_and_update(&prev_vals->stats.obcast,
+ &new_vals->stats.obcast,
+ &prev_vals->old_stats->obcast,
+ &need_wrap_check))
+ DEBUGMSGTL(("access:interface",
+ "Error expanding ifHCOutBroadcastPkts to 64bits\n"));
+
+ /*
+ * Copy 32 bit counters
+ */
+ prev_vals->stats.ierrors = new_vals->stats.ierrors;
+ prev_vals->stats.idiscards = new_vals->stats.idiscards;
+ prev_vals->stats.iunknown_protos = new_vals->stats.iunknown_protos;
+ prev_vals->stats.inucast = new_vals->stats.inucast;
+ prev_vals->stats.oerrors = new_vals->stats.oerrors;
+ prev_vals->stats.odiscards = new_vals->stats.odiscards;
+ prev_vals->stats.oqlen = new_vals->stats.oqlen;
+ prev_vals->stats.collisions = new_vals->stats.collisions;
+ prev_vals->stats.onucast = new_vals->stats.onucast;
+
+ /*
+ * if we've decided we no longer need to check wraps, free old stats
+ */
+ if (0 == need_wrap_check) {
+ SNMP_FREE(prev_vals->old_stats);
+ }
+ else {
+ /*
+ * update old stats from new stats.
+ * careful - old_stats is a pointer to stats...
+ */
+ memcpy(prev_vals->old_stats, &new_vals->stats, sizeof(new_vals->stats));
+ }
+
+ return 0;
+}
+
+/**
+ * Calculate stats
+ *
+ * @retval 0 : success
+ * @retval -1 : error
+ */
+int
+netsnmp_access_interface_entry_calculate_stats(netsnmp_interface_entry *entry)
+{
+ DEBUGMSGTL(("access:interface", "calculate_stats\n"));
+ if (entry->ns_flags & NETSNMP_INTERFACE_FLAGS_CALCULATE_UCAST) {
+ u64Subtract(&entry->stats.iall, &entry->stats.imcast,
+ &entry->stats.iucast);
+ }
+ return 0;
+}
+
+/**
+ * copy interface entry data (after checking for counter wraps)
+ *
+ * @retval -2 : malloc failed
+ * @retval -1 : interfaces not the same
+ * @retval 0 : no error
+ */
+int
+netsnmp_access_interface_entry_copy(netsnmp_interface_entry * lhs,
+ netsnmp_interface_entry * rhs)
+{
+ DEBUGMSGTL(("access:interface", "copy\n"));
+
+ if ((NULL == lhs) || (NULL == rhs) ||
+ (NULL == lhs->name) || (NULL == rhs->name) ||
+ (0 != strncmp(lhs->name, rhs->name, strlen(rhs->name))))
+ return -1;
+
+ /*
+ * update stats
+ */
+ netsnmp_access_interface_entry_update_stats(lhs, rhs);
+ netsnmp_access_interface_entry_calculate_stats(lhs);
+
+ /*
+ * update data
+ */
+ lhs->ns_flags = rhs->ns_flags;
+ if((NULL != lhs->descr) && (NULL != rhs->descr) &&
+ (0 == strcmp(lhs->descr, rhs->descr)))
+ ;
+ else {
+ SNMP_FREE(lhs->descr);
+ if (rhs->descr) {
+ lhs->descr = strdup(rhs->descr);
+ if(NULL == lhs->descr)
+ return -2;
+ }
+ }
+ lhs->type = rhs->type;
+ lhs->speed = rhs->speed;
+ lhs->speed_high = rhs->speed_high;
+ lhs->retransmit_v6 = rhs->retransmit_v6;
+ lhs->retransmit_v4 = rhs->retransmit_v4;
+ lhs->reachable_time = rhs->reachable_time;
+ lhs->mtu = rhs->mtu;
+ lhs->lastchange = rhs->lastchange;
+ lhs->discontinuity = rhs->discontinuity;
+ lhs->reasm_max_v4 = rhs->reasm_max_v4;
+ lhs->reasm_max_v6 = rhs->reasm_max_v6;
+ lhs->admin_status = rhs->admin_status;
+ lhs->oper_status = rhs->oper_status;
+ lhs->promiscuous = rhs->promiscuous;
+ lhs->connector_present = rhs->connector_present;
+ lhs->forwarding_v6 = rhs->forwarding_v6;
+ lhs->os_flags = rhs->os_flags;
+ if(lhs->paddr_len == rhs->paddr_len) {
+ if(rhs->paddr_len)
+ memcpy(lhs->paddr,rhs->paddr,rhs->paddr_len);
+ } else {
+ SNMP_FREE(lhs->paddr);
+ if (rhs->paddr) {
+ lhs->paddr = (char*)malloc(rhs->paddr_len);
+ if(NULL == lhs->paddr)
+ return -2;
+ memcpy(lhs->paddr,rhs->paddr,rhs->paddr_len);
+ }
+ }
+ lhs->paddr_len = rhs->paddr_len;
+
+ return 0;
+}
+
+void
+netsnmp_access_interface_entry_guess_speed(netsnmp_interface_entry *entry)
+{
+ if (entry->type == IANAIFTYPE_ETHERNETCSMACD)
+ entry->speed = 10000000;
+ else if (entry->type == IANAIFTYPE_SOFTWARELOOPBACK)
+ entry->speed = 10000000;
+ else if (entry->type == IANAIFTYPE_ISO88025TOKENRING)
+ entry->speed = 4000000;
+ else
+ entry->speed = 0;
+ entry->speed_high = entry->speed / 1000000LL;
+}
+
+netsnmp_conf_if_list *
+netsnmp_access_interface_entry_overrides_get(const char * name)
+{
+ netsnmp_conf_if_list * if_ptr;
+
+ netsnmp_assert(1 == _access_interface_init);
+ if(NULL == name)
+ return NULL;
+
+ for (if_ptr = conf_list; if_ptr; if_ptr = if_ptr->next)
+ if (!strcmp(if_ptr->name, name))
+ break;
+
+ return if_ptr;
+}
+
+void
+netsnmp_access_interface_entry_overrides(netsnmp_interface_entry *entry)
+{
+ netsnmp_conf_if_list * if_ptr;
+
+ netsnmp_assert(1 == _access_interface_init);
+ if (NULL == entry)
+ return;
+
+ /*
+ * enforce mib size limit
+ */
+ if(entry->descr && (strlen(entry->descr) > 255))
+ entry->descr[255] = 0;
+
+ if_ptr =
+ netsnmp_access_interface_entry_overrides_get(entry->name);
+ if (if_ptr) {
+ entry->type = if_ptr->type;
+ if (if_ptr->speed > 0xffffffff) {
+ entry->speed = 0xffffffff;
+ } else {
+ entry->speed = if_ptr->speed;
+ }
+ entry->speed_high = if_ptr->speed / 1000000LL;
+ }
+}
+
+/**---------------------------------------------------------------------*/
+/*
+ * interface config token
+ */
+/**
+ */
+static void
+_parse_interface_config(const char *token, char *cptr)
+{
+ netsnmp_conf_if_list *if_ptr, *if_new;
+ char *name, *type, *speed, *ecp;
+ char *st;
+
+ name = strtok_r(cptr, " \t", &st);
+ if (!name) {
+ config_perror("Missing NAME parameter");
+ return;
+ }
+ type = strtok_r(NULL, " \t", &st);
+ if (!type) {
+ config_perror("Missing TYPE parameter");
+ return;
+ }
+ speed = strtok_r(NULL, " \t", &st);
+ if (!speed) {
+ config_perror("Missing SPEED parameter");
+ return;
+ }
+ if_ptr = conf_list;
+ while (if_ptr)
+ if (strcmp(if_ptr->name, name))
+ if_ptr = if_ptr->next;
+ else
+ break;
+ if (if_ptr)
+ config_pwarn("Duplicate interface specification");
+ if_new = SNMP_MALLOC_TYPEDEF(netsnmp_conf_if_list);
+ if (!if_new) {
+ config_perror("Out of memory");
+ return;
+ }
+ if_new->speed = strtoull(speed, &ecp, 0);
+ if (*ecp) {
+ config_perror("Bad SPEED value");
+ free(if_new);
+ return;
+ }
+ if_new->type = strtol(type, &ecp, 0);
+ if (*ecp || if_new->type < 0) {
+ config_perror("Bad TYPE");
+ free(if_new);
+ return;
+ }
+ if_new->name = strdup(name);
+ if (!if_new->name) {
+ config_perror("Out of memory");
+ free(if_new);
+ return;
+ }
+ if_new->next = conf_list;
+ conf_list = if_new;
+}
+
+static void
+_free_interface_config(void)
+{
+ netsnmp_conf_if_list *if_ptr = conf_list, *if_next;
+ while (if_ptr) {
+ if_next = if_ptr->next;
+ free(NETSNMP_REMOVE_CONST(char *, if_ptr->name));
+ free(if_ptr);
+ if_ptr = if_next;
+ }
+ conf_list = NULL;
+}
diff --git a/agent/mibgroup/if-mib/data_access/interface.h b/agent/mibgroup/if-mib/data_access/interface.h
new file mode 100644
index 0000000..353b254
--- /dev/null
+++ b/agent/mibgroup/if-mib/data_access/interface.h
@@ -0,0 +1,58 @@
+/*
+ * interface data access header
+ *
+ * $Id$
+ */
+#ifndef NETSNMP_ACCESS_INTERFACE_CONFIG_H
+#define NETSNMP_ACCESS_INTERFACE_CONFIG_H
+
+/*
+ * all platforms use this generic code
+ */
+config_require(if-mib/data_access/interface)
+
+/**---------------------------------------------------------------------*/
+/*
+ * configure required files
+ *
+ * Notes:
+ *
+ * 1) prefer functionality over platform, where possible. If a method
+ * is available for multiple platforms, test that first. That way
+ * when a new platform is ported, it won't need a new test here.
+ *
+ * 2) don't do detail requirements here. If, for example,
+ * HPUX11 had different reuirements than other HPUX, that should
+ * be handled in the *_hpux.h header file.
+ */
+
+#ifdef NETSNMP_INCLUDE_IFTABLE_REWRITES
+
+config_exclude(mibII/interfaces)
+
+# if defined( linux )
+
+ config_require(util_funcs)
+ config_require(if-mib/data_access/interface_linux)
+ config_require(if-mib/data_access/interface_ioctl)
+
+# elif defined( openbsd3 ) || \
+ defined( freebsd4 ) || defined( freebsd5 ) || defined( freebsd6 ) || \
+ defined( darwin ) || defined( dragonfly ) || defined( netbsd1 )
+
+ config_require(if-mib/data_access/interface_sysctl)
+
+# elif defined( solaris2 )
+
+ config_require(if-mib/data_access/interface_solaris2)
+
+# else
+
+ config_error(This platform does not yet support IF-MIB rewrites)
+
+# endif
+#else
+# define NETSNMP_ACCESS_INTERFACE_NOARCH 1
+#endif
+
+#endif /* NETSNMP_ACCESS_INTERFACE_CONFIG_H */
diff --git a/agent/mibgroup/if-mib/data_access/interface_ioctl.c b/agent/mibgroup/if-mib/data_access/interface_ioctl.c
new file mode 100644
index 0000000..db2c245
--- /dev/null
+++ b/agent/mibgroup/if-mib/data_access/interface_ioctl.c
@@ -0,0 +1,506 @@
+/*
+ * Interface MIB architecture support
+ *
+ * $Id$
+ */
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-features.h>
+#include <net-snmp/net-snmp-includes.h>
+#include "mibII/mibII_common.h"
+#include "if-mib/ifTable/ifTable_constants.h"
+
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#include <net-snmp/data_access/interface.h>
+#include <net-snmp/data_access/ipaddress.h>
+#include "if-mib/data_access/interface.h"
+
+netsnmp_feature_child_of(interface_ioctl_flags_set, interface_all)
+
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_NET_IF_ARP_H
+#include <net/if_arp.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#include "interface_ioctl.h"
+#include "ip-mib/data_access/ipaddress_ioctl.h"
+
+/**
+ * ioctl wrapper
+ *
+ * @param fd : socket fd to use w/ioctl, or -1 to open/close one
+ * @param which
+ * @param ifrq
+ * param ifentry : ifentry to update
+ * @param name
+ *
+ * @retval 0 : success
+ * @retval -1 : invalid parameters
+ * @retval -2 : couldn't create socket
+ * @retval -3 : ioctl call failed
+ */
+static int
+_ioctl_get(int fd, int which, struct ifreq *ifrq, const char* name)
+{
+ int ourfd = -1, rc = 0;
+
+ DEBUGMSGTL(("verbose:access:interface:ioctl",
+ "ioctl %d for %s\n", which, name));
+
+ /*
+ * sanity checks
+ */
+ if(NULL == name) {
+ snmp_log(LOG_ERR, "invalid ifentry\n");
+ return -1;
+ }
+
+ /*
+ * create socket for ioctls
+ */
+ if(fd < 0) {
+ fd = ourfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if(ourfd < 0) {
+ snmp_log(LOG_ERR,"couldn't create socket\n");
+ return -2;
+ }
+ }
+
+ strlcpy(ifrq->ifr_name, name, sizeof(ifrq->ifr_name));
+ rc = ioctl(fd, which, ifrq);
+ if (rc < 0) {
+ snmp_log(LOG_ERR,"ioctl %d returned %d\n", which, rc);
+ rc = -3;
+ }
+
+ if(ourfd >= 0)
+ close(ourfd);
+
+ return rc;
+}
+
+#ifdef SIOCGIFHWADDR
+/**
+ * interface entry physaddr ioctl wrapper
+ *
+ * @param fd : socket fd to use w/ioctl, or -1 to open/close one
+ * @param ifentry : ifentry to update
+ *
+ * @retval 0 : success
+ * @retval -1 : invalid parameters
+ * @retval -2 : couldn't create socket
+ * @retval -3 : ioctl call failed
+ * @retval -4 : malloc error
+ */
+int
+netsnmp_access_interface_ioctl_physaddr_get(int fd,
+ netsnmp_interface_entry *ifentry)
+{
+ struct ifreq ifrq;
+ int rc = 0;
+
+ DEBUGMSGTL(("access:interface:ioctl", "physaddr_get\n"));
+
+ if((NULL != ifentry->paddr) &&
+ (ifentry->paddr_len != IFHWADDRLEN)) {
+ SNMP_FREE(ifentry->paddr);
+ }
+ if(NULL == ifentry->paddr)
+ ifentry->paddr = (char*)malloc(IFHWADDRLEN);
+
+ if(NULL == ifentry->paddr) {
+ rc = -4;
+ } else {
+
+ /*
+ * 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. Uncomment this memset, and suddenly
+ * the sit interface will be 0:0:0:0:?:? where ? is whatever was
+ * in the memory before. Not sure if this memset should be done
+ * for every ioctl, as the rest seem to work ok...
+ */
+ memset(ifrq.ifr_hwaddr.sa_data, (0), IFHWADDRLEN);
+ ifentry->paddr_len = IFHWADDRLEN;
+ rc = _ioctl_get(fd, SIOCGIFHWADDR, &ifrq, ifentry->name);
+ if (rc < 0) {
+ memset(ifentry->paddr, (0), IFHWADDRLEN);
+ rc = -3; /* msg already logged */
+ }
+ else {
+ memcpy(ifentry->paddr, ifrq.ifr_hwaddr.sa_data, IFHWADDRLEN);
+
+ /*
+ * arphrd defines vary greatly. ETHER seems to be the only common one
+ */
+#ifdef ARPHRD_ETHER
+ switch (ifrq.ifr_hwaddr.sa_family) {
+ case ARPHRD_ETHER:
+ ifentry->type = IANAIFTYPE_ETHERNETCSMACD;
+ break;
+#if defined(ARPHRD_TUNNEL) || defined(ARPHRD_IPGRE) || defined(ARPHRD_SIT)
+#ifdef ARPHRD_TUNNEL
+ case ARPHRD_TUNNEL:
+ case ARPHRD_TUNNEL6:
+#endif
+#ifdef ARPHRD_IPGRE
+ case ARPHRD_IPGRE:
+#endif
+#ifdef ARPHRD_SIT
+ case ARPHRD_SIT:
+#endif
+ ifentry->type = IANAIFTYPE_TUNNEL;
+ break; /* tunnel */
+#endif
+#ifdef ARPHRD_INFINIBAND
+ case ARPHRD_INFINIBAND:
+ ifentry->type = IANAIFTYPE_INFINIBAND;
+ break;
+#endif
+#ifdef ARPHRD_SLIP
+ case ARPHRD_SLIP:
+ case ARPHRD_CSLIP:
+ case ARPHRD_SLIP6:
+ case ARPHRD_CSLIP6:
+ ifentry->type = IANAIFTYPE_SLIP;
+ break; /* slip */
+#endif
+#ifdef ARPHRD_PPP
+ case ARPHRD_PPP:
+ ifentry->type = IANAIFTYPE_PPP;
+ break; /* ppp */
+#endif
+#ifdef ARPHRD_LOOPBACK
+ case ARPHRD_LOOPBACK:
+ ifentry->type = IANAIFTYPE_SOFTWARELOOPBACK;
+ break; /* softwareLoopback */
+#endif
+#ifdef ARPHRD_FDDI
+ case ARPHRD_FDDI:
+ ifentry->type = IANAIFTYPE_FDDI;
+ break;
+#endif
+#ifdef ARPHRD_ARCNET
+ case ARPHRD_ARCNET:
+ ifentry->type = IANAIFTYPE_ARCNET;
+ break;
+#endif
+#ifdef ARPHRD_LOCALTLK
+ case ARPHRD_LOCALTLK:
+ ifentry->type = IANAIFTYPE_LOCALTALK;
+ break;
+#endif
+#ifdef ARPHRD_HIPPI
+ case ARPHRD_HIPPI:
+ ifentry->type = IANAIFTYPE_HIPPI;
+ break;
+#endif
+#ifdef ARPHRD_ATM
+ case ARPHRD_ATM:
+ ifentry->type = IANAIFTYPE_ATM;
+ break;
+#endif
+ /*
+ * XXX: more if_arp.h:ARPHRD_xxx to IANAifType mappings...
+ */
+ default:
+ DEBUGMSGTL(("access:interface:ioctl", "unknown entry type %d\n",
+ ifrq.ifr_hwaddr.sa_family));
+ ifentry->type = IANAIFTYPE_OTHER;
+ } /* switch */
+#endif /* ARPHRD_LOOPBACK */
+
+ }
+ }
+
+ return rc;
+}
+#endif /* SIOCGIFHWADDR */
+
+
+#ifdef SIOCGIFFLAGS
+/**
+ * interface entry flags ioctl wrapper
+ *
+ * @param fd : socket fd to use w/ioctl, or -1 to open/close one
+ * @param ifentry : ifentry to update
+ *
+ * @retval 0 : success
+ * @retval -1 : invalid parameters
+ * @retval -2 : couldn't create socket
+ * @retval -3 : ioctl call failed
+ */
+int
+netsnmp_access_interface_ioctl_flags_get(int fd,
+ netsnmp_interface_entry *ifentry)
+{
+ struct ifreq ifrq;
+ int rc = 0;
+
+ DEBUGMSGTL(("access:interface:ioctl", "flags_get\n"));
+
+ rc = _ioctl_get(fd, SIOCGIFFLAGS, &ifrq, ifentry->name);
+ if (rc < 0) {
+ ifentry->ns_flags &= ~NETSNMP_INTERFACE_FLAGS_HAS_IF_FLAGS;
+ return rc; /* msg already logged */
+ }
+ else {
+ ifentry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_IF_FLAGS;
+ ifentry->os_flags = ifrq.ifr_flags;
+
+ /*
+ * ifOperStatus description:
+ * If ifAdminStatus is down(2) then ifOperStatus should be down(2).
+ */
+ if(ifentry->os_flags & IFF_UP) {
+ ifentry->admin_status = IFADMINSTATUS_UP;
+ if(ifentry->os_flags & IFF_RUNNING)
+ ifentry->oper_status = IFOPERSTATUS_UP;
+ else
+ ifentry->oper_status = IFOPERSTATUS_DOWN;
+ }
+ else {
+ ifentry->admin_status = IFADMINSTATUS_DOWN;
+ ifentry->oper_status = IFOPERSTATUS_DOWN;
+ }
+
+ /*
+ * ifConnectorPresent description:
+ * This object has the value 'true(1)' if the interface sublayer has a
+ * physical connector and the value 'false(2)' otherwise."
+ * So, at very least, false(2) should be returned for loopback devices.
+ */
+ if(ifentry->os_flags & IFF_LOOPBACK) {
+ ifentry->connector_present = 0;
+ }
+ else {
+ ifentry->connector_present = 1;
+ }
+ }
+
+ return rc;
+}
+
+#ifndef NETSNMP_FEATURE_REMOVE_INTERFACE_IOCTL_FLAGS_SET
+/**
+ * interface entry flags ioctl wrapper
+ *
+ * @param fd : socket fd to use w/ioctl, or -1 to open/close one
+ * @param ifentry : ifentry to update
+ *
+ * @retval 0 : success
+ * @retval -1 : invalid parameters
+ * @retval -2 : couldn't create socket
+ * @retval -3 : ioctl get call failed
+ * @retval -4 : ioctl set call failed
+ */
+int
+netsnmp_access_interface_ioctl_flags_set(int fd,
+ netsnmp_interface_entry *ifentry,
+ unsigned int flags, int and_complement)
+{
+ struct ifreq ifrq;
+ int ourfd = -1, rc = 0;
+
+ DEBUGMSGTL(("access:interface:ioctl", "flags_set\n"));
+
+ /*
+ * sanity checks
+ */
+ if((NULL == ifentry) || (NULL == ifentry->name)) {
+ snmp_log(LOG_ERR, "invalid ifentry\n");
+ return -1;
+ }
+
+ /*
+ * create socket for ioctls
+ */
+ if(fd < 0) {
+ fd = ourfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if(ourfd < 0) {
+ snmp_log(LOG_ERR,"couldn't create socket\n");
+ return -2;
+ }
+ }
+
+ strlcpy(ifrq.ifr_name, ifentry->name, sizeof(ifrq.ifr_name));
+ rc = ioctl(fd, SIOCGIFFLAGS, &ifrq);
+ if(rc < 0) {
+ snmp_log(LOG_ERR,"error getting flags\n");
+ close(fd);
+ return -3;
+ }
+ if(0 == and_complement)
+ ifrq.ifr_flags |= flags;
+ else
+ ifrq.ifr_flags &= ~flags;
+ rc = ioctl(fd, SIOCSIFFLAGS, &ifrq);
+ if(rc < 0) {
+ close(fd);
+ snmp_log(LOG_ERR,"error setting flags\n");
+ ifentry->os_flags = 0;
+ return -4;
+ }
+
+ if(ourfd >= 0)
+ close(ourfd);
+
+ ifentry->os_flags = ifrq.ifr_flags;
+
+ return 0;
+}
+#endif /* NETSNMP_FEATURE_REMOVE_INTERFACE_IOCTL_FLAGS_SET */
+#endif /* SIOCGIFFLAGS */
+
+#ifdef SIOCGIFMTU
+/**
+ * interface entry mtu ioctl wrapper
+ *
+ * @param fd : socket fd to use w/ioctl, or -1 to open/close one
+ * @param ifentry : ifentry to update
+ *
+ * @retval 0 : success
+ * @retval -1 : invalid parameters
+ * @retval -2 : couldn't create socket
+ * @retval -3 : ioctl call failed
+ */
+int
+netsnmp_access_interface_ioctl_mtu_get(int fd,
+ netsnmp_interface_entry *ifentry)
+{
+ struct ifreq ifrq;
+ int rc = 0;
+
+ DEBUGMSGTL(("access:interface:ioctl", "mtu_get\n"));
+
+ rc = _ioctl_get(fd, SIOCGIFMTU, &ifrq, ifentry->name);
+ if (rc < 0) {
+ ifentry->mtu = 0;
+ return rc; /* msg already logged */
+ }
+ else {
+ ifentry->mtu = ifrq.ifr_mtu;
+ }
+
+ return rc;
+}
+#endif /* SIOCGIFMTU */
+
+/**
+ * interface entry ifIndex ioctl wrapper
+ *
+ * @param fd : socket fd to use w/ioctl, or -1 to open/close one
+ * @param name : ifentry to update
+ *
+ * @retval 0 : not found
+ * @retval !0 : ifIndex
+ */
+oid
+netsnmp_access_interface_ioctl_ifindex_get(int fd, const char *name)
+{
+#ifndef SIOCGIFINDEX
+ return 0;
+#else
+ struct ifreq ifrq;
+ int rc = 0;
+
+ DEBUGMSGTL(("access:interface:ioctl", "ifindex_get\n"));
+
+ rc = _ioctl_get(fd, SIOCGIFINDEX, &ifrq, name);
+ if (rc < 0) {
+ DEBUGMSGTL(("access:interface:ioctl",
+ "ifindex_get error on inerface '%s'\n", name));
+ return 0;
+ }
+
+#if defined(__FreeBSD__) /* ? Should use HAVE_STRUCT_IFREQ_IFR_INDEX */
+ return ifrq.ifr_index;
+#else
+ return ifrq.ifr_ifindex;
+#endif
+#endif /* SIOCGIFINDEX */
+}
+
+/**
+ * check an interface for ipv4 addresses
+ *
+ * @param sd : open socket descriptor
+ * @param if_name : optional name. takes precedent over if_index.
+ * @param if_index: optional if index. only used if no if_name specified
+ * @param flags :
+ *
+ * @retval < 0 : error
+ * @retval 0 : no ip v4 addresses
+ * @retval 1 : 1 or more ip v4 addresses
+ */
+int
+netsnmp_access_interface_ioctl_has_ipv4(int sd, const char *if_name,
+ int if_index, u_int *flags)
+{
+ int i, interfaces = 0;
+ struct ifconf ifc;
+ struct ifreq *ifrp;
+
+ /*
+ * one or the other
+ */
+ if ((NULL == flags) ||
+ ((0 == if_index) && (NULL == if_name))) {
+ return -1;
+ }
+
+ interfaces = netsnmp_access_ipaddress_ioctl_get_interface_count(sd, &ifc);
+ if(interfaces < 0) {
+ close(sd);
+ return -2;
+ }
+ netsnmp_assert(NULL != ifc.ifc_buf);
+
+ *flags &= ~NETSNMP_INTERFACE_FLAGS_HAS_IPV4;
+
+ ifrp = ifc.ifc_req;
+ for(i=0; i < interfaces; ++i, ++ifrp) {
+
+ DEBUGMSGTL(("access:ipaddress:container",
+ " interface %d, %s\n", i, ifrp->ifr_name));
+
+ /*
+ * search for matching if_name or if_index
+ */
+ if (NULL != if_name) {
+ if (strncmp(if_name, ifrp->ifr_name, sizeof(ifrp->ifr_name)) != 0)
+ continue;
+ }
+ else {
+ /*
+ * I think that Linux and Solaris both use ':' in the
+ * interface name for aliases.
+ */
+ char *ptr = strchr(ifrp->ifr_name, ':');
+ if (NULL != ptr)
+ *ptr = 0;
+
+ if (if_index != (int)netsnmp_access_interface_ioctl_ifindex_get(sd, ifrp->ifr_name))
+ continue;
+ }
+
+ /*
+ * check and set v4 or v6 flag, and break if we've found both
+ */
+ if (AF_INET == ifrp->ifr_addr.sa_family) {
+ *flags |= NETSNMP_INTERFACE_FLAGS_HAS_IPV4;
+ break;
+ }
+ }
+
+ /*
+ * clean up
+ */
+ free(ifc.ifc_buf);
+
+ return 0;
+}
diff --git a/agent/mibgroup/if-mib/data_access/interface_ioctl.h b/agent/mibgroup/if-mib/data_access/interface_ioctl.h
new file mode 100644
index 0000000..d765876
--- /dev/null
+++ b/agent/mibgroup/if-mib/data_access/interface_ioctl.h
@@ -0,0 +1,52 @@
+/*
+ * ioctl interface data access header
+ *
+ * $Id$
+ */
+#ifndef NETSNMP_ACCESS_INTERFACE_IOCTL_H
+#define NETSNMP_ACCESS_INTERFACE_IOCTL_H
+
+/*
+ * need ipaddress functions to get ipversions of an interface
+*/
+config_require(ip-mib/data_access/ipaddress)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**---------------------------------------------------------------------*/
+/**/
+
+int
+netsnmp_access_interface_ioctl_physaddr_get(int fd,
+ netsnmp_interface_entry *ifentry);
+
+int
+netsnmp_access_interface_ioctl_flags_get(int fd,
+ netsnmp_interface_entry *ifentry);
+
+int
+netsnmp_access_interface_ioctl_flags_set(int fd,
+ netsnmp_interface_entry *ifentry,
+ unsigned int flags,
+ int and_complement);
+
+int
+netsnmp_access_interface_ioctl_mtu_get(int fd,
+ netsnmp_interface_entry *ifentry);
+
+oid
+netsnmp_access_interface_ioctl_ifindex_get(int fd, const char *name);
+
+int
+netsnmp_access_interface_ioctl_has_ipv4(int sd, const char *if_name,
+ int if_index, u_int *flags);
+
+/**---------------------------------------------------------------------*/
+
+# ifdef __cplusplus
+}
+#endif
+
+#endif /* NETSNMP_ACCESS_INTERFACE_IOCTL_H */
diff --git a/agent/mibgroup/if-mib/data_access/interface_linux.c b/agent/mibgroup/if-mib/data_access/interface_linux.c
new file mode 100644
index 0000000..3419811
--- /dev/null
+++ b/agent/mibgroup/if-mib/data_access/interface_linux.c
@@ -0,0 +1,1213 @@
+/*
+ * Interface MIB architecture support
+ *
+ * $Id$
+ */
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-features.h>
+#include <net-snmp/net-snmp-includes.h>
+
+netsnmp_feature_require(fd_event_manager)
+netsnmp_feature_require(delete_prefix_info)
+netsnmp_feature_require(create_prefix_info)
+netsnmp_feature_child_of(interface_arch_set_admin_status, interface_all)
+
+#ifdef NETSNMP_FEATURE_REQUIRE_INTERFACE_ARCH_SET_ADMIN_STATUS
+netsnmp_feature_require(interface_ioctl_flags_set)
+#endif /* NETSNMP_FEATURE_REQUIRE_INTERFACE_ARCH_SET_ADMIN_STATUS */
+
+#ifdef HAVE_PCI_LOOKUP_NAME
+#include <pci/pci.h>
+static struct pci_access *pci_access;
+#endif
+
+#ifdef HAVE_LINUX_ETHTOOL_H
+#include <linux/types.h>
+#ifndef HAVE_PCI_LOOKUP_NAME
+typedef __u64 u64; /* hack, so we may include kernel's ethtool.h */
+typedef __u32 u32; /* ditto */
+typedef __u16 u16; /* ditto */
+typedef __u8 u8; /* ditto */
+#endif
+
+#include <linux/ethtool.h>
+#endif /* HAVE_LINUX_ETHTOOL_H */
+
+#include "mibII/mibII_common.h"
+#include "if-mib/ifTable/ifTable_constants.h"
+
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#else
+#error "linux should have sys/ioctl header"
+#endif
+
+#include <net-snmp/data_access/interface.h>
+#include <net-snmp/data_access/ipaddress.h>
+#include "if-mib/data_access/interface.h"
+#include "mibgroup/util_funcs.h"
+#include "interface_ioctl.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <linux/sockios.h>
+#include <linux/if_ether.h>
+
+#ifndef IF_NAMESIZE
+#define IF_NAMESIZE 16
+#endif
+
+#ifndef SIOCGMIIPHY
+#define SIOCGMIIPHY 0x8947
+#endif
+
+#ifndef SIOCGMIIREG
+#define SIOCGMIIREG 0x8948
+#endif
+
+#ifdef NETSNMP_ENABLE_IPV6
+#if defined(HAVE_LINUX_RTNETLINK_H)
+#include <linux/rtnetlink.h>
+#ifdef RTMGRP_IPV6_PREFIX
+#define SUPPORT_PREFIX_FLAGS 1
+#endif /* RTMGRP_IPV6_PREFIX */
+#endif /* HAVE_LINUX_RTNETLINK_H */
+#endif /* NETSNMP_ENABLE_IPV6 */
+unsigned long long
+netsnmp_linux_interface_get_if_speed(int fd, const char *name,
+ unsigned long long defaultspeed);
+#ifdef HAVE_LINUX_ETHTOOL_H
+unsigned long long
+netsnmp_linux_interface_get_if_speed_mii(int fd, const char *name,
+ unsigned long long defaultspeed);
+#endif
+
+#define PROC_SYS_NET_IPVx_NEIGH_RETRANS_TIME_MS "/proc/sys/net/ipv%d/neigh/%s/retrans_time_ms"
+#define PROC_SYS_NET_IPVx_NEIGH_RETRANS_TIME "/proc/sys/net/ipv%d/neigh/%s/retrans_time"
+static const char *proc_sys_retrans_time;
+static unsigned short retrans_time_factor = 1;
+
+
+#define PROC_SYS_NET_IPVx_BASE_REACHABLE_TIME_MS "/proc/sys/net/ipv%d/neigh/%s/base_reachable_time_ms"
+#define PROC_SYS_NET_IPVx_BASE_REACHABLE_TIME "/proc/sys/net/ipv%d/neigh/%s/base_reachable_time"
+static const char *proc_sys_basereachable_time;
+static unsigned short basereachable_time_ms = 0;
+#ifdef SUPPORT_PREFIX_FLAGS
+prefix_cbx *prefix_head_list = NULL;
+netsnmp_prefix_listen_info list_info;
+#define IF_PREFIX_ONLINK 0x01
+#define IF_PREFIX_AUTOCONF 0x02
+
+int netsnmp_prefix_listen(void);
+#endif
+
+
+void
+netsnmp_arch_interface_init(void)
+{
+ /*
+ * Check which retransmit time interface is available
+ */
+ char proc_path[ 64+IF_NAMESIZE];
+ char proc_path2[64+IF_NAMESIZE];
+ struct stat st;
+
+ snprintf(proc_path, sizeof(proc_path),
+ PROC_SYS_NET_IPVx_NEIGH_RETRANS_TIME_MS, 6, "default");
+ snprintf(proc_path2, sizeof(proc_path2),
+ PROC_SYS_NET_IPVx_NEIGH_RETRANS_TIME_MS, 4, "default");
+
+ if ((stat(proc_path, &st) == 0) || (stat(proc_path2, &st) == 0)) {
+ proc_sys_retrans_time = PROC_SYS_NET_IPVx_NEIGH_RETRANS_TIME_MS;
+ } else {
+ proc_sys_retrans_time = PROC_SYS_NET_IPVx_NEIGH_RETRANS_TIME;
+ retrans_time_factor = 10;
+ }
+
+ snprintf(proc_path, sizeof(proc_path), PROC_SYS_NET_IPVx_BASE_REACHABLE_TIME_MS, 6, "default");
+ snprintf(proc_path2, sizeof(proc_path), PROC_SYS_NET_IPVx_BASE_REACHABLE_TIME, 4, "default");
+
+ if ((stat(proc_path, &st) == 0) || (stat(proc_path2, &st) == 0)) {
+ proc_sys_basereachable_time = PROC_SYS_NET_IPVx_BASE_REACHABLE_TIME_MS;
+ basereachable_time_ms = 1;
+ }
+ else {
+ proc_sys_basereachable_time = PROC_SYS_NET_IPVx_BASE_REACHABLE_TIME;
+ }
+
+#ifdef SUPPORT_PREFIX_FLAGS
+ list_info.list_head = &prefix_head_list;
+ netsnmp_prefix_listen();
+#endif
+
+#ifdef HAVE_PCI_LOOKUP_NAME
+ pci_access = pci_alloc();
+ if (pci_access)
+ pci_init(pci_access);
+ else
+ snmp_log(LOG_ERR, "Unable to create pci access method\n");
+#endif
+}
+
+/*
+ * find the ifIndex for an interface name
+ * NOTE: The Linux version is not efficient for large numbers of calls.
+ * consider using netsnmp_access_interface_ioctl_ifindex_get()
+ * for loops which need to look up a lot of indexes.
+ *
+ * @retval 0 : no index found
+ * @retval >0: ifIndex for interface
+ */
+oid
+netsnmp_arch_interface_index_find(const char *name)
+{
+ return netsnmp_access_interface_ioctl_ifindex_get(-1, name);
+}
+
+
+/*
+ * check for ipv6 addresses
+ */
+void
+_arch_interface_has_ipv6(oid if_index, u_int *flags,
+ netsnmp_container *addr_container)
+{
+#ifdef NETSNMP_ENABLE_IPV6
+ netsnmp_ipaddress_entry *addr_entry = NULL;
+ netsnmp_iterator *addr_it = NULL;
+ u_int addr_container_flags = 0; /* must init to 0 */
+#endif
+
+ if (NULL == flags)
+ return;
+
+ *flags &= ~NETSNMP_INTERFACE_FLAGS_HAS_IPV6;
+
+#ifdef NETSNMP_ENABLE_IPV6
+ /*
+ * get ipv6 addresses
+ */
+ if (NULL == addr_container) {
+ /*
+ * we only care about ipv6, if we need to allocate our own
+ * temporary container. set the flags (which we also use later
+ * to determine if we need to free the container).
+ */
+ addr_container_flags = NETSNMP_ACCESS_IPADDRESS_LOAD_IPV6_ONLY;
+ addr_container =
+ netsnmp_access_ipaddress_container_load(NULL,
+ addr_container_flags);
+ if (NULL == addr_container) {
+ DEBUGMSGTL(("access:ifcontainer",
+ "couldn't get ip addresses container\n"));
+ return;
+ }
+ }
+ else {
+ /*
+ * addr_container flags must be 0, so we don't release the
+ * user's container.
+ */
+ netsnmp_assert(0 == addr_container_flags);
+ }
+
+
+ /*
+ * get an ipaddress container iterator, and look for ipv6 addrs
+ */
+ addr_it = CONTAINER_ITERATOR(addr_container);
+ if (NULL == addr_it) {
+ DEBUGMSGTL(("access:ifcontainer",
+ "couldn't get ip addresses iterator\n"));
+ if (0!=addr_container_flags)
+ netsnmp_access_ipaddress_container_free(addr_container, 0);
+ return;
+ }
+
+ addr_entry = ITERATOR_FIRST(addr_it);
+ for( ; addr_entry ; addr_entry = ITERATOR_NEXT(addr_it) ) {
+ /*
+ * skip non matching indexes and ipv4 addresses
+ */
+ if ((if_index != addr_entry->if_index) ||
+ (4 == addr_entry->ia_address_len))
+ continue;
+
+ /*
+ * found one! no need to keep looking, set the flag and bail
+ */
+ *flags |= NETSNMP_INTERFACE_FLAGS_HAS_IPV6;
+ break;
+ }
+
+ /*
+ * make mama proud and clean up after ourselves
+ */
+ ITERATOR_RELEASE(addr_it);
+ if (0!=addr_container_flags)
+ netsnmp_access_ipaddress_container_free(addr_container, 0);
+#endif
+}
+
+/**
+ * @internal
+ */
+static void
+_arch_interface_flags_v4_get(netsnmp_interface_entry *entry)
+{
+ FILE *fin;
+ char line[256];
+
+ /*
+ * get the retransmit time
+ */
+ snprintf(line,sizeof(line), proc_sys_retrans_time, 4,
+ entry->name);
+ if (!(fin = fopen(line, "r"))) {
+ DEBUGMSGTL(("access:interface",
+ "Failed to open %s\n", line));
+ }
+ else {
+ if (fgets(line, sizeof(line), fin)) {
+ entry->retransmit_v4 = atoi(line) * retrans_time_factor;
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_V4_RETRANSMIT;
+ }
+ fclose(fin);
+ }
+}
+
+#ifdef HAVE_PCI_LOOKUP_NAME
+
+/* Get value from sysfs file */
+static int sysfs_get_id(const char *path, unsigned short *id)
+{
+ FILE *fin;
+ int n;
+
+ if (!(fin = fopen(path, "r"))) {
+ DEBUGMSGTL(("access:interface",
+ "Failed to open %s\n", path));
+ return 0;
+ }
+
+ n = fscanf(fin, "%hx", id);
+ fclose(fin);
+
+ return n == 1;
+}
+
+/* Get interface description for PCI device
+ * by using sysfs to find vendor and device
+ * then lookup name (-lpci)
+ *
+ * For software interfaces there is no PCI information
+ * so description will not be set.
+ */
+static void
+_arch_interface_description_get(netsnmp_interface_entry *entry)
+{
+ const char *descr;
+ char buf[256];
+ unsigned short vendor_id, device_id;
+
+ if (!pci_access)
+ return;
+
+ snprintf(buf, sizeof(buf),
+ "/sys/class/net/%s/device/vendor", entry->name);
+
+ if (!sysfs_get_id(buf, &vendor_id))
+ return;
+
+ snprintf(buf, sizeof(buf),
+ "/sys/class/net/%s/device/device", entry->name);
+
+ if (!sysfs_get_id(buf, &device_id))
+ return;
+
+ descr = pci_lookup_name(pci_access, buf, sizeof(buf),
+ PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE,
+ vendor_id, device_id, 0, 0);
+ if (descr) {
+ free(entry->descr);
+ entry->descr = strdup(descr);
+ } else {
+ DEBUGMSGTL(("access:interface",
+ "Failed pci_lookup_name vendor=%#hx device=%#hx\n",
+ vendor_id, device_id));
+ }
+}
+#endif
+
+
+#ifdef NETSNMP_ENABLE_IPV6
+/**
+ * @internal
+ */
+static void
+_arch_interface_flags_v6_get(netsnmp_interface_entry *entry)
+{
+ FILE *fin;
+ char line[256];
+
+ /*
+ * get the retransmit time
+ */
+ snprintf(line,sizeof(line), proc_sys_retrans_time, 6,
+ entry->name);
+ if (!(fin = fopen(line, "r"))) {
+ DEBUGMSGTL(("access:interface",
+ "Failed to open %s\n", line));
+ }
+ else {
+ if (fgets(line, sizeof(line), fin)) {
+ entry->retransmit_v6 = atoi(line) * retrans_time_factor;
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_V6_RETRANSMIT;
+ }
+ fclose(fin);
+ }
+
+ /*
+ * get the forwarding status
+ */
+ snprintf(line, sizeof(line), "/proc/sys/net/ipv6/conf/%s/forwarding",
+ entry->name);
+ if (!(fin = fopen(line, "r"))) {
+ DEBUGMSGTL(("access:interface",
+ "Failed to open %s\n", line));
+ }
+ else {
+ if (fgets(line, sizeof(line), fin)) {
+ entry->forwarding_v6 = atoi(line);
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_V6_FORWARDING;
+ }
+ fclose(fin);
+ }
+
+ /*
+ * get the reachable time
+ */
+ snprintf(line, sizeof(line), proc_sys_basereachable_time, 6, entry->name);
+ if (!(fin = fopen(line, "r"))) {
+ DEBUGMSGTL(("access:interface",
+ "Failed to open %s\n", line));
+ }
+ else {
+ if (fgets(line, sizeof(line), fin)) {
+ if (basereachable_time_ms) {
+ entry->reachable_time = atoi(line); /* millisec */
+ } else {
+ entry->reachable_time = atoi(line)*1000; /* sec to millisec */
+ }
+
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_V6_REACHABLE;
+ }
+ fclose(fin);
+ }
+}
+#endif /* NETSNMP_ENABLE_IPV6 */
+
+/**
+ * @internal
+ */
+static int
+_parse_stats(netsnmp_interface_entry *entry, char *stats, int expected)
+{
+ /*
+ * 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, rec_mcast;
+ 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, rec_mcast;
+ 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
+ static const char *scan_line_to_use = NULL;
+ int scan_count;
+
+ if (10 == expected)
+ scan_line_to_use = scan_line_2_2;
+ else {
+ netsnmp_assert(5 == expected);
+ scan_line_to_use = scan_line_2_0;
+ }
+
+ while (*stats == ' ')
+ stats++;
+
+ if ((*stats == 'N') &&
+ (0 == strncmp(stats, "No statistics available",
+ strlen("No statistics available"))))
+ return -1;
+
+ /*
+ * Now parse the rest of the line (i.e. starting from 'stats')
+ * to extract the relevant statistics, and populate
+ * data structure accordingly.
+ * Use the entry flags field to indicate which counters are valid
+ */
+ rec_pkt = rec_oct = rec_err = rec_drop = rec_mcast = 0;
+ snd_pkt = snd_oct = snd_err = snd_drop = coll = 0;
+ if (scan_line_to_use == scan_line_2_2) {
+ scan_count = sscanf(stats, scan_line_to_use,
+ &rec_oct, &rec_pkt, &rec_err, &rec_drop, &rec_mcast,
+ &snd_oct, &snd_pkt, &snd_err, &snd_drop,
+ &coll);
+ if (scan_count == expected) {
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_BYTES;
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_DROPS;
+ /*
+ * 2.4 kernel includes a single multicast (input) counter?
+ */
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_MCAST_PKTS;
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_HIGH_SPEED;
+#ifdef SCNuMAX /* XXX - should be flag for 64-bit variables */
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_HIGH_BYTES;
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_HIGH_PACKETS;
+#endif
+ }
+ } else {
+ scan_count = sscanf(stats, scan_line_to_use,
+ &rec_pkt, &rec_err,
+ &snd_pkt, &snd_err, &coll);
+ if (scan_count == expected) {
+ entry->ns_flags &= ~NETSNMP_INTERFACE_FLAGS_HAS_MCAST_PKTS;
+ rec_oct = rec_drop = 0;
+ snd_oct = snd_drop = 0;
+ }
+ }
+ if(scan_count != expected) {
+ snmp_log(LOG_ERR,
+ "error scanning interface data (expected %d, got %d)\n",
+ expected, scan_count);
+ return scan_count;
+ }
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_ACTIVE;
+
+ /*
+ * linux previous to 1.3.~13 may miss transmitted loopback pkts:
+ */
+ if (!strcmp(entry->name, "lo") && rec_pkt > 0 && !snd_pkt)
+ snd_pkt = rec_pkt;
+
+ /*
+ * subtract out multicast packets from rec_pkt before
+ * we store it as unicast counter.
+ */
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_CALCULATE_UCAST;
+ entry->stats.ibytes.low = rec_oct & 0xffffffff;
+ entry->stats.iall.low = rec_pkt & 0xffffffff;
+ entry->stats.imcast.low = rec_mcast & 0xffffffff;
+ entry->stats.obytes.low = snd_oct & 0xffffffff;
+ entry->stats.oucast.low = snd_pkt & 0xffffffff;
+#ifdef SCNuMAX /* XXX - should be flag for 64-bit variables */
+ entry->stats.ibytes.high = rec_oct >> 32;
+ entry->stats.iall.high = rec_pkt >> 32;
+ entry->stats.imcast.high = rec_mcast >> 32;
+ entry->stats.obytes.high = snd_oct >> 32;
+ entry->stats.oucast.high = snd_pkt >> 32;
+#endif
+ entry->stats.ierrors = rec_err;
+ entry->stats.idiscards = rec_drop;
+ entry->stats.oerrors = snd_err;
+ entry->stats.odiscards = snd_drop;
+ entry->stats.collisions = coll;
+
+ /*
+ * calculated stats.
+ *
+ * we have imcast, but not ibcast.
+ */
+ entry->stats.inucast = entry->stats.imcast.low +
+ entry->stats.ibcast.low;
+ entry->stats.onucast = entry->stats.omcast.low +
+ entry->stats.obcast.low;
+
+ return 0;
+}
+
+/*
+ *
+ * @retval 0 success
+ * @retval -1 no container specified
+ * @retval -2 could not open /proc/net/dev
+ * @retval -3 could not create entry (probably malloc)
+ */
+int
+netsnmp_arch_interface_container_load(netsnmp_container* container,
+ u_int load_flags)
+{
+ FILE *devin;
+ char line[256];
+ netsnmp_interface_entry *entry = NULL;
+ static char scan_expected = 0;
+ int fd;
+#ifdef NETSNMP_ENABLE_IPV6
+ netsnmp_container *addr_container;
+#endif
+
+ DEBUGMSGTL(("access:interface:container:arch", "load (flags %x)\n",
+ load_flags));
+
+ if (NULL == container) {
+ snmp_log(LOG_ERR, "no container specified/found for interface\n");
+ return -1;
+ }
+
+ if (!(devin = fopen("/proc/net/dev", "r"))) {
+ DEBUGMSGTL(("access:interface",
+ "Failed to load Interface Table (linux1)\n"));
+ NETSNMP_LOGONCE((LOG_ERR, "cannot open /proc/net/dev ...\n"));
+ return -2;
+ }
+
+ /*
+ * create socket for ioctls
+ */
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if(fd < 0) {
+ snmp_log(LOG_ERR, "could not create socket\n");
+ fclose(devin);
+ return -2;
+ }
+
+#ifdef NETSNMP_ENABLE_IPV6
+ /*
+ * get ipv6 addresses
+ */
+ addr_container = netsnmp_access_ipaddress_container_load(NULL, 0);
+#endif
+
+ /*
+ * Read the first two lines of the file, containing the header
+ * This indicates which version of the kernel we're working with,
+ * and hence which statistics are actually available.
+ *
+ * Wes originally suggested parsing the field names in this header
+ * to detect the position of individual fields directly,
+ * but I suspect this is probably more trouble than it's worth.
+ */
+ fgets(line, sizeof(line), devin);
+ fgets(line, sizeof(line), devin);
+
+ if( 0 == scan_expected ) {
+ if (strstr(line, "compressed")) {
+ scan_expected = 10;
+ DEBUGMSGTL(("access:interface",
+ "using linux 2.2 kernel /proc/net/dev\n"));
+ } else {
+ scan_expected = 5;
+ DEBUGMSGTL(("access:interface",
+ "using linux 2.0 kernel /proc/net/dev\n"));
+ }
+ }
+
+ /*
+ * The rest of the file provides the statistics for each interface.
+ * Read in each line in turn, isolate the interface name
+ * and retrieve (or create) the corresponding data structure.
+ */
+ while (fgets(line, sizeof(line), devin)) {
+ char *stats, *ifstart = line;
+ u_int flags;
+ oid if_index;
+
+ flags = 0;
+ 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,
+ "interface data format error 1, line ==|%s|\n", line);
+ continue;
+ }
+ if ((scan_expected == 10) && ((stats - line) < 6)) {
+ snmp_log(LOG_ERR,
+ "interface data format error 2 (%d < 6), line ==|%s|\n",
+ (int)(stats - line), line);
+ }
+
+ DEBUGMSGTL(("9:access:ifcontainer", "processing '%s'\n", ifstart));
+
+ /*
+ * get index via ioctl.
+ * If we've met this interface before, use the same index.
+ * Otherwise find an unused index value and use that.
+ */
+ *stats++ = 0; /* null terminate name */
+
+ if_index = netsnmp_arch_interface_index_find(ifstart);
+
+ /*
+ * set address type flags.
+ * the only way I know of to check an interface for
+ * ip version is to look for ip addresses. If anyone
+ * knows a better way, put it here!
+ */
+#ifdef NETSNMP_ENABLE_IPV6
+ _arch_interface_has_ipv6(if_index, &flags, addr_container);
+#endif
+ netsnmp_access_interface_ioctl_has_ipv4(fd, ifstart, 0, &flags);
+
+ /*
+ * do we only want one address type?
+ */
+ if (((load_flags & NETSNMP_ACCESS_INTERFACE_LOAD_IP4_ONLY) &&
+ ((flags & NETSNMP_INTERFACE_FLAGS_HAS_IPV4) == 0)) ||
+ ((load_flags & NETSNMP_ACCESS_INTERFACE_LOAD_IP6_ONLY) &&
+ ((flags & NETSNMP_INTERFACE_FLAGS_HAS_IPV6) == 0))) {
+ DEBUGMSGTL(("9:access:ifcontainer",
+ "interface '%s' excluded by ip version\n",
+ ifstart));
+ continue;
+ }
+
+ entry = netsnmp_access_interface_entry_create(ifstart, 0);
+ if(NULL == entry) {
+#ifdef NETSNMP_ENABLE_IPV6
+ netsnmp_access_ipaddress_container_free(addr_container, 0);
+#endif
+ netsnmp_access_interface_container_free(container,
+ NETSNMP_ACCESS_INTERFACE_FREE_NOFLAGS);
+ fclose(devin);
+ close(fd);
+ return -3;
+ }
+ entry->ns_flags = flags; /* initial flags; we'll set more later */
+
+#ifdef HAVE_PCI_LOOKUP_NAME
+ _arch_interface_description_get(entry);
+#endif
+
+
+ /*
+ * use ioctls for some stuff
+ * (ignore rc, so we get as much info as possible)
+ */
+ netsnmp_access_interface_ioctl_physaddr_get(fd, entry);
+
+ /*
+ * physaddr should have set type. make some guesses (based
+ * on name) if not.
+ */
+ if(0 == entry->type) {
+ typedef struct _match_if {
+ int mi_type;
+ const char *mi_name;
+ } *pmatch_if, match_if;
+
+ static match_if lmatch_if[] = {
+ {IANAIFTYPE_SOFTWARELOOPBACK, "lo"},
+ {IANAIFTYPE_ETHERNETCSMACD, "eth"},
+ {IANAIFTYPE_ETHERNETCSMACD, "vmnet"},
+ {IANAIFTYPE_ISO88025TOKENRING, "tr"},
+ {IANAIFTYPE_FASTETHER, "feth"},
+ {IANAIFTYPE_GIGABITETHERNET,"gig"},
+ {IANAIFTYPE_INFINIBAND,"ib"},
+ {IANAIFTYPE_PPP, "ppp"},
+ {IANAIFTYPE_SLIP, "sl"},
+ {IANAIFTYPE_TUNNEL, "sit"},
+ {IANAIFTYPE_BASICISDN, "ippp"},
+ {IANAIFTYPE_PROPVIRTUAL, "bond"}, /* Bonding driver find fastest slave */
+ {IANAIFTYPE_PROPVIRTUAL, "vad"}, /* ANS driver - ?speed? */
+ {0, NULL} /* end of list */
+ };
+
+ int len;
+ register pmatch_if pm;
+
+ for (pm = lmatch_if; pm->mi_name; pm++) {
+ len = strlen(pm->mi_name);
+ if (0 == strncmp(entry->name, pm->mi_name, len)) {
+ entry->type = pm->mi_type;
+ break;
+ }
+ }
+ if(NULL == pm->mi_name)
+ entry->type = IANAIFTYPE_OTHER;
+ }
+
+ /*
+ * interface identifier is specified based on physaddr and type
+ */
+ switch (entry->type) {
+ case IANAIFTYPE_ETHERNETCSMACD:
+ case IANAIFTYPE_ETHERNET3MBIT:
+ case IANAIFTYPE_FASTETHER:
+ case IANAIFTYPE_FASTETHERFX:
+ case IANAIFTYPE_GIGABITETHERNET:
+ case IANAIFTYPE_FDDI:
+ case IANAIFTYPE_ISO88025TOKENRING:
+ if (NULL != entry->paddr && ETH_ALEN != entry->paddr_len)
+ break;
+
+ entry->v6_if_id_len = entry->paddr_len + 2;
+ memcpy(entry->v6_if_id, entry->paddr, 3);
+ memcpy(entry->v6_if_id + 5, entry->paddr + 3, 3);
+ entry->v6_if_id[0] ^= 2;
+ entry->v6_if_id[3] = 0xFF;
+ entry->v6_if_id[4] = 0xFE;
+
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_V6_IFID;
+ break;
+
+ case IANAIFTYPE_SOFTWARELOOPBACK:
+ entry->v6_if_id_len = 0;
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_V6_IFID;
+ break;
+ }
+
+ if (IANAIFTYPE_ETHERNETCSMACD == entry->type) {
+ unsigned long long speed;
+ unsigned long long defaultspeed = NOMINAL_LINK_SPEED;
+ if (!(entry->os_flags & IFF_RUNNING)) {
+ /*
+ * use speed 0 if the if speed cannot be determined *and* the
+ * interface is down
+ */
+ defaultspeed = 0;
+ }
+ speed = netsnmp_linux_interface_get_if_speed(fd,
+ entry->name, defaultspeed);
+ if (speed > 0xffffffffL) {
+ entry->speed = 0xffffffff;
+ } else
+ entry->speed = speed;
+ entry->speed_high = speed / 1000000LL;
+ }
+#ifdef APPLIED_PATCH_836390 /* xxx-rks ifspeed fixes */
+ else if (IANAIFTYPE_PROPVIRTUAL == entry->type)
+ entry->speed = _get_bonded_if_speed(entry);
+#endif
+ else
+ netsnmp_access_interface_entry_guess_speed(entry);
+
+ netsnmp_access_interface_ioctl_flags_get(fd, entry);
+
+ netsnmp_access_interface_ioctl_mtu_get(fd, entry);
+
+ /*
+ * Zero speed means link problem.
+ * - i'm not sure this is always true...
+ */
+ if((entry->speed == 0) && (entry->os_flags & IFF_UP)) {
+ entry->os_flags &= ~IFF_RUNNING;
+ }
+
+ /*
+ * check for promiscuous mode.
+ * NOTE: there are 2 ways to set promiscuous mode in Linux
+ * (kernels later than 2.2.something) - using ioctls and
+ * using setsockopt. The ioctl method tested here does not
+ * detect if an interface was set using setsockopt. google
+ * on IFF_PROMISC and linux to see lots of arguments about it.
+ */
+ if(entry->os_flags & IFF_PROMISC) {
+ entry->promiscuous = 1; /* boolean */
+ }
+
+ /*
+ * hardcoded max packet size
+ * (see ip_frag_reasm: if(len > 65535) goto out_oversize;)
+ */
+ entry->reasm_max_v4 = entry->reasm_max_v6 = 65535;
+ entry->ns_flags |=
+ NETSNMP_INTERFACE_FLAGS_HAS_V4_REASMMAX |
+ NETSNMP_INTERFACE_FLAGS_HAS_V6_REASMMAX;
+
+ netsnmp_access_interface_entry_overrides(entry);
+
+ if (! (load_flags & NETSNMP_ACCESS_INTERFACE_LOAD_NO_STATS))
+ _parse_stats(entry, stats, scan_expected);
+
+ if (flags & NETSNMP_INTERFACE_FLAGS_HAS_IPV4)
+ _arch_interface_flags_v4_get(entry);
+
+#ifdef NETSNMP_ENABLE_IPV6
+ if (flags & NETSNMP_INTERFACE_FLAGS_HAS_IPV6)
+ _arch_interface_flags_v6_get(entry);
+#endif /* NETSNMP_ENABLE_IPV6 */
+
+ /*
+ * add to container
+ */
+ CONTAINER_INSERT(container, entry);
+ }
+#ifdef NETSNMP_ENABLE_IPV6
+ netsnmp_access_ipaddress_container_free(addr_container, 0);
+#endif
+ fclose(devin);
+ close(fd);
+ return 0;
+}
+
+#ifndef NETSNMP_FEATURE_REMOVE_INTERFACE_ARCH_SET_ADMIN_STATUS
+int
+netsnmp_arch_set_admin_status(netsnmp_interface_entry * entry,
+ int ifAdminStatus_val)
+{
+ int and_complement;
+
+ DEBUGMSGTL(("access:interface:arch", "set_admin_status\n"));
+
+ if(IFADMINSTATUS_UP == ifAdminStatus_val)
+ and_complement = 0; /* |= */
+ else
+ and_complement = 1; /* &= ~ */
+
+ return netsnmp_access_interface_ioctl_flags_set(-1, entry,
+ IFF_UP, and_complement);
+}
+#endif /* NETSNMP_FEATURE_REMOVE_INTERFACE_ARCH_SET_ADMIN_STATUS */
+
+#ifdef HAVE_LINUX_ETHTOOL_H
+/**
+ * Determines network interface speed from ETHTOOL_GSET
+ */
+unsigned long long
+netsnmp_linux_interface_get_if_speed(int fd, const char *name,
+ unsigned long long defaultspeed)
+{
+ int ret;
+ struct ifreq ifr;
+ struct ethtool_cmd edata;
+ uint16_t speed_hi;
+ uint32_t speed;
+
+ memset(&ifr, 0, sizeof(ifr));
+ memset(&edata, 0, sizeof(edata));
+ edata.cmd = ETHTOOL_GSET;
+
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_data = (char *) &edata;
+
+ ret = ioctl(fd, SIOCETHTOOL, &ifr);
+ if (ret == -1 || edata.speed == 0) {
+ DEBUGMSGTL(("mibII/interfaces", "ETHTOOL_GSET on %s failed (%d / %d)\n",
+ ifr.ifr_name, ret, edata.speed));
+ return netsnmp_linux_interface_get_if_speed_mii(fd,name,defaultspeed);
+ }
+
+#ifdef HAVE_STRUCT_ETHTOOL_CMD_SPEED_HI
+ speed_hi = edata.speed_hi;
+#else
+ speed_hi = 0;
+#endif
+ speed = speed_hi << 16 | edata.speed;
+ if (speed == 0xffff || speed == 0xffffffffUL /*SPEED_UNKNOWN*/)
+ speed = defaultspeed;
+ /* return in bps */
+ DEBUGMSGTL(("mibII/interfaces", "ETHTOOL_GSET on %s speed = %#x -> %d\n",
+ ifr.ifr_name, speed_hi << 16 | edata.speed, speed));
+ return speed * 1000LL * 1000LL;
+}
+#endif
+
+/**
+ * Determines network interface speed from MII
+ */
+unsigned long long
+#ifdef HAVE_LINUX_ETHTOOL_H
+netsnmp_linux_interface_get_if_speed_mii(int fd, const char *name,
+ unsigned long long defaultspeed)
+#else
+netsnmp_linux_interface_get_if_speed(int fd, const char *name,
+ unsigned long long defaultspeed)
+#endif
+{
+ unsigned long long retspeed = defaultspeed;
+ struct ifreq ifr;
+
+ /* the code is based on mii-diag utility by Donald Becker
+ * see ftp://ftp.scyld.com/pub/diag/mii-diag.c
+ */
+ ushort *data = (ushort *)(&ifr.ifr_data);
+ unsigned phy_id;
+ int mii_reg, i;
+ ushort mii_val[32];
+ ushort bmcr, bmsr, nway_advert, lkpar;
+ const unsigned long long media_speeds[] = {10000000, 10000000, 100000000, 100000000, 10000000, 0};
+ /* It corresponds to "10baseT", "10baseT-FD", "100baseTx", "100baseTx-FD", "100baseT4", "Flow-control", 0, */
+
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ data[0] = 0;
+
+ /*
+ * SIOCGMIIPHY has been defined since at least kernel 2.4.10 (Sept 2001).
+ * It's probably safe to drop the interim SIOCDEVPRIVATE handling now!
+ */
+ if (ioctl(fd, SIOCGMIIPHY, &ifr) < 0) {
+ DEBUGMSGTL(("mibII/interfaces", "SIOCGMIIPHY on %s failed\n",
+ ifr.ifr_name));
+ return retspeed;
+ }
+
+ /* Begin getting mii register values */
+ phy_id = data[0];
+ for (mii_reg = 0; mii_reg < 8; mii_reg++){
+ data[0] = phy_id;
+ data[1] = mii_reg;
+ if(ioctl(fd, SIOCGMIIREG, &ifr) <0){
+ DEBUGMSGTL(("mibII/interfaces", "SIOCGMIIREG on %s failed\n", ifr.ifr_name));
+ }
+ mii_val[mii_reg] = data[3];
+ }
+ /*Parsing of mii values*/
+ /*Invalid basic mode control register*/
+ if (mii_val[0] == 0xffff || mii_val[1] == 0x0000) {
+ DEBUGMSGTL(("mibII/interfaces", "No MII transceiver present!.\n"));
+ return retspeed;
+ }
+ /* Descriptive rename. */
+ bmcr = mii_val[0]; /*basic mode control register*/
+ bmsr = mii_val[1]; /* basic mode status register*/
+ nway_advert = mii_val[4]; /* autonegotiation advertisement*/
+ lkpar = mii_val[5]; /*link partner ability*/
+
+ /*Check for link existence, returns 0 if link is absent*/
+ if ((bmsr & 0x0016) != 0x0004){
+ DEBUGMSGTL(("mibII/interfaces", "No link...\n"));
+ retspeed = 0;
+ return retspeed;
+ }
+
+ if(!(bmcr & 0x1000) ){
+ DEBUGMSGTL(("mibII/interfaces", "Auto-negotiation disabled.\n"));
+ retspeed = bmcr & 0x2000 ? 100000000 : 10000000;
+ return retspeed;
+ }
+ /* Link partner got our advertised abilities */
+ if (lkpar & 0x4000) {
+ int negotiated = nway_advert & lkpar & 0x3e0;
+ int max_capability = 0;
+ /* Scan for the highest negotiated capability, highest priority
+ (100baseTx-FDX) to lowest (10baseT-HDX). */
+ int media_priority[] = {8, 9, 7, 6, 5}; /* media_names[i-5] */
+ for (i = 0; media_priority[i]; i++){
+ if (negotiated & (1 << media_priority[i])) {
+ max_capability = media_priority[i];
+ break;
+ }
+ }
+ if (max_capability)
+ retspeed = media_speeds[max_capability - 5];
+ else
+ DEBUGMSGTL(("mibII/interfaces", "No common media type was autonegotiated!\n"));
+ }else if(lkpar & 0x00A0){
+ retspeed = (lkpar & 0x0080) ? 100000000 : 10000000;
+ }
+ return retspeed;
+}
+#ifdef SUPPORT_PREFIX_FLAGS
+void netsnmp_prefix_process(int fd, void *data);
+
+/* Open netlink socket to watch new ipv6 addresses and prefixes. */
+int netsnmp_prefix_listen()
+{
+ struct {
+ struct nlmsghdr n;
+ struct ifinfomsg r;
+ char buf[1024];
+ } req;
+
+ struct rtattr *rta;
+ int status;
+ struct sockaddr_nl localaddrinfo;
+ unsigned groups = 0;
+
+ int fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (fd < 0) {
+ snmp_log(LOG_ERR, "netsnmp_prefix_listen: Cannot create socket.\n");
+ return -1;
+ }
+
+ memset(&localaddrinfo, 0, sizeof(struct sockaddr_nl));
+
+ groups |= RTMGRP_IPV6_IFADDR;
+ groups |= RTMGRP_IPV6_PREFIX;
+ localaddrinfo.nl_family = AF_NETLINK;
+ localaddrinfo.nl_groups = groups;
+
+ if (bind(fd, (struct sockaddr*)&localaddrinfo, sizeof(localaddrinfo)) < 0) {
+ snmp_log(LOG_ERR,"netsnmp_prefix_listen: Bind failed.\n");
+ close(fd);
+ return -1;
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
+ req.n.nlmsg_type = RTM_GETLINK;
+ req.r.ifi_family = AF_INET6;
+ rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.n.nlmsg_len));
+ rta->rta_len = RTA_LENGTH(16);
+
+ status = send(fd, &req, req.n.nlmsg_len, 0);
+ if (status < 0) {
+ snmp_log(LOG_ERR,"netsnmp_prefix_listen: send failed\n");
+ close(fd);
+ return -1;
+ }
+
+ if (register_readfd(fd, netsnmp_prefix_process, NULL) != 0) {
+ snmp_log(LOG_ERR,"netsnmp_prefix_listen: error registering netlink socket\n");
+ close(fd);
+ return -1;
+ }
+ return 0;
+}
+
+/* Process one incoming netlink packets.
+ * RTM_NEWADDR and RTM_NEWPREFIX usually arrive in separate packets
+ * -> information from these packets must be stored locally and
+ * new prefix is added when information from both packets is complete.
+ */
+void netsnmp_prefix_process(int fd, void *data)
+{
+ int status;
+ char buf[16384];
+ struct nlmsghdr *nlmp;
+ struct rtattr *rtatp;
+ struct ifaddrmsg *ifa;
+ struct prefixmsg *prefix;
+ struct in6_addr *in6p;
+
+ /* these values must persist between calls */
+ static char in6pAddr[40];
+ static int have_addr = 0,have_prefix = 0;
+ static int onlink = 2,autonomous = 2; /*Assume as false*/
+
+ int iret;
+ prefix_cbx *new;
+ int len, req_len, length;
+
+ status = recv(fd, buf, sizeof(buf), 0);
+ if (status < 0) {
+ if (errno == EINTR)
+ return;
+ snmp_log(LOG_ERR,"netsnmp_prefix_listen: Receive failed.\n");
+ return;
+ }
+
+ if(status == 0){
+ DEBUGMSGTL(("access:interface:prefix", "End of File\n"));
+ return;
+ }
+
+ for(nlmp = (struct nlmsghdr *)buf; status > sizeof(*nlmp);){
+ len = nlmp->nlmsg_len;
+ req_len = len - sizeof(*nlmp);
+
+ if (req_len < 0 || len > status) {
+ snmp_log(LOG_ERR,"netsnmp_prefix_listen: Error in length.\n");
+ return;
+ }
+
+ if (!NLMSG_OK(nlmp, status)) {
+ DEBUGMSGTL(("access:interface:prefix", "NLMSG not OK\n"));
+ continue;
+ }
+
+ if (nlmp->nlmsg_type == RTM_NEWADDR || nlmp->nlmsg_type == RTM_DELADDR) {
+ ifa = NLMSG_DATA(nlmp);
+ length = nlmp->nlmsg_len;
+ length -= NLMSG_LENGTH(sizeof(*ifa));
+
+ if (length < 0) {
+ DEBUGMSGTL(("access:interface:prefix", "wrong nlmsg length %d\n", length));
+ continue;
+ }
+
+ if(!ifa->ifa_flags) {
+ rtatp = IFA_RTA(ifa);
+ while (RTA_OK(rtatp, length)) {
+ if (rtatp->rta_type == IFA_ADDRESS){
+ in6p = (struct in6_addr *) RTA_DATA(rtatp);
+ if(nlmp->nlmsg_type == RTM_DELADDR) {
+ snprintf(in6pAddr, sizeof(in6pAddr), "%04x%04x%04x%04x%04x%04x%04x%04x", NIP6(*in6p));
+ have_addr = -1;
+ break;
+ } else {
+ snprintf(in6pAddr, sizeof(in6pAddr), "%04x%04x%04x%04x%04x%04x%04x%04x", NIP6(*in6p));
+ have_addr = 1;
+ break;
+ }
+ }
+ rtatp = RTA_NEXT(rtatp,length);
+ }
+ }
+ }
+
+ if(nlmp->nlmsg_type == RTM_NEWPREFIX) {
+ prefix = NLMSG_DATA(nlmp);
+ length = nlmp->nlmsg_len;
+ length -= NLMSG_LENGTH(sizeof(*prefix));
+
+ if (length < 0) {
+ DEBUGMSGTL(("access:interface:prefix", "wrong nlmsg length %d\n", length));
+ continue;
+ }
+ have_prefix = 1;
+ if (prefix->prefix_flags & IF_PREFIX_ONLINK) {
+ onlink = 1;
+ }
+ if (prefix->prefix_flags & IF_PREFIX_AUTOCONF) {
+ autonomous = 1;
+ }
+ }
+ status -= NLMSG_ALIGN(len);
+ nlmp = (struct nlmsghdr*)((char*)nlmp + NLMSG_ALIGN(len));
+ }
+
+ if((have_addr == 1) && (have_prefix == 1)){
+ if(!(new = net_snmp_create_prefix_info (onlink, autonomous, in6pAddr)))
+ DEBUGMSGTL(("access:interface:prefix", "Unable to create prefix info\n"));
+ else {
+
+ iret = net_snmp_search_update_prefix_info (list_info.list_head, new, 0);
+ if(iret < 0) {
+ DEBUGMSGTL(("access:interface:prefix", "Unable to add/update prefix info\n"));
+ free(new);
+ }
+ if(iret == 2) /*Only when enrty already exists and we are only updating*/
+ free(new);
+ }
+ have_addr = have_prefix = 0;
+ onlink = autonomous = 2; /*Set to defaults again*/
+ } else if (have_addr == -1) {
+ iret = net_snmp_delete_prefix_info (list_info.list_head, in6pAddr);
+ if(iret < 0)
+ DEBUGMSGTL(("access:interface:prefix", "Unable to delete the prefix info\n"));
+ if(!iret)
+ DEBUGMSGTL(("access:interface:prefix", "Unable to find the node to delete\n"));
+ have_addr = 0;
+ }
+}
+#endif
+
diff --git a/agent/mibgroup/if-mib/data_access/interface_openbsd.c b/agent/mibgroup/if-mib/data_access/interface_openbsd.c
new file mode 100644
index 0000000..8340dc6
--- /dev/null
+++ b/agent/mibgroup/if-mib/data_access/interface_openbsd.c
@@ -0,0 +1,407 @@
+/*
+ * Interface MIB architecture support
+ *
+ * $Id$
+ */
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-features.h>
+#include <net-snmp/net-snmp-includes.h>
+#include "mibII/mibII_common.h"
+#include "if-mib/ifTable/ifTable_constants.h"
+
+netsnmp_feature_child_of(interface_arch_set_admin_status, interface_all)
+
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#else
+#error "linux should have sys/ioctl header"
+#endif
+
+#include <net-snmp/data_access/interface.h>
+#include <net-snmp/data_access/ipaddress.h>
+#include "if-mib/data_access/interface.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/if_media.h>
+
+#define starttime (*(const struct timeval*)netsnmp_get_agent_starttime())
+
+int
+netsnmp_openbsd_interface_get_if_speed(char *name, u_int *speed, u_int *speed_high);
+
+void
+netsnmp_arch_interface_init(void)
+{
+ /*
+ * nothing to do
+ */
+}
+
+/*
+ * find the ifIndex for an interface name
+ *
+ * @retval 0 : no index found
+ * @retval >0: ifIndex for interface
+ */
+oid
+netsnmp_arch_interface_index_find(const char *name)
+{
+ return if_nametoindex(name);
+}
+
+/* sa_len roundup macro. */
+#define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+
+/*
+ *
+ * @retval 0 success
+ * @retval -1 no container specified
+ * @retval -2 could not get interface info
+ * @retval -3 could not create entry (probably malloc)
+ */
+int
+netsnmp_arch_interface_container_load(netsnmp_container* container,
+ u_int load_flags)
+{
+ netsnmp_interface_entry *entry = NULL;
+ u_char *if_list = NULL, *cp;
+ size_t if_list_size = 0;
+ struct if_msghdr *ifp;
+ int sysctl_oid[] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0 };
+ struct ifa_msghdr *ifa;
+ struct sockaddr *a;
+ struct sockaddr_dl *adl;
+ int amask;
+ char *if_name;
+ int flags;
+
+ DEBUGMSGTL(("access:interface:container:arch",
+ "load (flags %p)\n", load_flags));
+
+ if (NULL == container) {
+ snmp_log(LOG_ERR, "no container specified/found for interface\n");
+ return -1;
+ }
+
+ if (sysctl(sysctl_oid, sizeof(sysctl_oid) / sizeof(int), 0, &if_list_size, 0, 0) == -1) {
+ snmp_log(LOG_ERR, "could not get interface info (size)\n");
+ return -2;
+ }
+
+ if_list = (u_char*)malloc(if_list_size);
+ if (if_list == NULL) {
+ snmp_log(LOG_ERR, "could not allocate memory for interface info (%u bytes)\n", if_list_size);
+ return -3;
+ } else {
+ DEBUGMSGTL(("access:interface:container:arch",
+ "allocated %u bytes for if_list\n", if_list_size));
+ }
+
+ if (sysctl(sysctl_oid, sizeof(sysctl_oid) / sizeof(int), if_list, &if_list_size, 0, 0) == -1) {
+ snmp_log(LOG_ERR, "could not get interface info\n");
+ free(if_list);
+ return -2;
+ }
+
+ /* 1st pass: create interface entries */
+ for (cp = if_list; cp < if_list + if_list_size; cp += ifp->ifm_msglen) {
+
+ ifp = (struct if_msghdr *) cp;
+ if_name = NULL;
+ flags = 0;
+ adl = NULL;
+
+ if (ifp->ifm_type != RTM_IFINFO)
+ continue;
+
+ if (ifp->ifm_addrs & RTA_IFP) {
+ a = (struct sockaddr *) (ifp + 1);
+ /* if_msghdr is followed by one or more sockaddrs, of which we need only RTA_IFP */
+ /* most of the time RTA_IFP is the first address we get, hence the shortcut */
+ if ((ifp->ifm_addrs & (~RTA_IFP - 1)) != 0) {
+ /* skip all addresses up to RTA_IFP. */
+ for (amask = (RTA_IFP >> 1); amask != 0; amask >>= 1) {
+ if (ifp->ifm_addrs & amask) { a = (struct sockaddr *) ( ((char *) a) + ROUNDUP(a->sa_len) ); }
+ }
+ }
+ adl = (struct sockaddr_dl *) a;
+ if_name = (char *) adl->sdl_data;
+ if_name[adl->sdl_nlen] = '\0';
+ }
+ if (!(ifp->ifm_addrs & RTA_IFP) || if_name == NULL) {
+ snmp_log(LOG_ERR, "ifm_index %u: no interface name in message, skipping\n", ifp->ifm_index);
+ continue;
+ }
+
+ entry = netsnmp_access_interface_entry_create(if_name, ifp->ifm_index);
+ if(NULL == entry) {
+ netsnmp_access_interface_container_free(container,
+ NETSNMP_ACCESS_INTERFACE_FREE_NOFLAGS);
+ free(if_list);
+ return -3;
+ }
+
+ /* get physical address */
+ if (adl != NULL && adl->sdl_alen > 0) {
+ entry->paddr_len = adl->sdl_alen;
+ entry->paddr = (char*)malloc(entry->paddr_len);
+ memcpy(entry->paddr, adl->sdl_data + adl->sdl_nlen, adl->sdl_alen);
+ DEBUGMSGTL(("access:interface:container:arch",
+ "%s: paddr_len=%d, entry->paddr=%x:%x:%x:%x:%x:%x\n",
+ if_name, entry->paddr_len,
+ entry->paddr[0], entry->paddr[1], entry->paddr[2],
+ entry->paddr[3], entry->paddr[4], entry->paddr[5]));
+ } else {
+ entry->paddr = (char*)malloc(6);
+ entry->paddr_len = 6;
+ memset(entry->paddr, 0, 6);
+ }
+
+ entry->mtu = ifp->ifm_data.ifi_mtu;
+ entry->type = ifp->ifm_data.ifi_type;
+
+
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_IF_FLAGS;
+ entry->os_flags = ifp->ifm_flags;
+
+ if (ifp->ifm_flags & IFF_UP) {
+ entry->admin_status = IFADMINSTATUS_UP;
+#if defined( LINK_STATE_UP ) && defined( LINK_STATE_DOWN )
+ if (ifp->ifm_data.ifi_link_state == LINK_STATE_UP) {
+ entry->oper_status = IFOPERSTATUS_UP;
+ } else if (ifp->ifm_data.ifi_link_state == LINK_STATE_DOWN) {
+ entry->oper_status = IFOPERSTATUS_DOWN;
+ } else {
+ entry->oper_status = IFOPERSTATUS_UNKNOWN;
+ }
+#else
+ entry->oper_status = IFOPERSTATUS_UP;
+#endif
+ } else {
+ entry->admin_status = IFADMINSTATUS_DOWN;
+ /* IF-MIB specifically says that ifOperStatus should be down in this case */
+ entry->oper_status = IFOPERSTATUS_DOWN;
+ }
+
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_V4_REASMMAX;
+ entry->reasm_max = IP_MAXPACKET;
+
+ /* get counters */
+ entry->stats.ibytes.low = ifp->ifm_data.ifi_ibytes; entry->stats.ibytes.high = 0;
+ entry->stats.iucast.low = ifp->ifm_data.ifi_ipackets; entry->stats.iucast.high = 0;
+ entry->stats.imcast.low = ifp->ifm_data.ifi_imcasts; entry->stats.imcast.high = 0;
+ entry->stats.ierrors = ifp->ifm_data.ifi_ierrors;
+ entry->stats.idiscards = ifp->ifm_data.ifi_iqdrops;
+ entry->stats.iunknown_protos = ifp->ifm_data.ifi_noproto;
+
+ entry->stats.obytes.low = ifp->ifm_data.ifi_obytes; entry->stats.obytes.high = 0;
+ entry->stats.oucast.low = ifp->ifm_data.ifi_opackets; entry->stats.oucast.high = 0;
+ entry->stats.omcast.low = ifp->ifm_data.ifi_omcasts; entry->stats.omcast.high = 0;
+ entry->stats.oerrors = ifp->ifm_data.ifi_oerrors;
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_BYTES |
+ NETSNMP_INTERFACE_FLAGS_HAS_DROPS |
+ NETSNMP_INTERFACE_FLAGS_HAS_MCAST_PKTS;
+
+ if (timercmp(&ifp->ifm_data.ifi_lastchange, &starttime, >)) {
+ entry->lastchange = (ifp->ifm_data.ifi_lastchange.tv_sec - starttime.tv_sec) * 100;
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_LASTCHANGE;
+ } else {
+ entry->lastchange = 0;
+ }
+
+ if (ifp->ifm_flags & IFF_PROMISC) entry->promiscuous = 1;
+
+ /* try to guess the speed from media type */
+ netsnmp_openbsd_interface_get_if_speed(entry->name, &entry->speed, &entry->speed_high);
+ if (entry->speed_high != 0) {
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_HIGH_SPEED;
+ } else {
+ /* or resort to ifi_baudrate */
+ entry->speed = ifp->ifm_data.ifi_baudrate;
+ }
+
+ netsnmp_access_interface_entry_overrides(entry);
+
+ CONTAINER_INSERT(container, entry);
+ DEBUGMSGTL(("access:interface:container:arch",
+ "created entry %u for %s\n", entry->index, entry->name));
+ } /* for (each interface entry) */
+
+ /* pass 2: walk addresses */
+ for (cp = if_list; cp < if_list + if_list_size; cp += ifa->ifam_msglen) {
+
+ ifa = (struct ifa_msghdr *) cp;
+
+ if (ifa->ifam_type != RTM_NEWADDR)
+ continue;
+
+ DEBUGMSGTL(("access:interface:container:arch",
+ "received 0x%x in RTM_NEWADDR for ifindex %u\n",
+ ifa->ifam_addrs, ifa->ifam_index));
+
+ entry = netsnmp_access_interface_entry_get_by_index(container, ifa->ifam_index);
+ if (entry == NULL) {
+ snmp_log(LOG_ERR, "address for a nonexistent interface? index=%d", ifa->ifam_index);
+ continue;
+ }
+
+ /* walk the list of addresses received.
+ we do not use actual addresses, the sole purpose of this is to set flags */
+ a = (struct sockaddr *) (ifa + 1);
+ for (amask = ifa->ifam_addrs; amask != 0; amask >>= 1) {
+ if ((amask & 1) != 0) {
+ DEBUGMSGTL(("access:interface:container:arch",
+ "%s: a=%p, sa_len=%d, sa_family=0x%x\n",
+ entry->name, a, a->sa_len, a->sa_family));
+
+ if (a->sa_family == AF_INET)
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_IPV4;
+ else if (a->sa_family == AF_INET6)
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_IPV6;
+
+ a = (struct sockaddr *) ( ((char *) a) + ROUNDUP(a->sa_len) );
+ }
+ }
+ DEBUGMSGTL(("access:interface:container:arch",
+ "%s: flags=0x%x\n", entry->name, entry->ns_flags));
+ }
+
+ if (if_list != NULL)
+ free(if_list);
+
+ return 0;
+}
+
+/*
+ * subroutine to translate known media typed to speed.
+ * see /usr/include/net/if_media.h for definitions
+ */
+
+void
+_openbsd_interface_ifmedia_to_speed(int media, u_int *speed, u_int *speed_high)
+{
+ *speed = 0; *speed_high = 0;
+
+ switch (IFM_TYPE(media)) {
+ case IFM_ETHER:
+ switch (IFM_SUBTYPE(media)) {
+ case IFM_10_T:
+ case IFM_10_2:
+ case IFM_10_5:
+ case IFM_10_STP:
+ case IFM_10_FL:
+ *speed = 10000000; *speed_high = 10; break;
+ case IFM_100_TX:
+ case IFM_100_FX:
+ case IFM_100_T4:
+ case IFM_100_VG:
+ case IFM_100_T2:
+ *speed = 100000000; *speed_high = 100; break;
+ case IFM_1000_LX:
+ case IFM_1000_SX:
+ case IFM_1000_CX:
+#ifdef IFM_1000_T
+ case IFM_1000_T:
+#endif
+ *speed = 1000000000; *speed_high = 1000; break;
+#ifdef IFM_10GBASE_SR
+ case IFM_10GBASE_SR:
+ case IFM_10GBASE_LR:
+ *speed = (u_int) -1; /* 4294967295; */ *speed_high = 10000; break;
+#endif
+ }
+ break;
+ }
+ return;
+}
+
+/*
+ * @retval 0 speed could not be determined (error, unknown media)
+ * @retval >0 speed, equal to *speed.
+ * sets *speed=2^31 and returns *speed_high=speed/10^6 as required by ifSpeed/ifHighSpeed.
+ */
+
+int
+netsnmp_openbsd_interface_get_if_speed(char *name, u_int *speed, u_int *speed_high)
+{
+ int s;
+ struct ifmediareq ifmr;
+ int *media_list, i;
+ u_int t_speed, t_speed_high;
+ u_int m_speed, m_speed_high;
+
+ *speed = 0; *speed_high = 0;
+
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ return 0;
+ }
+
+ memset(&ifmr, 0, sizeof(ifmr));
+ strlcpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
+
+ if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0 || ifmr.ifm_count == 0) {
+ close(s);
+ return 0;
+ }
+
+ /*
+ * try to get speed from current media.
+ * if unsuccessful (e.g., interface is down), get a list of capabilities,
+ * try each and return maximum speed the interface is capable of.
+ */
+
+ _openbsd_interface_ifmedia_to_speed(ifmr.ifm_current, speed, speed_high);
+
+ if (*speed == 0 &&
+ (media_list = (int *) malloc(ifmr.ifm_count * sizeof(int))) != NULL ) {
+
+ ifmr.ifm_ulist = media_list;
+
+ if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) == 0) {
+ m_speed = 0; m_speed_high = 0;
+ for (i = 0; i < ifmr.ifm_count; i++) {
+
+ _openbsd_interface_ifmedia_to_speed(media_list[i], &t_speed, &t_speed_high);
+
+ if (t_speed_high > m_speed_high ||
+ (t_speed_high == m_speed_high && t_speed > t_speed)) {
+ m_speed_high = t_speed_high; m_speed = t_speed;
+ }
+ }
+ *speed = m_speed; *speed_high = m_speed_high;
+ }
+ free(media_list);
+ }
+
+ close(s);
+
+ DEBUGMSGTL(("access:interface:container:arch",
+ "%s: speed: %u, speed_high: %u\n",
+ name, *speed, *speed_high));
+
+ return *speed;
+}
+
+#ifndef NETSNMP_FEATURE_REMOVE_INTERFACE_ARCH_SET_ADMIN_STATUS
+int
+netsnmp_arch_set_admin_status(netsnmp_interface_entry * entry,
+ int ifAdminStatus_val)
+{
+ DEBUGMSGTL(("access:interface:arch", "set_admin_status\n"));
+
+ /* TODO: implement this call */
+
+ /* not implemented */
+ snmp_log(LOG_ERR, "netsnmp_arch_set_admin_status is not (yet) implemented for FreeBSD.\n");
+
+ return -4;
+}
+#endif /* NETSNMP_FEATURE_REMOVE_INTERFACE_ARCH_SET_ADMIN_STATUS */
+
diff --git a/agent/mibgroup/if-mib/data_access/interface_solaris2.c b/agent/mibgroup/if-mib/data_access/interface_solaris2.c
new file mode 100644
index 0000000..8aa47f8
--- /dev/null
+++ b/agent/mibgroup/if-mib/data_access/interface_solaris2.c
@@ -0,0 +1,363 @@
+/*
+ * Interface MIB architecture support for Solaris
+ */
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-features.h>
+#include <net-snmp/net-snmp-includes.h>
+#include "if-mib/ifTable/ifTable_constants.h"
+#include "kernel_sunos5.h"
+#include "mibII/mibII_common.h"
+
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+
+#include <net-snmp/data_access/interface.h>
+#include "if-mib/data_access/interface.h"
+#include <sys/ioctl.h>
+#include <sys/sockio.h>
+#include <strings.h>
+#include <string.h>
+
+netsnmp_feature_child_of(interface_arch_set_admin_status, interface_all)
+
+static int _set_ip_flags_v4(netsnmp_interface_entry *, mib2_ifEntry_t *);
+static int _match_ifname_v4addr(void *ifname, void *ipaddr);
+static int _get_v4addr(mib2_ifEntry_t *ife, mib2_ipAddrEntry_t *e);
+
+static int _set_ip_flags_v6(netsnmp_interface_entry *, mib2_ifEntry_t *);
+#ifdef SOLARIS_HAVE_IPV6_MIB_SUPPORT
+static int _get_v6addr(mib2_ifEntry_t *ife, mib2_ipv6AddrEntry_t *ipv6e);
+static int _match_ifname_v6addr(void *ifname, void *ipaddr);
+#endif
+
+void
+netsnmp_arch_interface_init(void)
+{
+ init_kernel_sunos5();
+}
+
+/*
+ * find the ifIndex for an interface name
+ *
+ * @retval 0 : no index found
+ * @retval >0: ifIndex for interface
+ */
+oid
+netsnmp_arch_interface_index_find(const char *name)
+{
+#if defined(HAVE_IF_NAMETOINDEX)
+ return if_nametoindex(name);
+#else /* use GIFINDEX */
+ return solaris2_if_nametoindex(name, strlen(name));
+#endif /* defined(HAVE_IF_NAMETOINDEX) */
+}
+
+/*
+ * @retval 0 success
+ * @retval -1 no container specified
+ * @retval -2 could not create entry (probably malloc)
+ */
+int
+netsnmp_arch_interface_container_load(netsnmp_container* container,
+ u_int l_flags)
+{
+ netsnmp_interface_entry *entry = NULL;
+ mib2_ifEntry_t ife;
+ int rc;
+ req_e req = GET_FIRST;
+ int error = 0;
+
+ DEBUGMSGTL(("access:interface:container:arch", "load (flags %u)\n",
+ l_flags));
+
+ if (container == NULL) {
+ snmp_log(LOG_ERR,
+ "no container specified/found for interface\n");
+ return -1;
+ }
+
+ while ((rc = getMibstat(MIB_INTERFACES, &ife, sizeof(ife), req,
+ &Get_everything, NULL)) == 0) {
+
+ req = GET_NEXT;
+
+ DEBUGMSGTL(("access:interface:container:arch",
+ "processing '%s'\n", ife.ifDescr.o_bytes));
+ entry =
+ netsnmp_access_interface_entry_create(ife.ifDescr.o_bytes,
+ ife.ifIndex);
+ if (entry == NULL) {
+ error = 1;
+ break;
+ }
+ entry->ns_flags = 0;
+
+ if (l_flags & NETSNMP_ACCESS_INTERFACE_LOAD_IP4_ONLY &&
+ _set_ip_flags_v4(entry, &ife) == 0) {
+ netsnmp_access_interface_entry_free(entry);
+ continue;
+ } else if (l_flags & NETSNMP_ACCESS_INTERFACE_LOAD_IP6_ONLY &&
+ _set_ip_flags_v6(entry, &ife) == 0) {
+ netsnmp_access_interface_entry_free(entry);
+ continue;
+ } else {
+ (void) _set_ip_flags_v4(entry, &ife);
+ (void) _set_ip_flags_v6(entry, &ife);
+ }
+
+ /*
+ * collect the information needed by IF-MIB
+ */
+ entry->paddr = (char*)malloc(ife.ifPhysAddress.o_length);
+ if (entry->paddr == NULL) {
+ netsnmp_access_interface_entry_free(entry);
+ error = 1;
+ break;
+ }
+ entry->paddr_len = ife.ifPhysAddress.o_length;
+ (void)memcpy(entry->paddr, ife.ifPhysAddress.o_bytes,
+ ife.ifPhysAddress.o_length);
+
+ entry->type = ife.ifType;
+ entry->mtu = ife.ifMtu;
+ entry->speed = ife.ifSpeed;
+ entry->speed_high = entry->speed / 1000000;
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_HIGH_SPEED;
+ entry->oper_status = ife.ifOperStatus;
+ entry->admin_status = ife.ifAdminStatus;
+
+ if (ife.flags & IFF_PROMISC)
+ entry->promiscuous = 1;
+
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_ACTIVE;
+
+ /*
+ * Interface Stats.
+ */
+ if (! (l_flags & NETSNMP_ACCESS_INTERFACE_LOAD_NO_STATS)) {
+ entry->ns_flags |=
+ NETSNMP_INTERFACE_FLAGS_HAS_BYTES |
+ NETSNMP_INTERFACE_FLAGS_HAS_DROPS |
+ NETSNMP_INTERFACE_FLAGS_HAS_MCAST_PKTS;
+ if (ife.ifHCInOctets > 0 || ife.ifHCOutOctets > 0) {
+ /*
+ * We make the assumption that if we have
+ * a 64-bit Octet counter, then the other
+ * counters are 64-bit as well.
+ */
+ DEBUGMSGTL(("access:interface:container:arch",
+ "interface '%s' have 64-bit stat counters\n",
+ entry->name));
+ entry->ns_flags |=
+ NETSNMP_INTERFACE_FLAGS_HAS_HIGH_BYTES |
+ NETSNMP_INTERFACE_FLAGS_HAS_HIGH_PACKETS;
+ /* in stats */
+ entry->stats.ibytes.low = ife.ifHCInOctets & 0xffffffff;
+ entry->stats.ibytes.high = ife.ifHCInOctets >> 32;
+ entry->stats.iucast.low = ife.ifHCInUcastPkts & 0xffffffff;
+ entry->stats.iucast.high = ife.ifHCInUcastPkts >> 32;
+ entry->stats.imcast.low = ife.ifHCInMulticastPkts & 0xffffffff;
+ entry->stats.imcast.high = ife.ifHCInMulticastPkts >> 32;
+ entry->stats.ibcast.low = ife.ifHCInBroadcastPkts & 0xffffffff;
+ entry->stats.ibcast.high = ife.ifHCInBroadcastPkts >> 32;
+ /* out stats */
+ entry->stats.obytes.low = ife.ifHCOutOctets & 0xffffffff;
+ entry->stats.obytes.high = ife.ifHCOutOctets >> 32;
+ entry->stats.oucast.low = ife.ifHCOutUcastPkts & 0xffffffff;
+ entry->stats.oucast.high = ife.ifHCOutUcastPkts >> 32;
+ entry->stats.omcast.low = ife.ifHCOutMulticastPkts & 0xffffffff;
+ entry->stats.omcast.high = ife.ifHCOutMulticastPkts >> 32;
+ entry->stats.obcast.low = ife.ifHCOutBroadcastPkts & 0xffffffff;
+ entry->stats.obcast.high = ife.ifHCOutBroadcastPkts >> 32;
+ } else {
+ DEBUGMSGTL(("access:interface:container:arch",
+ "interface '%s' have 32-bit stat counters\n",
+ entry->name));
+ /* in stats */
+ entry->stats.ibytes.low = ife.ifInOctets;
+ entry->stats.iucast.low = ife.ifInUcastPkts;
+ entry->stats.imcast.low = ife.ifHCInMulticastPkts & 0xffffffff;
+ entry->stats.ibcast.low = ife.ifHCInBroadcastPkts & 0xffffffff;
+ /* out stats */
+ entry->stats.obytes.low = ife.ifOutOctets;
+ entry->stats.oucast.low = ife.ifOutUcastPkts;
+ entry->stats.omcast.low = ife.ifHCOutMulticastPkts & 0xffffffff;
+ entry->stats.obcast.low = ife.ifHCOutBroadcastPkts & 0xffffffff;
+ }
+ /* in stats */
+ entry->stats.ierrors = ife.ifInErrors;
+ entry->stats.idiscards = ife.ifInDiscards;
+ entry->stats.iunknown_protos = ife.ifInUnknownProtos;
+ entry->stats.inucast = ife.ifInNUcastPkts;
+ /* out stats */
+ entry->stats.oerrors = ife.ifOutErrors;
+ entry->stats.odiscards = ife.ifOutDiscards;
+ entry->stats.onucast = ife.ifOutNUcastPkts;
+ entry->stats.oqlen = ife.ifOutQLen;
+
+ /* other stats */
+ entry->stats.collisions = ife.ifCollisions;
+ }
+
+ netsnmp_access_interface_entry_overrides(entry);
+
+ /*
+ * add to container
+ */
+ CONTAINER_INSERT(container, entry);
+ }
+ DEBUGMSGTL(("access:interface:container:arch", "rc = %d\n", rc));
+
+ if (error) {
+ DEBUGMSGTL(("access:interface:container:arch",
+ "error %d, free container\n", error));
+ netsnmp_access_interface_container_free(container,
+ NETSNMP_ACCESS_INTERFACE_FREE_NOFLAGS);
+ return -2;
+ }
+
+ return 0;
+}
+/**
+ * @internal
+ */
+static int
+_set_ip_flags_v4(netsnmp_interface_entry *entry, mib2_ifEntry_t *ife)
+{
+ mib2_ipAddrEntry_t ipv4e;
+
+ if (_get_v4addr(ife, &ipv4e) > 0) {
+ entry->reasm_max_v4 = ipv4e.ipAdEntReasmMaxSize;
+ entry->ns_flags |=
+ NETSNMP_INTERFACE_FLAGS_HAS_IPV4 |
+ NETSNMP_INTERFACE_FLAGS_HAS_V4_REASMMAX;
+#if defined( SOLARIS_HAVE_RFC4293_SUPPORT )
+ entry->retransmit_v4 = ipv4e.ipAdEntRetransmitTime;
+ entry->ns_flags |=
+ NETSNMP_INTERFACE_FLAGS_HAS_V4_RETRANSMIT;
+#endif
+ return (1);
+ }
+ return (0);
+}
+
+/**
+ * @internal
+ */
+static int
+_set_ip_flags_v6(netsnmp_interface_entry *entry, mib2_ifEntry_t *ife)
+{
+#ifdef SOLARIS_HAVE_IPV6_MIB_SUPPORT
+ mib2_ipv6AddrEntry_t ipv6e;
+
+ if (_get_v6addr(ife, &ipv6e) > 0) {
+ entry->ns_flags |=
+ NETSNMP_INTERFACE_FLAGS_HAS_IPV6;
+#if defined( SOLARIS_HAVE_RFC4293_SUPPORT )
+ if (ipv6e.ipv6AddrIdentifierLen <= sizeof(entry->v6_if_id)) {
+ entry->v6_if_id_len = ipv6e.ipv6AddrIdentifierLen;
+ (void)memcpy(&entry->v6_if_id, &ipv6e.ipv6AddrIdentifier,
+ entry->v6_if_id_len);
+ entry->ns_flags |=
+ NETSNMP_INTERFACE_FLAGS_HAS_V6_IFID;
+ }
+ entry->reasm_max_v6 = ipv6e.ipv6AddrReasmMaxSize;
+ entry->retransmit_v6 = ipv6e.ipv6AddrRetransmitTime;
+ entry->reachable_time = ipv6e.ipv6AddrReachableTime;
+ entry->ns_flags |=
+ NETSNMP_INTERFACE_FLAGS_HAS_V6_REASMMAX |
+ NETSNMP_INTERFACE_FLAGS_HAS_V6_RETRANSMIT |
+ NETSNMP_INTERFACE_FLAGS_HAS_V6_REACHABLE;
+
+ /* XXX forwarding info missing */
+#else
+ /* XXX Don't have this info, 1500 is the minimum */
+ entry->reasm_max_v6 = 1500;
+ entry->ns_flags |=
+ NETSNMP_INTERFACE_FLAGS_HAS_V6_REASMMAX; /* ??? */
+#endif /* SOLARIS_HAVE_RFC4293_SUPPORT */
+ return (1);
+ }
+#endif /* SOLARIS_HAVE_IPV6_MIB_SUPPORT */
+ return (0);
+}
+
+/**
+ * @internal
+ */
+static int
+_match_ifname_v4addr(void *ifname, void *ipaddr)
+{
+ DeviceName *devname = &((mib2_ipAddrEntry_t *)ipaddr)->ipAdEntIfIndex;
+
+ return (strncmp((char *)ifname, devname->o_bytes, devname->o_length));
+
+}
+
+/**
+ * @internal
+ *
+ * Search for address entry that belongs to the IF entry.
+ * Returns 1 if an address was found, in which case the entry
+ * will be stored in ipv4e. If not entry was found, 0 is returned.
+ *
+ */
+static int
+_get_v4addr(mib2_ifEntry_t *ife, mib2_ipAddrEntry_t *ipv4e)
+{
+ int rc;
+
+ if ((rc = getMibstat(MIB_IP_ADDR, ipv4e, sizeof(*ipv4e), GET_EXACT,
+ &_match_ifname_v4addr, &ife->ifDescr.o_bytes)) == 0)
+ return (1);
+ memset(ipv4e, '\0', sizeof(*ipv4e));
+ return (0);
+}
+
+#ifdef SOLARIS_HAVE_IPV6_MIB_SUPPORT
+/**
+ * @internal
+ */
+static int
+_match_ifname_v6addr(void *ifname, void *ipaddr)
+{
+ DeviceName *devname = &((mib2_ipv6AddrEntry_t*)ipaddr)->ipv6AddrIfIndex;
+
+ return (strncmp((char *)ifname, devname->o_bytes, devname->o_length));
+
+}
+
+/**
+ * @internal
+ *
+ * Search for address entry that belongs to the IF entry.
+ * Returns 1 if an address was found, in which case the entry
+ * will be stored in ipv4e. If not entry was found, 0 is returned.
+ *
+ */
+static int
+_get_v6addr(mib2_ifEntry_t *ife, mib2_ipv6AddrEntry_t *ipv6e)
+{
+ int rc;
+
+ if ((rc = getMibstat(MIB_IP6_ADDR, ipv6e, sizeof(*ipv6e), GET_EXACT,
+ &_match_ifname_v6addr, &ife->ifDescr.o_bytes)) == 0) {
+ return (1);
+ }
+ memset(ipv6e, '\0', sizeof(*ipv6e));
+ return (0);
+}
+#endif /* SOLARIS_HAVE_IPV6_MIB_SUPPORT */
+
+#ifndef NETSNMP_FEATURE_REMOVE_INTERFACE_ARCH_SET_ADMIN_STATUS
+int
+netsnmp_arch_set_admin_status(netsnmp_interface_entry * entry,
+ int ifAdminStatus_val)
+{
+ DEBUGMSGTL(("access:interface:arch", "set_admin_status\n"));
+
+ /*
+ * XXX Not supported yet
+ */
+ return (-1);
+}
+#endif /* NETSNMP_FEATURE_REMOVE_INTERFACE_ARCH_SET_ADMIN_STATUS */
diff --git a/agent/mibgroup/if-mib/data_access/interface_sysctl.c b/agent/mibgroup/if-mib/data_access/interface_sysctl.c
new file mode 100644
index 0000000..1deff82
--- /dev/null
+++ b/agent/mibgroup/if-mib/data_access/interface_sysctl.c
@@ -0,0 +1,581 @@
+/*
+ * Interface MIB architecture support
+ *
+ * Based on patch 1362403, submited by Rojer
+ *
+ * $Id$
+ */
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-features.h>
+#include <net-snmp/net-snmp-includes.h>
+#include "mibII/mibII_common.h"
+#include "if-mib/ifTable/ifTable_constants.h"
+
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#else
+#error "BSD should have sys/ioctl header"
+#endif
+
+#include <net-snmp/data_access/interface.h>
+#include <net-snmp/data_access/ipaddress.h>
+#include "if-mib/data_access/interface.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/if_media.h>
+
+netsnmp_feature_child_of(interface_arch_set_admin_status, interface_all)
+
+/*
+ * account for minor differences between FreeBSD and OpenBSD.
+ * If this gets unruly, split stuff out into the respective
+ * files (interface_*BDS.c).
+ */
+/*
+ * FreeBSD has 2 promiscuous flags: kernel/user; check either
+ * http://unix.derkeiler.com/Mailing-Lists/FreeBSD/net/2004-09/0289.html
+ * which says:
+ * The first flag (IFF_PROMISC) is the one that the kernel code uses and
+ * sets on an interface's ifp structure. The second one is the one that
+ * comes from user space programs and is sent to the routine ifhwioctl()
+ * to set the first flag.
+ */
+#ifdef IFF_PPROMISC
+# define ARCH_PROMISC_FLAG (IFF_PPROMISC|IFF_PROMISC)
+#else
+# define ARCH_PROMISC_FLAG IFF_PROMISC
+#endif
+
+#define starttime (*(const struct timeval*)netsnmp_get_agent_starttime())
+
+/* sa_len roundup macro. */
+#define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+
+void
+netsnmp_arch_interface_init(void)
+{
+ /*
+ * nothing to do
+ */
+}
+
+/*
+ * find the ifIndex for an interface name
+ *
+ * @retval 0 : no index found
+ * @retval >0: ifIndex for interface
+ */
+oid
+netsnmp_arch_interface_index_find(const char *name)
+{
+ return if_nametoindex(name);
+}
+
+/*
+ * subroutine to translate known media typed to speed.
+ * see /usr/include/net/if_media.h for definitions
+ */
+
+void
+netsnmp_sysctl_ifmedia_to_speed(int media, u_int *speed,
+ u_int *speed_high)
+{
+ *speed = 0;
+ *speed_high = 0;
+
+ switch (IFM_TYPE(media)) {
+ case IFM_ETHER:
+ switch (IFM_SUBTYPE(media)) {
+ case IFM_10_T:
+ case IFM_10_2:
+ case IFM_10_5:
+ case IFM_10_STP:
+ case IFM_10_FL:
+ *speed = 10000000;
+ *speed_high = 10; break;
+ case IFM_100_TX:
+ case IFM_100_FX:
+ case IFM_100_T4:
+ case IFM_100_VG:
+ case IFM_100_T2:
+ *speed = 100000000;
+ *speed_high = 100; break;
+ case IFM_1000_LX:
+ case IFM_1000_CX:
+#ifdef IFM_1000_T
+ case IFM_1000_T:
+#endif
+ *speed = 1000000000;
+ *speed_high = 1000; break;
+#ifdef IFM_10GBASE_SR
+ case IFM_10GBASE_SR:
+ case IFM_10GBASE_LR:
+ *speed = (u_int) -1; /* 4294967295; */
+ *speed_high = 10000; break;
+#endif
+ }
+ break;
+ case IFM_IEEE80211:
+ switch (IFM_SUBTYPE(media)) {
+ case IFM_IEEE80211_FH1:
+ case IFM_IEEE80211_DS1:
+ *speed = 1000000;
+ *speed_high = 1;
+ break;
+ case IFM_IEEE80211_FH2:
+ case IFM_IEEE80211_DS2:
+ *speed = 2000000;
+ *speed_high = 2;
+ break;
+ case IFM_IEEE80211_DS5:
+ *speed = 5500000;
+ *speed_high = 5;
+ break;
+ case IFM_IEEE80211_DS11:
+ *speed = 11000000;
+ *speed_high = 11;
+ break;
+ case IFM_IEEE80211_DS22:
+ *speed = 22000000;
+ *speed_high = 22;
+ break;
+#ifdef IFM_IEEE80211_OFDM6
+ case IFM_IEEE80211_OFDM6:
+ *speed = 6000000;
+ *speed_high = 6;
+ break;
+ case IFM_IEEE80211_OFDM9:
+ *speed = 9000000;
+ *speed_high = 9;
+ break;
+ case IFM_IEEE80211_OFDM12:
+ *speed = 12000000;
+ *speed_high = 12;
+ break;
+ case IFM_IEEE80211_OFDM18:
+ *speed = 18000000;
+ *speed_high = 18;
+ break;
+ case IFM_IEEE80211_OFDM24:
+ *speed = 24000000;
+ *speed_high = 24;
+ break;
+ case IFM_IEEE80211_OFDM36:
+ *speed = 36000000;
+ *speed_high = 36;
+ break;
+ case IFM_IEEE80211_OFDM48:
+ *speed = 48000000;
+ *speed_high = 48;
+ break;
+ case IFM_IEEE80211_OFDM54:
+ *speed = 54000000;
+ *speed_high = 54;
+ break;
+ case IFM_IEEE80211_OFDM72:
+ *speed = 72000000;
+ *speed_high = 72;
+ break;
+#endif
+ }
+ break;
+#if defined(IFM_TOKEN)
+ case IFM_TOKEN:
+ switch (IFM_SUBTYPE(media)) {
+ case IFM_TOK_STP4:
+ case IFM_TOK_UTP4:
+ *speed = 4000000;
+ *speed_high = 4;
+ break;
+ case IFM_TOK_STP16:
+ case IFM_TOK_UTP16:
+ *speed = 16000000;
+ *speed_high = 16;
+ break;
+#if defined(IFM_TOK_STP100) /* guessing if you've got one, you've got the other.. */
+ case IFM_TOK_STP100:
+ case IFM_TOK_UTP100:
+ *speed = 100000000;
+ *speed_high = 100;
+ break;
+#endif /* IFM_TOK_STP100 */
+ }
+ break;
+#endif /* IFM_TOKEN */
+#ifdef IFM_ATM
+ case IFM_ATM:
+ switch (IFM_SUBTYPE(media)) {
+ case IFM_ATM_MM_155:
+ case IFM_ATM_SM_155:
+ *speed = 155000000;
+ *speed_high = 155;
+ break;
+ case IFM_ATM_MM_622:
+ case IFM_ATM_SM_622:
+ *speed = 622000000;
+ *speed_high = 622;
+ break;
+ }
+#endif
+ }
+ return;
+}
+
+/*
+ * @retval 0 speed could not be determined (error, unknown media)
+ * @retval >0 speed, equal to *speed.
+ * sets *speed=2^31 and returns *speed_high=speed/10^6 as required
+ * by ifSpeed/ifHighSpeed.
+ */
+
+int
+netsnmp_sysctl_get_if_speed(char *name, u_int *speed,
+ u_int *speed_high)
+{
+ int s;
+ struct ifmediareq ifmr;
+ int *media_list, i;
+ u_int t_speed, t_speed_high;
+ u_int m_speed, m_speed_high;
+
+ *speed = 0;
+ *speed_high = 0;
+
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ return 0;
+ }
+
+ memset(&ifmr, 0, sizeof(ifmr));
+ strlcpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
+
+ DEBUGMSGTL(("access:interface:container:sysctl"," speed in\n"));
+ if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0 ||
+ ifmr.ifm_count == 0) {
+
+ close(s);
+ return 0;
+ }
+
+ /*
+ * try to get speed from current media.
+ * if unsuccessful (e.g., interface is down), get a list of capabilities,
+ * try each and return maximum speed the interface is capable of.
+ */
+
+ netsnmp_sysctl_ifmedia_to_speed(ifmr.ifm_current, speed, speed_high);
+
+ if (*speed == 0 &&
+ (media_list = (int *) malloc(ifmr.ifm_count * sizeof(int))) != NULL ) {
+
+ ifmr.ifm_ulist = media_list;
+
+ if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) == 0) {
+ m_speed = 0;
+ m_speed_high = 0;
+ for (i = 0; i < ifmr.ifm_count; i++) {
+
+ netsnmp_sysctl_ifmedia_to_speed(media_list[i], &t_speed,
+ &t_speed_high);
+ if (t_speed_high > m_speed_high ||
+ (t_speed_high == m_speed_high && t_speed > m_speed)) {
+ m_speed_high = t_speed_high;
+ m_speed = t_speed;
+ }
+ }
+ *speed = m_speed;
+ *speed_high = m_speed_high;
+ }
+ free(media_list);
+ }
+
+ close(s);
+
+ DEBUGMSGTL(("access:interface:container:sysctl",
+ "%s: speed: %u, speed_high: %u\n",
+ name, *speed, *speed_high));
+
+ return *speed;
+}
+
+static void set_counter(struct counter64 *c, uint64_t v)
+{
+ c->low = (uint32_t)(v);
+ c->high = (v) >> 32;
+}
+
+/*
+ *
+ * @retval 0 success
+ * @retval -1 no container specified
+ * @retval -2 could not get interface info
+ * @retval -3 could not create entry (probably malloc)
+ */
+int
+netsnmp_arch_interface_container_load(netsnmp_container* container,
+ u_int load_flags)
+{
+ netsnmp_interface_entry *entry = NULL;
+ u_char *if_list = NULL, *cp;
+ size_t if_list_size = 0;
+ struct if_msghdr *ifp;
+ int sysctl_oid[] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0 };
+ struct ifa_msghdr *ifa;
+ struct sockaddr *a;
+ struct sockaddr_dl *adl;
+ int amask;
+ char *if_name;
+ int flags;
+#ifdef HAVE_STRUCT_IFNET_IF_LASTCHANGE_TV_NSEC
+ struct timespec startspec;
+
+ TIMEVAL_TO_TIMESPEC(&starttime, &startspec);
+#endif
+
+ DEBUGMSGTL(("access:interface:container:sysctl",
+ "load (flags %u)\n", load_flags));
+
+ if (NULL == container) {
+ snmp_log(LOG_ERR, "no container specified/found for interface\n");
+ return -1;
+ }
+
+ if (sysctl(sysctl_oid, sizeof(sysctl_oid)/sizeof(int), 0,
+ &if_list_size, 0, 0) == -1) {
+ snmp_log(LOG_ERR, "could not get interface info (size)\n");
+ return -2;
+ }
+
+ if_list = (u_char*)malloc(if_list_size);
+ if (if_list == NULL) {
+ snmp_log(LOG_ERR, "could not allocate memory for interface info "
+ "(%zu bytes)\n", if_list_size);
+ return -3;
+ } else {
+ DEBUGMSGTL(("access:interface:container:sysctl",
+ "allocated %zu bytes for if_list\n", if_list_size));
+ }
+
+ if (sysctl(sysctl_oid, sizeof(sysctl_oid)/sizeof(int), if_list,
+ &if_list_size, 0, 0) == -1) {
+ snmp_log(LOG_ERR, "could not get interface info\n");
+ free(if_list);
+ return -2;
+ }
+
+ /* 1st pass: create interface entries */
+ for (cp = if_list; cp < if_list + if_list_size; cp += ifp->ifm_msglen) {
+
+ ifp = (struct if_msghdr *) cp;
+ if_name = NULL;
+ flags = 0;
+ adl = NULL;
+
+ if (ifp->ifm_type != RTM_IFINFO)
+ continue;
+
+ if (ifp->ifm_addrs & RTA_IFP) {
+ a = (struct sockaddr *) (ifp + 1);
+ /*
+ * if_msghdr is followed by one or more sockaddrs, of which we
+ * need only RTA_IFP. most of the time RTA_IFP is the first
+ * address we get, hence the shortcut.
+ */
+ if ((ifp->ifm_addrs & (~RTA_IFP - 1)) != 0) {
+ /* skip all addresses up to RTA_IFP. */
+ for (amask = (RTA_IFP >> 1); amask != 0; amask >>= 1) {
+ if (ifp->ifm_addrs & amask)
+ a = (struct sockaddr *)
+ ( ((char *) a) + ROUNDUP(a->sa_len) );
+ }
+ }
+ adl = (struct sockaddr_dl *) a;
+ if_name = (char *) adl->sdl_data;
+ if_name[adl->sdl_nlen] = '\0';
+ }
+ if (!(ifp->ifm_addrs & RTA_IFP) || if_name == NULL) {
+ snmp_log(LOG_ERR, "ifm_index %u: no interface name in message, "
+ "skipping\n", ifp->ifm_index);
+ continue;
+ }
+
+ entry = netsnmp_access_interface_entry_create(if_name, ifp->ifm_index);
+ if(NULL == entry) {
+ netsnmp_access_interface_container_free(container,
+ NETSNMP_ACCESS_INTERFACE_FREE_NOFLAGS);
+ free(if_list);
+ return -3;
+ }
+
+ /* get physical address */
+ if (adl != NULL && adl->sdl_alen > 0) {
+ entry->paddr_len = adl->sdl_alen;
+ entry->paddr = (char*)malloc(entry->paddr_len);
+ memcpy(entry->paddr, adl->sdl_data + adl->sdl_nlen, adl->sdl_alen);
+ DEBUGMSGTL(("access:interface:container:sysctl",
+ "%s: paddr_len=%d, entry->paddr=%x:%x:%x:%x:%x:%x\n",
+ if_name, entry->paddr_len,
+ entry->paddr[0], entry->paddr[1], entry->paddr[2],
+ entry->paddr[3], entry->paddr[4], entry->paddr[5]));
+ } else {
+ entry->paddr = (char*)malloc(6);
+ entry->paddr_len = 6;
+ memset(entry->paddr, 0, 6);
+ }
+
+ entry->mtu = ifp->ifm_data.ifi_mtu;
+ entry->type = ifp->ifm_data.ifi_type;
+
+
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_IF_FLAGS;
+ entry->os_flags = ifp->ifm_flags;
+
+ if (ifp->ifm_flags & IFF_UP) {
+ entry->admin_status = IFADMINSTATUS_UP;
+#if defined( LINK_STATE_UP ) && defined( LINK_STATE_DOWN )
+ if (ifp->ifm_data.ifi_link_state == LINK_STATE_UP) {
+ entry->oper_status = IFOPERSTATUS_UP;
+ } else if (ifp->ifm_data.ifi_link_state == LINK_STATE_DOWN) {
+ entry->oper_status = IFOPERSTATUS_DOWN;
+ } else
+#endif
+ {
+ /*
+ * link state is unknown, which is not very useful to report.
+ * use running state instead.
+ */
+ entry->oper_status = ifp->ifm_flags & IFF_RUNNING ? 1 : 2;
+ }
+ } else {
+ entry->admin_status = IFADMINSTATUS_DOWN;
+ /*
+ * IF-MIB specifically says that ifOperStatus should be down in
+ * this case
+ */
+ entry->oper_status = IFOPERSTATUS_DOWN;
+ }
+
+ entry->reasm_max_v4 = entry->reasm_max_v6 = IP_MAXPACKET;
+ entry->ns_flags |=
+ NETSNMP_INTERFACE_FLAGS_HAS_V4_REASMMAX |
+ NETSNMP_INTERFACE_FLAGS_HAS_V6_REASMMAX;
+
+ /* get counters */
+ set_counter(&entry->stats.ibytes, ifp->ifm_data.ifi_ibytes);
+ set_counter(&entry->stats.iucast, ifp->ifm_data.ifi_ipackets);
+ set_counter(&entry->stats.imcast, ifp->ifm_data.ifi_imcasts);
+ entry->stats.ierrors = ifp->ifm_data.ifi_ierrors;
+ entry->stats.idiscards = ifp->ifm_data.ifi_iqdrops;
+ entry->stats.iunknown_protos = ifp->ifm_data.ifi_noproto;
+
+ set_counter(&entry->stats.obytes, ifp->ifm_data.ifi_obytes);
+ set_counter(&entry->stats.oucast, ifp->ifm_data.ifi_opackets);
+ set_counter(&entry->stats.omcast, ifp->ifm_data.ifi_omcasts);
+ entry->stats.oerrors = ifp->ifm_data.ifi_oerrors;
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_BYTES |
+ NETSNMP_INTERFACE_FLAGS_HAS_DROPS |
+ NETSNMP_INTERFACE_FLAGS_HAS_MCAST_PKTS;
+
+#ifdef HAVE_STRUCT_IFNET_IF_LASTCHANGE_TV_NSEC
+ if (timespeccmp(&ifp->ifm_data.ifi_lastchange, &startspec, >)) {
+#else
+ if (timercmp(&ifp->ifm_data.ifi_lastchange, &starttime, >)) {
+#endif
+ entry->lastchange = (ifp->ifm_data.ifi_lastchange.tv_sec -
+ starttime.tv_sec) * 100;
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_LASTCHANGE;
+ } else {
+ entry->lastchange = 0;
+ }
+
+ if (ifp->ifm_flags & ARCH_PROMISC_FLAG)
+ entry->promiscuous = 1;
+
+ /* try to guess the speed from media type */
+ netsnmp_sysctl_get_if_speed(entry->name, &entry->speed,
+ &entry->speed_high);
+ if (entry->speed_high != 0) {
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_HIGH_SPEED;
+ } else {
+ /* or resort to ifi_baudrate */
+ entry->speed = ifp->ifm_data.ifi_baudrate;
+ }
+
+ netsnmp_access_interface_entry_overrides(entry);
+
+ CONTAINER_INSERT(container, entry);
+ DEBUGMSGTL(("access:interface:container:sysctl",
+ "created entry %d for %s\n", (int)entry->index, entry->name));
+ } /* for (each interface entry) */
+
+ /* pass 2: walk addresses */
+ for (cp = if_list; cp < if_list + if_list_size; cp += ifa->ifam_msglen) {
+
+ ifa = (struct ifa_msghdr *) cp;
+
+ if (ifa->ifam_type != RTM_NEWADDR)
+ continue;
+
+ DEBUGMSGTL(("access:interface:container:sysctl",
+ "received 0x%x in RTM_NEWADDR for ifindex %u\n",
+ ifa->ifam_addrs, ifa->ifam_index));
+
+ entry = netsnmp_access_interface_entry_get_by_index(container,
+ ifa->ifam_index);
+ if (entry == NULL) {
+ snmp_log(LOG_ERR, "address for a nonexistent interface? index=%d",
+ ifa->ifam_index);
+ continue;
+ }
+
+ /*
+ * walk the list of addresses received. we do not use actual
+ * addresses, the sole purpose of this is to set flags
+ */
+ a = (struct sockaddr *) (ifa + 1);
+ for (amask = ifa->ifam_addrs; amask != 0; amask >>= 1) {
+ if ((amask & 1) != 0) {
+ DEBUGMSGTL(("access:interface:container:sysctl",
+ "%s: a=%p, sa_len=%d, sa_family=0x%x\n",
+ entry->name, a, a->sa_len, a->sa_family));
+
+ if (a->sa_family == AF_INET)
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_IPV4;
+ else if (a->sa_family == AF_INET6)
+ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_IPV6;
+
+ a = (struct sockaddr *) ( ((char *) a) + ROUNDUP(a->sa_len) );
+ }
+ }
+ DEBUGMSGTL(("access:interface:container:sysctl",
+ "%s: flags=0x%x\n", entry->name, entry->ns_flags));
+ }
+
+ if (if_list != NULL)
+ free(if_list);
+
+ return 0;
+}
+
+#ifndef NETSNMP_FEATURE_REMOVE_INTERFACE_ARCH_SET_ADMIN_STATUS
+int
+netsnmp_arch_set_admin_status(netsnmp_interface_entry * entry,
+ int ifAdminStatus_val)
+{
+ DEBUGMSGTL(("access:interface:arch", "set_admin_status\n"));
+
+ /* TODO: implement this call */
+
+ /* not implemented */
+ snmp_log(LOG_ERR, "netsnmp_arch_set_admin_status not (yet) implemented "
+ "for BSD sysctl.\n");
+
+ return -4;
+}
+#endif /* NETSNMP_FEATURE_REMOVE_INTERFACE_ARCH_SET_ADMIN_STATUS */
diff --git a/agent/mibgroup/if-mib/data_access/interface_sysctl.h b/agent/mibgroup/if-mib/data_access/interface_sysctl.h
new file mode 100644
index 0000000..2a267d4
--- /dev/null
+++ b/agent/mibgroup/if-mib/data_access/interface_sysctl.h
@@ -0,0 +1,31 @@
+/*
+ * Interface MIB architecture support
+ *
+ * Based on patch 1362403, submited by Rojer
+ *
+ * $Id$
+ */
+#ifndef INTERFACE_SYSCTL_H
+#define INTERFACE_SYSCTL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int
+netsnmp_access_interface_sysctl_container_load(netsnmp_container* container,
+ u_int load_flags);
+
+void
+netsnmp_access_interface_sysctl_ifmedia_to_speed(int media, u_int *speed,
+ u_int *speed_high);
+
+int
+netsnmp_access_interface_sysctl_get_if_speed(char *name, u_int *speed,
+ u_int *speed_high);
+
+# ifdef __cplusplus
+}
+#endif
+
+#endif