diff options
Diffstat (limited to 'agent/mibgroup/mibII/at.c')
-rw-r--r-- | agent/mibgroup/mibII/at.c | 1273 |
1 files changed, 1273 insertions, 0 deletions
diff --git a/agent/mibgroup/mibII/at.c b/agent/mibgroup/mibII/at.c new file mode 100644 index 0000000..71c36c1 --- /dev/null +++ b/agent/mibgroup/mibII/at.c @@ -0,0 +1,1273 @@ +/* + * Template MIB group implementation - at.c + * + */ + +/* Portions of this file are subject to the following copyright(s). See + * the Net-SNMP's COPYING file for more details and other copyrights + * that may apply: + */ +/* + * Portions of this file are copyrighted by: + * Copyright © 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms specified in the COPYING file + * distributed with the Net-SNMP package. + */ + +#include <net-snmp/net-snmp-config.h> +#include "mibII_common.h" /* for NETSNMP_KLOOKUP */ + +#if HAVE_STRING_H +#include <string.h> +#else +#include <strings.h> +#endif +#if HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if defined(IFNET_NEEDS_KERNEL) && !defined(_KERNEL) +#define _KERNEL 1 +#define _I_DEFINED_KERNEL +#endif +#include <sys/types.h> +#if TIME_WITH_SYS_TIME +# if defined (WIN32) || defined (cygwin) +# include <sys/timeb.h> +# else +# include <sys/time.h> +# endif +# include <time.h> +#else +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif +#if HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif + +#if HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#if HAVE_NET_IF_H +#include <net/if.h> +#endif +#if HAVE_NET_IF_VAR_H +#include <net/if_var.h> +#endif +#ifdef _I_DEFINED_KERNEL +#undef _KERNEL +#endif + +#if HAVE_NETINET_IF_ETHER_H +#include <netinet/if_ether.h> +#endif +#if HAVE_INET_MIB2_H +#include <inet/mib2.h> +#endif +#if HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif +#if HAVE_SYS_SYSCTL_H +#include <sys/sysctl.h> +#endif +#if HAVE_NET_IF_DL_H +#ifndef dynix +#include <net/if_dl.h> +#else +#include <sys/net/if_dl.h> +#endif +#endif +#if HAVE_SYS_STREAM_H +#include <sys/stream.h> +#endif +#if HAVE_NET_ROUTE_H +#include <net/route.h> +#endif +#ifdef solaris2 +#include "kernel_sunos5.h" +#endif +#if HAVE_WINSOCK_H +#include <winsock.h> +#endif + +#ifdef hpux11 +#include <sys/mib.h> +#include <netinet/mib_kern.h> +#endif /* hpux11 */ + +#include <net-snmp/net-snmp-includes.h> +#include <net-snmp/agent/net-snmp-agent-includes.h> +#include <net-snmp/agent/auto_nlist.h> + +#include "at.h" +#include "interfaces.h" + +#include <net-snmp/data_access/interface.h> + +#if defined(HAVE_SYS_SYSCTL_H) && !defined(NETSNMP_CAN_USE_SYSCTL) +# if defined(RTF_LLINFO) +# define NETSNMP_CAN_USE_SYSCTL 1 +# endif +#endif + +#ifdef cygwin +#include <windows.h> +#endif + + /********************* + * + * Kernel & interface information, + * and internal forward declarations + * + *********************/ + +#if !defined (WIN32) && !defined (cygwin) +#ifndef solaris2 +static void ARP_Scan_Init(void); +#ifdef ARP_SCAN_FOUR_ARGUMENTS +static int ARP_Scan_Next(in_addr_t *, char *, int *, u_long *, u_short *); +#else +static int ARP_Scan_Next(in_addr_t *, char *, int *, u_long *); +#endif +#endif +#endif + + /********************* + * + * Public interface functions + * + *********************/ + +/* + * define the structure we're going to ask the agent to register our + * information at + */ +struct variable1 at_variables[] = { + {ATIFINDEX, ASN_INTEGER, RONLY, var_atEntry, 1, {1}}, + {ATPHYSADDRESS, ASN_OCTET_STR, RONLY, var_atEntry, 1, {2}}, + {ATNETADDRESS, ASN_IPADDRESS, RONLY, var_atEntry, 1, {3}} +}; + +/* + * Define the OID pointer to the top of the mib tree that we're + * registering underneath + */ +oid at_variables_oid[] = { SNMP_OID_MIB2, 3, 1, 1 }; + +void +init_at(void) +{ + /* + * register ourselves with the agent to handle our mib tree + */ + REGISTER_MIB("mibII/at", at_variables, variable1, at_variables_oid); +#ifdef solaris2 + init_kernel_sunos5(); +#endif +} + +#if !defined (WIN32) && !defined (cygwin) +#ifndef solaris2 + +/* + * var_atEntry(... + * Arguments: + * vp IN - pointer to variable entry that points here + * name IN/OUT - IN/name requested, OUT/name found + * length IN/OUT - length of IN/OUT oid's + * exact IN - TRUE if an exact match was requested + * var_len OUT - length of variable or 0 if function returned + * write_method + * + */ + +u_char * +var_atEntry(struct variable *vp, + oid * name, + size_t * length, + int exact, size_t * var_len, WriteMethod ** write_method) +{ + /* + * Address Translation table object identifier is of form: + * 1.3.6.1.2.1.3.1.1.1.interface.1.A.B.C.D, where A.B.C.D is IP address. + * Interface is at offset 10, + * IPADDR starts at offset 12. + * + * IP Net to Media table object identifier is of form: + * 1.3.6.1.2.1.4.22.1.1.1.interface.A.B.C.D, where A.B.C.D is IP address. + * Interface is at offset 10, + * IPADDR starts at offset 11. + */ + u_char *cp; + oid *op; + oid lowest[16]; + oid current[16]; + static char PhysAddr[MAX_MAC_ADDR_LEN], LowPhysAddr[MAX_MAC_ADDR_LEN]; + static int PhysAddrLen, LowPhysAddrLen; + in_addr_t Addr, LowAddr; + int foundone; + static in_addr_t addr_ret; +#ifdef ARP_SCAN_FOUR_ARGUMENTS + u_short ifIndex, lowIfIndex = 0; +#endif /* ARP_SCAN_FOUR_ARGUMENTS */ + u_long ifType, lowIfType = 0; + + int oid_length; + + /* + * fill in object part of name for current (less sizeof instance part) + */ + memcpy((char *) current, (char *) vp->name, + (int) vp->namelen * sizeof(oid)); + + if (current[6] == 3) { /* AT group oid */ + oid_length = 16; + } else { /* IP NetToMedia group oid */ + oid_length = 15; + } + + LowAddr = 0; /* Don't have one yet */ + foundone = 0; + ARP_Scan_Init(); + for (;;) { +#ifdef ARP_SCAN_FOUR_ARGUMENTS + if (ARP_Scan_Next(&Addr, PhysAddr, &PhysAddrLen, &ifType, &ifIndex) == 0) + break; + current[10] = ifIndex; + + if (current[6] == 3) { /* AT group oid */ + current[11] = 1; + op = current + 12; + } else { /* IP NetToMedia group oid */ + op = current + 11; + } +#else /* ARP_SCAN_FOUR_ARGUMENTS */ + if (ARP_Scan_Next(&Addr, PhysAddr, &PhysAddrLen, &ifType) == 0) + break; + current[10] = 1; + + if (current[6] == 3) { /* AT group oid */ + current[11] = 1; + op = current + 12; + } else { /* IP NetToMedia group oid */ + op = current + 11; + } +#endif /* ARP_SCAN_FOUR_ARGUMENTS */ + cp = (u_char *) & Addr; + *op++ = *cp++; + *op++ = *cp++; + *op++ = *cp++; + *op++ = *cp++; + + if (exact) { + if (snmp_oid_compare(current, oid_length, name, *length) == 0) { + memcpy((char *) lowest, (char *) current, + oid_length * sizeof(oid)); + LowAddr = Addr; + foundone = 1; +#ifdef ARP_SCAN_FOUR_ARGUMENTS + lowIfIndex = ifIndex; +#endif /* ARP_SCAN_FOUR_ARGUMENTS */ + memcpy(LowPhysAddr, PhysAddr, sizeof(PhysAddr)); + LowPhysAddrLen = PhysAddrLen; + lowIfType = ifType; + break; /* no need to search further */ + } + } else { + if ((snmp_oid_compare(current, oid_length, name, *length) > 0) + && ((foundone == 0) + || + (snmp_oid_compare + (current, oid_length, lowest, oid_length) < 0))) { + /* + * if new one is greater than input and closer to input than + * previous lowest, save this one as the "next" one. + */ + memcpy((char *) lowest, (char *) current, + oid_length * sizeof(oid)); + LowAddr = Addr; + foundone = 1; +#ifdef ARP_SCAN_FOUR_ARGUMENTS + lowIfIndex = ifIndex; +#endif /* ARP_SCAN_FOUR_ARGUMENTS */ + memcpy(LowPhysAddr, PhysAddr, sizeof(PhysAddr)); + LowPhysAddrLen = PhysAddrLen; + lowIfType = ifType; + } + } + } + if (foundone == 0) + return (NULL); + + memcpy((char *) name, (char *) lowest, oid_length * sizeof(oid)); + *length = oid_length; + *write_method = 0; + switch (vp->magic) { + case IPMEDIAIFINDEX: /* also ATIFINDEX */ + *var_len = sizeof long_return; +#ifdef ARP_SCAN_FOUR_ARGUMENTS + long_return = lowIfIndex; +#else /* ARP_SCAN_FOUR_ARGUMENTS */ +#if NETSNMP_NO_DUMMY_VALUES + return NULL; +#endif + long_return = 1; /* XXX */ +#endif /* ARP_SCAN_FOUR_ARGUMENTS */ + return (u_char *) & long_return; + case IPMEDIAPHYSADDRESS: /* also ATPHYSADDRESS */ + *var_len = LowPhysAddrLen; + return (u_char *) LowPhysAddr; + case IPMEDIANETADDRESS: /* also ATNETADDRESS */ + *var_len = sizeof(addr_ret); + addr_ret = LowAddr; + return (u_char *) & addr_ret; + case IPMEDIATYPE: + *var_len = sizeof long_return; + long_return = lowIfType; + return (u_char *) & long_return; + default: + DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_atEntry\n", + vp->magic)); + } + return NULL; +} +#else /* solaris2 */ + +typedef struct if_ip { + int ifIdx; + IpAddress ipAddr; +} if_ip_t; + +static int +AT_Cmp(void *addr, void *ep) +{ + mib2_ipNetToMediaEntry_t *mp = (mib2_ipNetToMediaEntry_t *) ep; + int ret = -1; + oid index; + +#ifdef NETSNMP_INCLUDE_IFTABLE_REWRITES + mp->ipNetToMediaIfIndex.o_bytes[mp->ipNetToMediaIfIndex.o_length] = '\0'; + index = netsnmp_access_interface_index_find( + mp->ipNetToMediaIfIndex.o_bytes); +#else + index = Interface_Index_By_Name(mp->ipNetToMediaIfIndex.o_bytes, + mp->ipNetToMediaIfIndex.o_length); +#endif + DEBUGMSGTL(("mibII/at", "......... AT_Cmp %lx<>%lx %d<>%d (%.5s)\n", + mp->ipNetToMediaNetAddress, ((if_ip_t *) addr)->ipAddr, + ((if_ip_t *) addr)->ifIdx, index, + mp->ipNetToMediaIfIndex.o_bytes)); + if (mp->ipNetToMediaNetAddress != ((if_ip_t *) addr)->ipAddr) + ret = 1; + else if (((if_ip_t *) addr)->ifIdx != index) + ret = 1; + else + ret = 0; + DEBUGMSGTL(("mibII/at", "......... AT_Cmp returns %d\n", ret)); + return ret; +} + +u_char * +var_atEntry(struct variable * vp, + oid * name, + size_t * length, + int exact, size_t * var_len, WriteMethod ** write_method) +{ + /* + * object identifier is of form: + * 1.3.6.1.2.1.3.1.1.1.interface.1.A.B.C.D, where A.B.C.D is IP address. + * Interface is at offset 10, + * IPADDR starts at offset 12. + */ +#define AT_MAX_NAME_LENGTH 16 +#define AT_IFINDEX_OFF 10 + u_char *cp; + oid *op; + oid lowest[AT_MAX_NAME_LENGTH]; + oid current[AT_MAX_NAME_LENGTH]; + if_ip_t NextAddr; + mib2_ipNetToMediaEntry_t entry; + static mib2_ipNetToMediaEntry_t Lowentry; + int Found = 0; + req_e req_type; + int offset, olength; + static in_addr_t addr_ret; + + /* + * fill in object part of name for current (less sizeof instance part) + */ + + DEBUGMSGTL(("mibII/at", "var_atEntry: ")); + DEBUGMSGOID(("mibII/at", vp->name, vp->namelen)); + DEBUGMSG(("mibII/at", " %d\n", exact)); + + memset(&Lowentry, 0, sizeof(Lowentry)); + memcpy((char *) current, (char *) vp->name, vp->namelen * sizeof(oid)); + lowest[0] = 1024; + for (NextAddr.ipAddr = (u_long) - 1, NextAddr.ifIdx = 255, req_type = + GET_FIRST;; + NextAddr.ipAddr = entry.ipNetToMediaNetAddress, NextAddr.ifIdx = + current[AT_IFINDEX_OFF], req_type = GET_NEXT) { + if (getMibstat + (MIB_IP_NET, &entry, sizeof(mib2_ipNetToMediaEntry_t), + req_type, &AT_Cmp, &NextAddr) != 0) + break; +#ifdef NETSNMP_INCLUDE_IFTABLE_REWRITES + entry.ipNetToMediaIfIndex.o_bytes[entry.ipNetToMediaIfIndex.o_length] = '\0'; + current[AT_IFINDEX_OFF] = netsnmp_access_interface_index_find( + entry.ipNetToMediaIfIndex.o_bytes); +#else + current[AT_IFINDEX_OFF] = + Interface_Index_By_Name(entry.ipNetToMediaIfIndex.o_bytes, + entry.ipNetToMediaIfIndex.o_length); +#endif + if (current[6] == 3) { /* AT group oid */ + current[AT_IFINDEX_OFF + 1] = 1; + offset = AT_IFINDEX_OFF + 2; + olength = AT_IFINDEX_OFF + 6; + } else { + offset = AT_IFINDEX_OFF + 1; + olength = AT_IFINDEX_OFF + 5; + } + COPY_IPADDR(cp, (u_char *) & entry.ipNetToMediaNetAddress, op, + current + offset); + if (exact) { + if (snmp_oid_compare(current, olength, name, *length) == 0) { + memcpy((char *) lowest, (char *) current, + olength * sizeof(oid)); + Lowentry = entry; + Found++; + break; /* no need to search further */ + } + } else { + if (snmp_oid_compare(current, olength, name, *length) > 0 + && snmp_oid_compare(current, olength, lowest, + *length) < 0) { + /* + * if new one is greater than input and closer to input than + * previous lowest, and is not equal to it, save this one as the "next" one. + */ + memcpy((char *) lowest, (char *) current, + olength * sizeof(oid)); + Lowentry = entry; + Found++; + } + } + } + DEBUGMSGTL(("mibII/at", "... Found = %d\n", Found)); + if (Found == 0) + return (NULL); + memcpy((char *) name, (char *) lowest, olength * sizeof(oid)); + *length = olength; + *write_method = 0; + switch (vp->magic) { + case IPMEDIAIFINDEX: + *var_len = sizeof long_return; +#ifdef NETSNMP_INCLUDE_IFTABLE_REWRITES + Lowentry.ipNetToMediaIfIndex.o_bytes[ + Lowentry.ipNetToMediaIfIndex.o_length] = '\0'; + long_return = netsnmp_access_interface_index_find( + Lowentry.ipNetToMediaIfIndex.o_bytes); +#else + long_return = Interface_Index_By_Name( + Lowentry.ipNetToMediaIfIndex.o_bytes, + Lowentry.ipNetToMediaIfIndex.o_length); +#endif + return (u_char *) & long_return; + case IPMEDIAPHYSADDRESS: + *var_len = Lowentry.ipNetToMediaPhysAddress.o_length; + return Lowentry.ipNetToMediaPhysAddress.o_bytes; + case IPMEDIANETADDRESS: + *var_len = sizeof(addr_ret); + addr_ret = Lowentry.ipNetToMediaNetAddress; + return (u_char *) &addr_ret; + case IPMEDIATYPE: + *var_len = sizeof long_return; + long_return = Lowentry.ipNetToMediaType; + return (u_char *) & long_return; + default: + DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_atEntry\n", + vp->magic)); + } + return NULL; +} +#endif /* solaris2 */ + + + /********************* + * + * Internal implementation functions + * + *********************/ + +#ifndef solaris2 + +static int arptab_size, arptab_current; +#if NETSNMP_CAN_USE_SYSCTL +static char *lim, *rtnext; +static char *at = 0; +#else +#ifdef STRUCT_ARPHD_HAS_AT_NEXT +static struct arphd *at = 0; +static struct arptab *at_ptr, at_entry; +static struct arpcom at_com; +#elif defined(hpux11) +static mib_ipNetToMediaEnt *at = (mib_ipNetToMediaEnt *) 0; +#else + +/* + * at used to be allocated every time we needed to look at the arp cache. + * This cause us to parse /proc/net/arp twice for each request and didn't + * allow us to filter things like we'd like to. So now we use it + * semi-statically. We initialize it to size 0 and if we need more room + * we realloc room for ARP_CACHE_INCR more entries in the table. + * We never release what we've taken . . . + */ +#define ARP_CACHE_INCR 1024 +static struct arptab *at = NULL; +static int arptab_curr_max_size = 0; + +#endif +#endif /* NETSNMP_CAN_USE_SYSCTL */ + +static void +ARP_Scan_Init(void) +{ +#ifndef NETSNMP_CAN_USE_SYSCTL +#ifndef linux +#ifdef hpux11 + + int fd; + struct nmparms p; + int val; + unsigned int ulen; + int ret; + + if (at) + free(at); + at = (mib_ipNetToMediaEnt *) 0; + arptab_size = 0; + + if ((fd = open_mib("/dev/ip", O_RDONLY, 0, NM_ASYNC_OFF)) >= 0) { + p.objid = ID_ipNetToMediaTableNum; + p.buffer = (void *) &val; + ulen = sizeof(int); + p.len = &ulen; + if ((ret = get_mib_info(fd, &p)) == 0) + arptab_size = val; + + if (arptab_size > 0) { + ulen = (unsigned) arptab_size *sizeof(mib_ipNetToMediaEnt); + at = (mib_ipNetToMediaEnt *) malloc(ulen); + p.objid = ID_ipNetToMediaTable; + p.buffer = (void *) at; + p.len = &ulen; + if ((ret = get_mib_info(fd, &p)) < 0) + arptab_size = 0; + } + + close_mib(fd); + } + + arptab_current = 0; + +#else /* hpux11 */ + + if (!at) { +#ifdef ARPTAB_SIZE_SYMBOL + auto_nlist(ARPTAB_SIZE_SYMBOL, (char *) &arptab_size, + sizeof arptab_size); +#ifdef STRUCT_ARPHD_HAS_AT_NEXT + at = (struct arphd *) malloc(arptab_size * sizeof(struct arphd)); +#else + at = (struct arptab *) malloc(arptab_size * sizeof(struct arptab)); +#endif +#else + return; +#endif + } +#ifdef STRUCT_ARPHD_HAS_AT_NEXT + auto_nlist(ARPTAB_SYMBOL, (char *) at, + arptab_size * sizeof(struct arphd)); + at_ptr = at[0].at_next; +#else + auto_nlist(ARPTAB_SYMBOL, (char *) at, + arptab_size * sizeof(struct arptab)); +#endif + arptab_current = 0; + +#endif /* hpux11 */ +#else /* linux */ + + static time_t tm = 0; /* Time of last scan */ + FILE *in; + int i, j; + char line[128]; + int za, zb, zc, zd; + char ifname[21]; + char mac[3*MAX_MAC_ADDR_LEN+1]; + char *tok; + + arptab_current = 0; /* Anytime this is called we need to reset 'current' */ + + if (time(NULL) < tm + 1) { /*Our cool one second cache implementation :-) */ + return; + } + + in = fopen("/proc/net/arp", "r"); + if (!in) { + snmp_log(LOG_ERR, "snmpd: Cannot open /proc/net/arp\n"); + arptab_size = 0; + return; + } + + /* + * Get rid of the header line + */ + fgets(line, sizeof(line), in); + + i = 0; + while (fgets(line, sizeof(line), in)) { + u_long tmp_a; + int tmp_flags; + if (i >= arptab_curr_max_size) { + struct arptab *newtab = (struct arptab *) + realloc(at, (sizeof(struct arptab) * + (arptab_curr_max_size + ARP_CACHE_INCR))); + if (newtab == at) { + snmp_log(LOG_ERR, + "Error allocating more space for arpcache. " + "Cache will continue to be limited to %d entries", + arptab_curr_max_size); + break; + } else { + arptab_curr_max_size += ARP_CACHE_INCR; + at = newtab; + } + } + if (7 != + sscanf(line, + "%d.%d.%d.%d 0x%*x 0x%x %s %*[^ ] %20s\n", + &za, &zb, &zc, &zd, &tmp_flags, mac, ifname)) { + snmp_log(LOG_ERR, "Bad line in /proc/net/arp: %s", line); + continue; + } + /* + * Invalidated entries have their flag set to 0. + * * We want to ignore them + */ + if (tmp_flags == 0) { + continue; + } + ifname[sizeof(ifname)-1] = 0; /* make sure name is null terminated */ + at[i].at_flags = tmp_flags; + tmp_a = ((u_long) za << 24) | + ((u_long) zb << 16) | ((u_long) zc << 8) | ((u_long) zd); + at[i].at_iaddr.s_addr = htonl(tmp_a); + at[i].if_index = netsnmp_access_interface_index_find(ifname); + + for (j=0,tok=strtok(mac, ":"); tok != NULL; tok=strtok(NULL, ":"),j++) { + at[i].at_enaddr[j] = strtol(tok, NULL, 16); + } + at[i].at_enaddr_len = j; + i++; + } + arptab_size = i; + + fclose(in); + time(&tm); +#endif /* linux */ +#else /* NETSNMP_CAN_USE_SYSCTL */ + + int mib[6]; + size_t needed; + + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = AF_INET; + mib[4] = NET_RT_FLAGS; + mib[5] = RTF_LLINFO; + + if (at) + free(at); + rtnext = lim = at = 0; + + if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) + snmp_log_perror("route-sysctl-estimate"); + else { + if ((at = malloc(needed ? needed : 1)) == NULL) + snmp_log_perror("malloc"); + else { + if (sysctl(mib, 6, at, &needed, NULL, 0) < 0) + snmp_log_perror("actual retrieval of routing table"); + else { + lim = at + needed; + rtnext = at; + } + } + } + +#endif /* NETSNMP_CAN_USE_SYSCTL */ +} + +#ifdef ARP_SCAN_FOUR_ARGUMENTS +static int +ARP_Scan_Next(in_addr_t * IPAddr, char *PhysAddr, int *PhysAddrLen, + u_long * ifType, u_short * ifIndex) +#else +static int +ARP_Scan_Next(in_addr_t * IPAddr, char *PhysAddr, int *PhysAddrLen, + u_long * ifType) +#endif +{ +#ifndef NETSNMP_CAN_USE_SYSCTL +#ifdef linux + if (arptab_current < arptab_size) { + /* + * copy values + */ + *IPAddr = at[arptab_current].at_iaddr.s_addr; + *ifType = + (at[arptab_current]. + at_flags & ATF_PERM) ? 4 /*static */ : 3 /*dynamic */ ; + *ifIndex = at[arptab_current].if_index; + memcpy(PhysAddr, &at[arptab_current].at_enaddr, + sizeof(at[arptab_current].at_enaddr)); + *PhysAddrLen = at[arptab_current].at_enaddr_len; + + /* + * increment to point next entry + */ + arptab_current++; + /* + * return success + */ + return (1); + } +#elif defined(hpux11) + if (arptab_current < arptab_size) { + /* + * copy values + */ + *IPAddr = at[arptab_current].NetAddr; + memcpy(PhysAddr, at[arptab_current].PhysAddr.o_bytes, + at[arptab_current].PhysAddr.o_length); + *ifType = at[arptab_current].Type; + *ifIndex = at[arptab_current].IfIndex; + *PhysAddrLen = at[arptab_current].PhysAddr.o_length; + /* + * increment to point next entry + */ + arptab_current++; + /* + * return success + */ + return (1); + } +#elif !defined(ARP_SCAN_FOUR_ARGUMENTS) || defined(hpux) + register struct arptab *atab; + + while (arptab_current < arptab_size) { +#ifdef STRUCT_ARPHD_HAS_AT_NEXT + /* + * The arp table is an array of linked lists of arptab entries. + * Unused slots have pointers back to the array entry itself + */ + + if (at_ptr == (auto_nlist_value(ARPTAB_SYMBOL) + + arptab_current * sizeof(struct arphd))) { + /* + * Usused + */ + arptab_current++; + at_ptr = at[arptab_current].at_next; + continue; + } + + if (!NETSNMP_KLOOKUP(at_ptr, (char *) &at_entry, sizeof(struct arptab))) { + DEBUGMSGTL(("mibII/at:ARP_Scan_Next", "klookup failed\n")); + break; + } + + if (!NETSNMP_KLOOKUP(at_entry.at_ac, (char *) &at_com, sizeof(struct arpcom))) { + DEBUGMSGTL(("mibII/at:ARP_Scan_Next", "klookup failed\n")); + break; + } + + at_ptr = at_entry.at_next; + atab = &at_entry; + *ifIndex = at_com.ac_if.if_index; /* not strictly ARPHD */ +#else /* STRUCT_ARPHD_HAS_AT_NEXT */ + atab = &at[arptab_current++]; +#endif /* STRUCT_ARPHD_HAS_AT_NEXT */ + if (!(atab->at_flags & ATF_COM)) + continue; + *ifType = (atab->at_flags & ATF_PERM) ? 4 : 3; + *IPAddr = atab->at_iaddr.s_addr; +#if defined (sunV3) || defined(sparc) || defined(hpux) + memcpy(PhysAddr, (char *) &atab->at_enaddr, + sizeof(atab->at_enaddr)); + *PhysAddrLen = sizeof(atab->at_enaddr); +#endif +#if defined(mips) || defined(ibm032) + memcpy(PhysAddr, (char *) atab->at_enaddr, + sizeof(atab->at_enaddr)); + *PhysAddrLen = sizeof(atab->at_enaddr); +#endif + return (1); + } +#endif /* linux || hpux11 || !ARP_SCAN_FOUR_ARGUMENTS || hpux */ + + return 0; /* we need someone with an irix box to fix this section */ + +#else /* !NETSNMP_CAN_USE_SYSCTL */ + struct rt_msghdr *rtm; + struct sockaddr_inarp *sin; + struct sockaddr_dl *sdl; + + while (rtnext < lim) { + rtm = (struct rt_msghdr *) rtnext; + sin = (struct sockaddr_inarp *) (rtm + 1); + sdl = (struct sockaddr_dl *) (sin + 1); + rtnext += rtm->rtm_msglen; + if (sdl->sdl_alen) { +#ifdef irix6 + *IPAddr = sin->sarp_addr.s_addr; +#else + *IPAddr = sin->sin_addr.s_addr; +#endif + memcpy(PhysAddr, (char *) LLADDR(sdl), sdl->sdl_alen); + *PhysAddrLen = sdl->sdl_alen; + *ifIndex = sdl->sdl_index; + *ifType = 1; /* XXX */ + return (1); + } + } + return (0); /* "EOF" */ +#endif /* !NETSNMP_CAN_USE_SYSCTL */ +} +#endif /* solaris2 */ + +#else /* WIN32 cygwin */ +#include <iphlpapi.h> + +extern WriteMethod write_arp; +MIB_IPNETROW *arp_row = NULL; +int create_flag = 0; + +u_char * +var_atEntry(struct variable *vp, + oid * name, + size_t * length, + int exact, size_t * var_len, WriteMethod ** write_method) +{ + /* + * Address Translation table object identifier is of form: + * 1.3.6.1.2.1.3.1.?.interface.1.A.B.C.D, where A.B.C.D is IP address. + * Interface is at offset 10, + * IPADDR starts at offset 12. + * + * IP Net to Media table object identifier is of form: + * 1.3.6.1.2.1.4.22.1.?.interface.A.B.C.D, where A.B.C.D is IP address. + * Interface is at offset 10, + * IPADDR starts at offset 11. + */ + u_char *cp; + oid *op; + oid lowest[16]; + oid current[16]; + int oid_length; + int lowState = -1; /* Don't have one yet */ + PMIB_IPNETTABLE pIpNetTable = NULL; + DWORD status = NO_ERROR; + DWORD dwActualSize = 0; + UINT i; + u_char dest_addr[4]; + static in_addr_t addr_ret; + + /* + * fill in object part of name for current (less sizeof instance part) + */ + memcpy((char *) current, (char *) vp->name, + (int) vp->namelen * sizeof(oid)); + + if (current[6] == 3) { /* AT group oid */ + oid_length = 16; + } else { /* IP NetToMedia group oid */ + oid_length = 15; + } + + status = GetIpNetTable(pIpNetTable, &dwActualSize, TRUE); + if (status == ERROR_INSUFFICIENT_BUFFER) { + pIpNetTable = (PMIB_IPNETTABLE) malloc(dwActualSize); + if (pIpNetTable != NULL) { + /* + * Get the sorted IpNet Table + */ + status = GetIpNetTable(pIpNetTable, &dwActualSize, TRUE); + } + } + + + if (status == NO_ERROR) { + for (i = 0; i < pIpNetTable->dwNumEntries; ++i) { + current[10] = pIpNetTable->table[i].dwIndex; + + + if (current[6] == 3) { /* AT group oid */ + current[11] = 1; + op = current + 12; + } else { /* IP NetToMedia group oid */ + op = current + 11; + } + cp = (u_char *) & pIpNetTable->table[i].dwAddr; + *op++ = *cp++; + *op++ = *cp++; + *op++ = *cp++; + *op++ = *cp++; + + if (exact) { + if (snmp_oid_compare(current, oid_length, name, *length) == + 0) { + memcpy((char *) lowest, (char *) current, + oid_length * sizeof(oid)); + lowState = 0; + break; /* no need to search further */ + } + } else { + if (snmp_oid_compare(current, oid_length, name, *length) > + 0) { + memcpy((char *) lowest, (char *) current, + oid_length * sizeof(oid)); + lowState = 0; + break; /* As the table is sorted, no need to search further */ + } + } + } + } + if (arp_row == NULL) { + /* + * Free allocated memory in case of SET request's FREE phase + */ + arp_row = (PMIB_IPNETROW) malloc(sizeof(MIB_IPNETROW)); + } + + if (lowState < 0 || status != NO_ERROR) { + /* + * for creation of new row, only ipNetToMediaTable case is considered + */ + if (*length == 15 || *length == 16) { + create_flag = 1; + *write_method = write_arp; + arp_row->dwIndex = name[10]; + + if (*length == 15) { /* ipNetToMediaTable */ + i = 11; + } else { /* at Table */ + + i = 12; + } + + dest_addr[0] = (u_char) name[i]; + dest_addr[1] = (u_char) name[i + 1]; + dest_addr[2] = (u_char) name[i + 2]; + dest_addr[3] = (u_char) name[i + 3]; + arp_row->dwAddr = *((DWORD *) dest_addr); + + arp_row->dwType = 4; /* Static */ + arp_row->dwPhysAddrLen = 0; + } + free(pIpNetTable); + return (NULL); + } + + create_flag = 0; + memcpy((char *) name, (char *) lowest, oid_length * sizeof(oid)); + *length = oid_length; + *write_method = write_arp; + *arp_row = pIpNetTable->table[i]; + + switch (vp->magic) { + case IPMEDIAIFINDEX: /* also ATIFINDEX */ + *var_len = sizeof long_return; + long_return = pIpNetTable->table[i].dwIndex; + free(pIpNetTable); + return (u_char *) & long_return; + case IPMEDIAPHYSADDRESS: /* also ATPHYSADDRESS */ + *var_len = pIpNetTable->table[i].dwPhysAddrLen; + memcpy(return_buf, pIpNetTable->table[i].bPhysAddr, *var_len); + free(pIpNetTable); + return (u_char *) return_buf; + case IPMEDIANETADDRESS: /* also ATNETADDRESS */ + *var_len = sizeof(addr_ret); + addr_ret = pIpNetTable->table[i].dwAddr; + free(pIpNetTable); + return (u_char *) & addr_ret; + case IPMEDIATYPE: + *var_len = sizeof long_return; + long_return = pIpNetTable->table[i].dwType; + free(pIpNetTable); + return (u_char *) & long_return; + default: + DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_atEntry\n", + vp->magic)); + } + return NULL; +} + +int +write_arp(int action, + u_char * var_val, + u_char var_val_type, + size_t var_val_len, u_char * statP, oid * name, size_t length) +{ + int var, retval = SNMP_ERR_NOERROR; + static PMIB_IPNETROW oldarp_row = NULL; + MIB_IPNETROW temp_row; + DWORD status = NO_ERROR; + + /* + * IP Net to Media table object identifier is of form: + * 1.3.6.1.2.1.4.22.1.?.interface.A.B.C.D, where A.B.C.D is IP address. + * Interface is at offset 10, + * IPADDR starts at offset 11. + */ + + if (name[6] == 3) { /* AT group oid */ + if (length != 16) { + snmp_log(LOG_ERR, "length error\n"); + return SNMP_ERR_NOCREATION; + } + } else { /* IP NetToMedia group oid */ + if (length != 15) { + snmp_log(LOG_ERR, "length error\n"); + return SNMP_ERR_NOCREATION; + } + } + + + /* + * #define for ipNetToMediaTable entries are 1 less than corresponding sub-id in MIB + * * i.e. IPMEDIAIFINDEX defined as 0, but ipNetToMediaIfIndex registered as 1 + */ + var = name[9] - 1; + switch (action) { + case RESERVE1: + switch (var) { + case IPMEDIAIFINDEX: + if (var_val_type != ASN_INTEGER) { + snmp_log(LOG_ERR, "not integer\n"); + return SNMP_ERR_WRONGTYPE; + } + if ((*((int *) var_val)) < 0) { + snmp_log(LOG_ERR, "invalid media ifIndex"); + return SNMP_ERR_WRONGVALUE; + } + if (var_val_len > sizeof(int)) { + snmp_log(LOG_ERR, "bad length\n"); + return SNMP_ERR_WRONGLENGTH; + } + break; + case IPMEDIANETADDRESS: + if (var_val_type != ASN_IPADDRESS) { + snmp_log(LOG_ERR, "not IP Address\n"); + return SNMP_ERR_WRONGTYPE; + } + if ((*((int *) var_val)) < 0) { + snmp_log(LOG_ERR, "invalid media net address"); + return SNMP_ERR_WRONGVALUE; + } + if (var_val_len > sizeof(DWORD)) { + snmp_log(LOG_ERR, "bad length\n"); + return SNMP_ERR_WRONGLENGTH; + } + break; + case IPMEDIATYPE: + if (var_val_type != ASN_INTEGER) { + snmp_log(LOG_ERR, "not integer\n"); + return SNMP_ERR_WRONGTYPE; + } + if ((*((int *) var_val)) < 1 || (*((int *) var_val)) > 4) { + snmp_log(LOG_ERR, "invalid media type"); + return SNMP_ERR_WRONGVALUE; + } + if (var_val_len > sizeof(int)) { + snmp_log(LOG_ERR, "bad length\n"); + return SNMP_ERR_WRONGLENGTH; + } + break; + case IPMEDIAPHYSADDRESS: + if (var_val_type != ASN_OCTET_STR) { + snmp_log(LOG_ERR, "not octet str"); + return SNMP_ERR_WRONGTYPE; + } + if (var_val_len != 6) { + snmp_log(LOG_ERR, "not correct ipAddress length: %d", + var_val_len); + return SNMP_ERR_WRONGLENGTH; + } + break; + default: + DEBUGMSGTL(("snmpd", "unknown sub-id %d in write_rte\n", + var + 1)); + return SNMP_ERR_NOTWRITABLE; + } + break; + case RESERVE2: + /* + * Save the old value, in case of UNDO + */ + if (oldarp_row == NULL) { + oldarp_row = (PMIB_IPNETROW) malloc(sizeof(MIB_IPNETROW)); + *oldarp_row = *arp_row; + } + break; + case ACTION: /* Perform the SET action (if reversible) */ + switch (var) { + + case IPMEDIAIFINDEX: + temp_row = *arp_row; + arp_row->dwIndex = *((int *) var_val); + /* + * In case of new entry, physical address is mandatory. + * * SetIpNetEntry will be done in COMMIT case + */ + if (!create_flag) { + if (SetIpNetEntry(arp_row) != NO_ERROR) { + arp_row->dwIndex = temp_row.dwIndex; + retval = SNMP_ERR_COMMITFAILED; + } + /* + * Don't know yet, whether change in ifIndex creates new row or not + */ + /* + * else{ + */ + /* + * temp_row.dwType = 2; + */ + /* + * if(SetIpNetEntry(&temp_row) != NO_ERROR) + */ + /* + * retval = SNMP_ERR_COMMITFAILED; + */ + /* + * } + */ + } + break; + case IPMEDIANETADDRESS: + temp_row = *arp_row; + arp_row->dwAddr = *((int *) var_val); + if (!create_flag) { + if (SetIpNetEntry(arp_row) != NO_ERROR) { + arp_row->dwAddr = oldarp_row->dwAddr; + retval = SNMP_ERR_COMMITFAILED; + } else { + temp_row.dwType = 2; + if (SetIpNetEntry(&temp_row) != NO_ERROR) { + snmp_log(LOG_ERR, + "Failed in ACTION, while deleting old row \n"); + retval = SNMP_ERR_COMMITFAILED; + } + } + } + break; + case IPMEDIATYPE: + arp_row->dwType = *((int *) var_val); + if (!create_flag) { + if (SetIpNetEntry(arp_row) != NO_ERROR) + retval = SNMP_ERR_COMMITFAILED; + } + break; + case IPMEDIAPHYSADDRESS: + memcpy(arp_row->bPhysAddr, var_val, var_val_len); + arp_row->dwPhysAddrLen = var_val_len; + if (!create_flag) { + if (SetIpNetEntry(arp_row) != NO_ERROR) + retval = SNMP_ERR_COMMITFAILED; + } + break; + default: + DEBUGMSGTL(("snmpd", "unknown sub-id %d in write_arp\n", + var + 1)); + retval = SNMP_ERR_NOTWRITABLE; + } + return retval; + case UNDO: + /* + * Reverse the SET action and free resources + */ + if (oldarp_row != NULL) { + /* + * UNDO the changes done for existing entry. + */ + if (!create_flag) { + if ((status = SetIpNetEntry(oldarp_row)) != NO_ERROR) { + snmp_log(LOG_ERR, "Error in case UNDO, status : %d\n", + status); + retval = SNMP_ERR_UNDOFAILED; + } + } + + if (oldarp_row->dwAddr != arp_row->dwAddr) { + arp_row->dwType = 2; /*If row was added/created delete that row */ + + if ((status = SetIpNetEntry(arp_row)) != NO_ERROR) { + snmp_log(LOG_ERR, + "Error while deleting added row, status : %d\n", + status); + retval = SNMP_ERR_UNDOFAILED; + } + } + free(oldarp_row); + oldarp_row = NULL; + free(arp_row); + arp_row = NULL; + return retval; + } + break; + case COMMIT: + /* + * if new entry and physical address specified, create new entry + */ + if (create_flag) { + if (arp_row->dwPhysAddrLen != 0) { + if ((status = CreateIpNetEntry(arp_row)) != NO_ERROR) { + snmp_log(LOG_ERR, + "Inside COMMIT: CreateIpNetEntry failed, status %d\n", + status); + retval = SNMP_ERR_COMMITFAILED; + } + } else { + /* + * For new entry, physical address must be set. + */ + snmp_log(LOG_ERR, + "Can't create new entry without physical address\n"); + retval = SNMP_ERR_WRONGVALUE; + } + /* + * unset the create_flag, so that CreateIpNetEntry called only once + */ + create_flag = 0; + } + + case FREE: + /* + * Free any resources allocated + */ + free(oldarp_row); + oldarp_row = NULL; + free(arp_row); + arp_row = NULL; + break; + } + return retval; +} +#endif /* WIN32 cygwin */ |