/* * Interfaces MIB group implementation - interfaces.c * */ /* Portions of this file are subject to the following copyright(s). See * the Net-SNMP's COPYING file for more details and other copyrights * that may apply: */ /* * Portions of this file are copyrighted by: * Copyright © 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms specified in the COPYING file * distributed with the Net-SNMP package. * * Portions of this file are copyrighted by: * Copyright (c) 2016 VMware, Inc. All rights reserved. * Use is subject to license terms specified in the COPYING file * distributed with the Net-SNMP package. */ #include #include netsnmp_feature_provide(interface_legacy); #if defined(NETSNMP_IFNET_NEEDS_KERNEL) && !defined(_KERNEL) && !defined(NETSNMP_IFNET_NEEDS_KERNEL_LATE) #define _KERNEL 1 #define _I_DEFINED_KERNEL #endif #if HAVE_STRING_H #include #else #include #endif #if HAVE_STDLIB_H #include #endif #if HAVE_UNISTD_H #include #endif #if HAVE_SYS_PARAM_H #include #endif #include #if defined(NETSNMP_IFNET_NEEDS_KERNEL) && !defined(_KERNEL) && defined(NETSNMP_IFNET_NEEDS_KERNEL_LATE) #define _KERNEL 1 #define _I_DEFINED_KERNEL #endif #if HAVE_SYS_SOCKET_H #include #endif #ifndef STREAM_NEEDS_KERNEL_ISLANDS #if HAVE_SYS_STREAM_H #include #endif #endif #if HAVE_SYS_SOCKETVAR_H #include #endif #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #if HAVE_SYS_SOCKIO_H #include #endif #if HAVE_FCNTL_H #include #endif #if HAVE_SYS_IOCTL_H #include #endif #if HAVE_NETINET_IN_H #include #endif #if HAVE_NET_IF_H #include #endif #if HAVE_NETINET_IN_VAR_H #include #endif #if HAVE_NET_IF_VAR_H #include #endif #ifdef _I_DEFINED_KERNEL #undef _KERNEL #endif #ifdef STREAM_NEEDS_KERNEL_ISLANDS #if HAVE_SYS_STREAM_H #include #endif #endif #if HAVE_NET_ROUTE_H #include #endif #if HAVE_NETINET_IN_SYSTM_H #include #endif #if HAVE_SYS_HASHING_H #include #endif #if HAVE_NETINET_IN_VAR_H #include #endif #if HAVE_NETINET_IP_H #include #endif #ifdef NETSNMP_ENABLE_IPV6 #if HAVE_NETINET_IP6_H #include #endif #endif #if HAVE_SYS_QUEUE_H #include #endif #if HAVE_NETINET_IP_VAR_H #include #endif #ifdef NETSNMP_ENABLE_IPV6 #if HAVE_NETNETSNMP_ENABLE_IPV6_IP6_VAR_H #include #endif #endif #if HAVE_NETINET_IN_PCB_H #include #endif #if HAVE_NETINET_IF_ETHER_H #include #endif #if HAVE_NET_IF_TYPES_H #include #endif #if HAVE_NET_IF_DL_H #ifndef dynix #include #else #include #endif #endif #if HAVE_INET_MIB2_H #include #endif #if HAVE_IOCTLS_H #include #endif #ifdef solaris2 # include #include "kernel_sunos5.h" #else #include "kernel.h" #endif #ifdef hpux #include #include #endif /* hpux */ #if defined(cygwin) || defined(mingw32) #include #endif #if HAVE_SYS_SYSCTL_H #include #if defined(freebsd3) || defined(freebsd4) || defined(freebsd5) # define USE_SYSCTL_IFLIST #else # if defined(CTL_NET) && !defined(freebsd2) && !defined(netbsd1) # ifdef PF_ROUTE # ifdef NET_RT_IFLIST # ifndef netbsd1 # define USE_SYSCTL_IFLIST # endif # endif # endif # endif #endif /* defined(freebsd3) */ #endif /* HAVE_SYS_SYSCTL_H */ #if HAVE_OSRELDATE_H #include #endif #ifdef NETSNMP_CAN_USE_SYSCTL #include #endif #include #include #include #include #include #include "interfaces.h" #include "struct.h" #include "util_funcs.h" #include "util_funcs/header_generic.h" /* if you want caching enabled for speed retrieval purposes, set this to 5?*/ #define MINLOADFREQ 0 /* min reload frequency in seconds */ #ifdef linux static unsigned long LastLoad = 0; /* ET in secs at last table load */ #endif #define starttime (*(const struct timeval*)netsnmp_get_agent_starttime()) struct variable3 interfaces_variables[] = { {NETSNMP_IFNUMBER, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_interfaces, 1, {1}}, {NETSNMP_IFINDEX, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_ifEntry, 3, {2, 1, 1}}, {NETSNMP_IFDESCR, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, var_ifEntry, 3, {2, 1, 2}}, {NETSNMP_IFTYPE, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_ifEntry, 3, {2, 1, 3}}, {NETSNMP_IFMTU, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_ifEntry, 3, {2, 1, 4}}, {NETSNMP_IFSPEED, ASN_GAUGE, NETSNMP_OLDAPI_RONLY, var_ifEntry, 3, {2, 1, 5}}, {NETSNMP_IFPHYSADDRESS, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, var_ifEntry, 3, {2, 1, 6}}, #ifndef NETSNMP_NO_WRITE_SUPPORT #if defined (WIN32) || defined (cygwin) {NETSNMP_IFADMINSTATUS, ASN_INTEGER, NETSNMP_OLDAPI_RWRITE, var_ifEntry, 3, {2, 1, 7}}, #else {NETSNMP_IFADMINSTATUS, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_ifEntry, 3, {2, 1, 7}}, #endif #else /* !NETSNMP_NO_WRITE_SUPPORT */ {NETSNMP_IFADMINSTATUS, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_ifEntry, 3, {2, 1, 7}}, #endif /* !NETSNMP_NO_WRITE_SUPPORT */ {NETSNMP_IFOPERSTATUS, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_ifEntry, 3, {2, 1, 8}}, {NETSNMP_IFLASTCHANGE, ASN_TIMETICKS, NETSNMP_OLDAPI_RONLY, var_ifEntry, 3, {2, 1, 9}}, {NETSNMP_IFINOCTETS, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, var_ifEntry, 3, {2, 1, 10}}, {NETSNMP_IFINUCASTPKTS, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, var_ifEntry, 3, {2, 1, 11}}, {NETSNMP_IFINNUCASTPKTS, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, var_ifEntry, 3, {2, 1, 12}}, {NETSNMP_IFINDISCARDS, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, var_ifEntry, 3, {2, 1, 13}}, {NETSNMP_IFINERRORS, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, var_ifEntry, 3, {2, 1, 14}}, {NETSNMP_IFINUNKNOWNPROTOS, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, var_ifEntry, 3, {2, 1, 15}}, {NETSNMP_IFOUTOCTETS, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, var_ifEntry, 3, {2, 1, 16}}, {NETSNMP_IFOUTUCASTPKTS, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, var_ifEntry, 3, {2, 1, 17}}, {NETSNMP_IFOUTNUCASTPKTS, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, var_ifEntry, 3, {2, 1, 18}}, {NETSNMP_IFOUTDISCARDS, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, var_ifEntry, 3, {2, 1, 19}}, {NETSNMP_IFOUTERRORS, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, var_ifEntry, 3, {2, 1, 20}}, {NETSNMP_IFOUTQLEN, ASN_GAUGE, NETSNMP_OLDAPI_RONLY, var_ifEntry, 3, {2, 1, 21}}, {NETSNMP_IFSPECIFIC, ASN_OBJECT_ID, NETSNMP_OLDAPI_RONLY, var_ifEntry, 3, {2, 1, 22}} }; /* * Define the OID pointer to the top of the mib tree that we're * registering underneath, and the OID of the MIB module */ oid interfaces_variables_oid[] = { SNMP_OID_MIB2, 2 }; oid interfaces_module_oid[] = { SNMP_OID_MIB2, 31 }; void init_interfaces(void) { /* * register ourselves with the agent to handle our mib tree */ REGISTER_MIB("mibII/interfaces", interfaces_variables, variable3, interfaces_variables_oid); REGISTER_SYSOR_ENTRY(interfaces_module_oid, "The MIB module to describe generic objects for network interface sub-layers"); #ifndef USE_SYSCTL_IFLIST #if HAVE_NET_IF_MIB_H init_interfaces_setup(); #endif #endif #ifdef solaris2 init_kernel_sunos5(); #endif } #ifdef linux /* * if_type_from_name * Return interface type using the interface name as a clue. * Returns 1 to imply "other" type if name not recognized. */ static int if_type_from_name(const char *pcch) { typedef struct _match_if { int mi_type; const char *mi_name; } *pmatch_if, match_if; static match_if lmatch_if[] = { {24, "lo"}, {6, "eth"}, {9, "tr"}, {23, "ppp"}, {28, "sl"}, {0, 0} /* end of list */ }; int len; register pmatch_if pm; for (pm = lmatch_if; pm->mi_name; pm++) { len = strlen(pm->mi_name); if (0 == strncmp(pcch, pm->mi_name, len)) { return (pm->mi_type); } } return (1); /* in case search fails */ } #endif #ifdef linux static struct ifnet *ifnetaddr_list; #endif /* * header_ifEntry(... * Arguments: * vp IN - pointer to variable entry that points here * name IN/OUT - IN/name requested, OUT/name found * length IN/OUT - length of IN/OUT oid's * exact IN - TRUE if an exact match was requested * var_len OUT - length of variable or 0 if function returned * write_method * */ #if !defined (WIN32) && !defined (cygwin) static int header_ifEntry(struct variable *vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { #define IFENTRY_NAME_LENGTH 10 oid newname[MAX_OID_LEN]; register int interface; int result, count; DEBUGMSGTL(("mibII/interfaces", "var_ifEntry: ")); DEBUGMSGOID(("mibII/interfaces", name, *length)); DEBUGMSG(("mibII/interfaces", " %d\n", exact)); memcpy((char *) newname, (char *) vp->name, (int) vp->namelen * sizeof(oid)); /* * find "next" interface */ count = Interface_Scan_Get_Count(); for (interface = 1; interface <= count; interface++) { newname[IFENTRY_NAME_LENGTH] = (oid) interface; result = snmp_oid_compare(name, *length, newname, (int) vp->namelen + 1); if ((exact && (result == 0)) || (!exact && (result < 0))) break; } if (interface > count) { DEBUGMSGTL(("mibII/interfaces", "... index out of range\n")); return MATCH_FAILED; } memcpy((char *) name, (char *) newname, ((int) vp->namelen + 1) * sizeof(oid)); *length = vp->namelen + 1; *write_method = 0; *var_len = sizeof(long); /* default to 'long' results */ DEBUGMSGTL(("mibII/interfaces", "... get I/F stats ")); DEBUGMSGOID(("mibII/interfaces", name, *length)); DEBUGMSG(("mibII/interfaces", "\n")); return interface; } u_char * var_interfaces(struct variable * vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { if (header_generic(vp, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; switch (vp->magic) { case NETSNMP_IFNUMBER: long_return = Interface_Scan_Get_Count(); return (u_char *) & long_return; default: DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_interfaces\n", vp->magic)); } return NULL; } #ifdef USE_SYSCTL_IFLIST static u_char *if_list = 0; static const u_char *if_list_end; static size_t if_list_size = 0; struct small_ifaddr { struct in_addr sifa_addr; struct in_addr sifa_netmask; struct in_addr sifa_broadcast; }; static int Interface_Scan_By_Index(int, struct if_msghdr *, char *, struct small_ifaddr *); static int Interface_Get_Ether_By_Index(int, u_char *); static int Interface_Scan_By_Index(int iindex, struct if_msghdr *if_msg, char *if_name, struct small_ifaddr *sifa) { u_char *cp; struct if_msghdr *ifp; int have_ifinfo = 0, have_addr = 0; if (NULL != sifa) memset(sifa, 0, sizeof(*sifa)); for (cp = if_list; cp < if_list_end; cp += ifp->ifm_msglen) { ifp = (struct if_msghdr *) cp; DEBUGMSGTL(("mibII/interfaces", "ifm_type = %d, ifm_index = %d\n", ifp->ifm_type, ifp->ifm_index)); switch (ifp->ifm_type) { case RTM_IFINFO: { const struct sockaddr *a; if (ifp->ifm_index == iindex) { a = get_address(ifp + 1, ifp->ifm_addrs, RTA_IFP); if (a == NULL) return 0; sprintf(if_name, "%.*s", ((const u_char *) a)[5], ((const struct sockaddr_in *) a)->sin_zero); *if_msg = *ifp; ++have_ifinfo; } } break; case RTM_NEWADDR: { struct ifa_msghdr *ifap = (struct ifa_msghdr *) cp; if ((NULL != sifa) && (ifap->ifam_index == iindex)) { const struct in_addr *ia; /* * I don't know why the normal get_address() doesn't * work on IRIX 6.2. Maybe this has to do with the * existence of struct sockaddr_new. Hopefully, on * other systems we can simply use get_in_address * three times, with (ifap+1) as the starting * address. */ sifa->sifa_netmask = *((struct in_addr *) ((char *) (ifap + 1) + 4)); ia = get_in_address((char *) (ifap + 1) + 8, ifap->ifam_addrs &= ~RTA_NETMASK, RTA_IFA); if (ia == NULL) return 0; sifa->sifa_addr = *ia; ia = get_in_address((char *) (ifap + 1) + 8, ifap->ifam_addrs &= ~RTA_NETMASK, RTA_BRD); if (ia == NULL) return 0; sifa->sifa_broadcast = *ia; ++have_addr; } } break; default: DEBUGMSGTL(("mibII/interfaces", "routing socket: unknown message type %d\n", ifp->ifm_type)); } } if (have_ifinfo && (NULL == sifa) || (have_addr)) { return 0; } else if (have_ifinfo && !(if_msg->ifm_flags & IFF_UP)) return 0; else { return -1; } } int Interface_Scan_Get_Count(void) { u_char *cp; struct if_msghdr *ifp; long n = 0; Interface_Scan_Init(); if (if_list_size) { for (cp = if_list, n = 0; cp < if_list_end; cp += ifp->ifm_msglen) { ifp = (struct if_msghdr *) cp; if (ifp->ifm_type == RTM_IFINFO) { ++n; } } } return n; } void Interface_Scan_Init(void) { int name[] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; size_t size; if (sysctl(name, sizeof(name) / sizeof(int), 0, &size, 0, 0) == -1) { snmp_log(LOG_ERR, "sysctl size fail\n"); } else { if (if_list == 0 || if_list_size < size) { if (if_list != 0) { free(if_list); } if_list = NULL; if_list_size = 0; if_list_end = 0; if ((if_list = malloc(size)) == NULL) { snmp_log(LOG_ERR, "out of memory allocating route table (size = %d)\n", size); return; } if_list_size = size; } else { size = if_list_size; } if (sysctl(name, sizeof(name) / sizeof(int), if_list, &size, 0, 0) == -1) { snmp_log(LOG_ERR, "sysctl get fail\n"); } if_list_end = if_list + size; } } u_char * var_ifEntry(struct variable *vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { int interface; struct if_msghdr if_msg; static char if_name[100]; conf_if_list *if_ptr; char *cp; interface = header_ifEntry(vp, name, length, exact, var_len, write_method); if (interface == MATCH_FAILED) return NULL; if (Interface_Scan_By_Index(interface, &if_msg, if_name, NULL) != 0) return NULL; if_ptr = netsnmp_access_interface_entry_overrides_get(if_name); switch (vp->magic) { case NETSNMP_IFINDEX: long_return = interface; return (u_char *) & long_return; case NETSNMP_IFDESCR: cp = if_name; *var_len = strlen(if_name); return (u_char *) cp; case NETSNMP_IFTYPE: if (if_ptr) long_return = if_ptr->type; else long_return = (long) if_msg.ifm_data.ifi_type; return (u_char *) & long_return; case NETSNMP_IFMTU: long_return = (long) if_msg.ifm_data.ifi_mtu; return (u_char *) & long_return; case NETSNMP_IFSPEED: if (if_ptr) long_return = if_ptr->speed; else { #if HAVE_STRUCT_IFNET_IF_BAUDRATE_IFS_VALUE long_return = (u_long) if_msg.ifm_data.ifi_baudrate.ifs_value << if_msg.ifm_data.ifi_baudrate.ifs_log2; #else long_return = (u_long) if_msg.ifm_data.ifi_baudrate; #endif } return (u_char *) & long_return; case NETSNMP_IFPHYSADDRESS: /* * XXX */ return NULL; case NETSNMP_IFADMINSTATUS: long_return = if_msg.ifm_flags & IFF_UP ? 1 : 2; return (u_char *) & long_return; case NETSNMP_IFOPERSTATUS: long_return = if_msg.ifm_flags & IFF_RUNNING ? 1 : 2; return (u_char *) & long_return; /* * ifLastChange */ case NETSNMP_IFINOCTETS: long_return = (u_long) if_msg.ifm_data.ifi_ibytes; return (u_char *) & long_return; case NETSNMP_IFINUCASTPKTS: long_return = (u_long) if_msg.ifm_data.ifi_ipackets - if_msg.ifm_data.ifi_imcasts; return (u_char *) & long_return; case NETSNMP_IFINNUCASTPKTS: long_return = (u_long) if_msg.ifm_data.ifi_imcasts; return (u_char *) & long_return; case NETSNMP_IFINDISCARDS: long_return = (u_long) if_msg.ifm_data.ifi_iqdrops; return (u_char *) & long_return; case NETSNMP_IFINERRORS: long_return = (u_long) if_msg.ifm_data.ifi_ierrors; return (u_char *) & long_return; case NETSNMP_IFINUNKNOWNPROTOS: long_return = (u_long) if_msg.ifm_data.ifi_noproto; return (u_char *) & long_return; case NETSNMP_IFOUTOCTETS: long_return = (u_long) if_msg.ifm_data.ifi_obytes; return (u_char *) & long_return; case NETSNMP_IFOUTUCASTPKTS: long_return = (u_long) if_msg.ifm_data.ifi_opackets - if_msg.ifm_data.ifi_omcasts; return (u_char *) & long_return; case NETSNMP_IFOUTNUCASTPKTS: long_return = (u_long) if_msg.ifm_data.ifi_omcasts; return (u_char *) & long_return; case NETSNMP_IFOUTDISCARDS: #ifdef if_odrops long_return = (u_long) if_msg.ifm_data.ifi_odrops; #else #if NETSNMP_NO_DUMMY_VALUES return NULL; #endif long_return = 0; #endif return (u_char *) & long_return; case NETSNMP_IFOUTERRORS: long_return = (u_long) if_msg.ifm_data.ifi_oerrors; return (u_char *) & long_return; case NETSNMP_IFLASTCHANGE: #ifdef irix6 long_return = 0; #else if (if_msg.ifm_data.ifi_lastchange.tv_sec == 0 && #if STRUCT_IFNET_HAS_IF_LASTCHANGE_TV_NSEC if_msg.ifm_data.ifi_lastchange.tv_nsec == 0 #else if_msg.ifm_data.ifi_lastchange.tv_usec == 0 #endif ) long_return = 0; else if (if_msg.ifm_data.ifi_lastchange.tv_sec < starttime.tv_sec) long_return = 0; else { long_return = (u_long) ((if_msg.ifm_data.ifi_lastchange.tv_sec - starttime.tv_sec) * 100 + ( #if STRUCT_IFNET_HAS_IF_LASTCHANGE_TV_NSEC if_msg.ifm_data.ifi_lastchange.tv_nsec / 1000 #else if_msg.ifm_data.ifi_lastchange.tv_usec #endif - starttime.tv_usec) / 10000); } #endif return (u_char *) & long_return; default: return 0; } } int Interface_Scan_Next(short *Index, char *Name, struct ifnet *Retifnet, struct in_ifaddr *Retin_ifaddr) { return 0; } int Interface_Scan_NextInt(int *Index, char *Name, struct ifnet *Retifnet, struct in_ifaddr *Retin_ifaddr) { return 0; } #else /* not USE_SYSCTL_IFLIST */ /********************* * * Kernel & interface information, * and internal forward declarations * *********************/ #ifndef HAVE_NET_IF_MIB_H #ifndef solaris2 #ifndef hpux11 static int Interface_Scan_By_Index(int, char *, struct ifnet *, struct in_ifaddr *); static int Interface_Get_Ether_By_Index(int, u_char *); #else static int Interface_Scan_By_Index(int, char *, nmapi_phystat *); #endif #endif /********************* * * System specific implementation functions * *********************/ #ifndef solaris2 #ifndef hpux u_char * var_ifEntry(struct variable *vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { static struct ifnet ifnet; int interface; static struct in_ifaddr in_ifaddr; static char Name[16]; char *cp; conf_if_list *if_ptr; interface = header_ifEntry(vp, name, length, exact, var_len, write_method); if (interface == MATCH_FAILED) return NULL; Interface_Scan_By_Index(interface, Name, &ifnet, &in_ifaddr); if_ptr = netsnmp_access_interface_entry_overrides_get(Name); switch (vp->magic) { case NETSNMP_IFINDEX: long_return = interface; return (u_char *) & long_return; case NETSNMP_IFDESCR: cp = Name; *var_len = strlen(cp); return (u_char *) cp; case NETSNMP_IFTYPE: if (if_ptr) long_return = if_ptr->type; else { #if HAVE_STRUCT_IFNET_IF_TYPE long_return = ifnet.if_type; #else long_return = 1; /* OTHER */ #endif } return (u_char *) & long_return; case NETSNMP_IFMTU:{ long_return = (long) ifnet.if_mtu; return (u_char *) & long_return; } case NETSNMP_IFSPEED: if (if_ptr) long_return = if_ptr->speed; else { #if HAVE_STRUCT_IFNET_IF_BAUDRATE long_return = ifnet.if_baudrate; #elif HAVE_STRUCT_IFNET_IF_SPEED long_return = ifnet.if_speed; #elif HAVE_STRUCT_IFNET_IF_TYPE && defined(IFT_ETHER) if (ifnet.if_type == IFT_ETHER) long_return = 10000000; if (ifnet.if_type == IFT_P10) long_return = 10000000; if (ifnet.if_type == IFT_P80) long_return = 80000000; if (ifnet.if_type == IFT_ISDNBASIC) long_return = 64000; /* EDSS1 only */ if (ifnet.if_type == IFT_ISDNPRIMARY) long_return = 64000 * 30; #else #if NETSNMP_NO_DUMMY_VALUES return NULL; #endif long_return = (u_long) 10000000; #endif } return (u_char *) & long_return; case NETSNMP_IFPHYSADDRESS: Interface_Get_Ether_By_Index(interface, return_buf); #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7) *var_len = 0; #else if ((return_buf[0] == 0) && (return_buf[1] == 0) && (return_buf[2] == 0) && (return_buf[3] == 0) && (return_buf[4] == 0) && (return_buf[5] == 0)) *var_len = 0; else *var_len = 6; #endif return (u_char *) return_buf; case NETSNMP_IFADMINSTATUS: long_return = ifnet.if_flags & IFF_UP ? 1 : 2; return (u_char *) & long_return; case NETSNMP_IFOPERSTATUS: long_return = ifnet.if_flags & IFF_RUNNING ? 1 : 2; return (u_char *) & long_return; case NETSNMP_IFLASTCHANGE: #if defined(HAVE_STRUCT_IFNET_IF_LASTCHANGE_TV_SEC) && !(defined(freebsd2) && __FreeBSD_version < 199607) /* * XXX - SNMP's ifLastchange is time when op. status changed * * FreeBSD's if_lastchange is time when packet was input or output * * (at least in 2.1.0-RELEASE. Changed in later versions of the kernel?) */ /* * FreeBSD's if_lastchange before the 2.1.5 release is the time when * * a packet was last input or output. In the 2.1.5 and later releases, * * this is fixed, thus the 199607 comparison. */ if (ifnet.if_lastchange.tv_sec == 0 && ifnet.if_lastchange.tv_usec == 0) long_return = 0; else if (ifnet.if_lastchange.tv_sec < starttime.tv_sec) long_return = 0; else { long_return = (u_long) ((ifnet.if_lastchange.tv_sec - starttime.tv_sec) * 100 + (ifnet.if_lastchange.tv_usec - starttime.tv_usec) / 10000); } #else #if NETSNMP_NO_DUMMY_VALUES return NULL; #endif long_return = 0; /* XXX */ #endif return (u_char *) & long_return; case NETSNMP_IFINOCTETS: #ifdef HAVE_STRUCT_IFNET_IF_IBYTES #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7) long_return = (u_long) ifnet.if_ibytes & 0xffffffff; #else long_return = (u_long) ifnet.if_ibytes; #endif #else #if NETSNMP_NO_DUMMY_VALUES return NULL; #endif long_return = (u_long) ifnet.if_ipackets * 308; /* XXX */ #endif return (u_char *) & long_return; case NETSNMP_IFINUCASTPKTS: { #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7) long_return = (u_long) ifnet.if_ipackets & 0xffffffff; #else long_return = (u_long) ifnet.if_ipackets; #endif #if HAVE_STRUCT_IFNET_IF_IMCASTS #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7) long_return -= (u_long) ifnet.if_imcasts & 0xffffffff; #else long_return -= (u_long) ifnet.if_imcasts; #endif #endif } return (u_char *) & long_return; case NETSNMP_IFINNUCASTPKTS: #if HAVE_STRUCT_IFNET_IF_IMCASTS #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7) long_return = (u_long) ifnet.if_imcasts & 0xffffffff; #else long_return = (u_long) ifnet.if_imcasts; #endif #else #if NETSNMP_NO_DUMMY_VALUES return NULL; #endif long_return = (u_long) 0; /* XXX */ #endif return (u_char *) & long_return; case NETSNMP_IFINDISCARDS: #if HAVE_STRUCT_IFNET_IF_IQDROPS #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7) long_return = (u_long) ifnet.if_iqdrops & 0xffffffff; #else long_return = (u_long) ifnet.if_iqdrops; #endif #else #if NETSNMP_NO_DUMMY_VALUES return NULL; #endif long_return = (u_long) 0; /* XXX */ #endif return (u_char *) & long_return; case NETSNMP_IFINERRORS: #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7) long_return = (u_long) ifnet.if_ierrors & 0xffffffff; #else long_return = (u_long) ifnet.if_ierrors; #endif return (u_char *) & long_return; case NETSNMP_IFINUNKNOWNPROTOS: #if HAVE_STRUCT_IFNET_IF_NOPROTO #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7) long_return = (u_long) ifnet.if_noproto & 0xffffffff; #else long_return = (u_long) ifnet.if_noproto; #endif #else #if NETSNMP_NO_DUMMY_VALUES return NULL; #endif long_return = (u_long) 0; /* XXX */ #endif return (u_char *) & long_return; case NETSNMP_IFOUTOCTETS: #ifdef HAVE_STRUCT_IFNET_IF_OBYTES #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7) long_return = (u_long) ifnet.if_obytes & 0xffffffff; #else long_return = (u_long) ifnet.if_obytes; #endif #else #if NETSNMP_NO_DUMMY_VALUES return NULL; #endif long_return = (u_long) ifnet.if_opackets * 308; /* XXX */ #endif return (u_char *) & long_return; case NETSNMP_IFOUTUCASTPKTS: { #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7) long_return = (u_long) ifnet.if_opackets & 0xffffffff; #else long_return = (u_long) ifnet.if_opackets; #endif #if HAVE_STRUCT_IFNET_IF_OMCASTS #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7) long_return -= (u_long) ifnet.if_omcasts & 0xffffffff; #else long_return -= (u_long) ifnet.if_omcasts; #endif #endif } return (u_char *) & long_return; case NETSNMP_IFOUTNUCASTPKTS: #if HAVE_STRUCT_IFNET_IF_OMCASTS #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7) long_return = (u_long) ifnet.if_omcasts & 0xffffffff; #else long_return = (u_long) ifnet.if_omcasts; #endif #else #if NETSNMP_NO_DUMMY_VALUES return NULL; #endif long_return = (u_long) 0; /* XXX */ #endif return (u_char *) & long_return; case NETSNMP_IFOUTDISCARDS: #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7) long_return = ifnet.if_snd.ifq_drops & 0xffffffff; #else long_return = ifnet.if_snd.ifq_drops; #endif return (u_char *) & long_return; case NETSNMP_IFOUTERRORS: #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7) long_return = ifnet.if_oerrors & 0xffffffff; #else long_return = ifnet.if_oerrors; #endif return (u_char *) & long_return; case NETSNMP_IFOUTQLEN: #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7) long_return = ifnet.if_snd.ifq_len & 0xffffffff; #else long_return = ifnet.if_snd.ifq_len; #endif return (u_char *) & long_return; case NETSNMP_IFSPECIFIC: *var_len = nullOidLen; return (u_char *) nullOid; default: DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ifEntry\n", vp->magic)); } return NULL; } #else /* hpux */ u_char * var_ifEntry(struct variable *vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { #if defined(hpux11) static nmapi_phystat ifnet; #else static struct ifnet ifnet; #endif register int interface; #if !defined(hpux11) static struct in_ifaddr in_ifaddrVar; #endif #if defined(hpux11) static char Name[MAX_PHYSADDR_LEN]; #else static char Name[16]; #endif register char *cp; #if HAVE_STRUCT_IFNET_IF_LASTCHANGE_TV_SEC struct timeval now; #endif #if !defined(hpux11) struct nmparms hp_nmparms; static mib_ifEntry hp_ifEntry; int hp_fd; int hp_len = sizeof(hp_ifEntry); #endif conf_if_list *if_ptr; interface = header_ifEntry(vp, name, length, exact, var_len, write_method); if (interface == MATCH_FAILED) return NULL; #if defined(hpux11) Interface_Scan_By_Index(interface, Name, &ifnet); #else Interface_Scan_By_Index(interface, Name, &ifnet, &in_ifaddrVar); #endif #if !defined(hpux11) /* * Additional information about the interfaces is available under * HP-UX through the network management interface '/dev/netman' */ hp_ifEntry.ifIndex = interface; hp_nmparms.objid = ID_ifEntry; hp_nmparms.buffer = (char *) &hp_ifEntry; hp_nmparms.len = &hp_len; if ((hp_fd = open("/dev/netman", O_RDONLY)) != -1) { if (ioctl(hp_fd, NMIOGET, &hp_nmparms) != -1) { close(hp_fd); } else { close(hp_fd); hp_fd = -1; /* failed */ } } #endif if_ptr = netsnmp_access_interface_entry_overrides_get(Name); switch (vp->magic) { case NETSNMP_IFINDEX: long_return = interface; return (u_char *) & long_return; case NETSNMP_IFDESCR: #if defined(hpux11) cp = ifnet.if_entry.ifDescr; #else if (hp_fd != -1) cp = hp_ifEntry.ifDescr; else cp = Name; #endif *var_len = strlen(cp); return (u_char *) cp; case NETSNMP_IFTYPE: if (if_ptr) long_return = if_ptr->type; else { #if defined(hpux11) long_return = ifnet.if_entry.ifType; #else if (hp_fd != -1) long_return = hp_ifEntry.ifType; else long_return = 1; /* OTHER */ #endif } return (u_char *) & long_return; case NETSNMP_IFMTU:{ #if defined(hpux11) long_return = (long) ifnet.if_entry.ifMtu; #else long_return = (long) ifnet.if_mtu; #endif return (u_char *) & long_return; } case NETSNMP_IFSPEED: if (if_ptr) long_return = if_ptr->speed; else { #if defined(hpux11) long_return = ifnet.if_entry.ifSpeed; #else if (hp_fd != -1) long_return = hp_ifEntry.ifSpeed; else long_return = (u_long) 1; /* OTHER */ #endif } return (u_char *) & long_return; case NETSNMP_IFPHYSADDRESS: #if defined(hpux11) *var_len = ifnet.if_entry.ifPhysAddress.o_length; return (u_char *) ifnet.if_entry.ifPhysAddress.o_bytes; #else Interface_Get_Ether_By_Index(interface, return_buf); if ((return_buf[0] == 0) && (return_buf[1] == 0) && (return_buf[2] == 0) && (return_buf[3] == 0) && (return_buf[4] == 0) && (return_buf[5] == 0)) *var_len = 0; else *var_len = 6; return (u_char *) return_buf; #endif case NETSNMP_IFADMINSTATUS: #if defined(hpux11) long_return = ifnet.if_entry.ifAdmin; #else long_return = ifnet.if_flags & IFF_UP ? 1 : 2; #endif return (u_char *) & long_return; case NETSNMP_IFOPERSTATUS: #if defined(hpux11) long_return = ifnet.if_entry.ifOper; #else long_return = ifnet.if_flags & IFF_RUNNING ? 1 : 2; #endif return (u_char *) & long_return; case NETSNMP_IFLASTCHANGE: #if defined(hpux11) long_return = ifnet.if_entry.ifLastChange; #else if (hp_fd != -1) long_return = hp_ifEntry.ifLastChange; else long_return = 0; /* XXX */ #endif return (u_char *) & long_return; case NETSNMP_IFINOCTETS: #if defined(hpux11) long_return = ifnet.if_entry.ifInOctets; #else if (hp_fd != -1) long_return = hp_ifEntry.ifInOctets; else long_return = (u_long) ifnet.if_ipackets * 308; /* XXX */ #endif return (u_char *) & long_return; case NETSNMP_IFINUCASTPKTS: #if defined(hpux11) long_return = ifnet.if_entry.ifInUcastPkts; #else if (hp_fd != -1) long_return = hp_ifEntry.ifInUcastPkts; else long_return = (u_long) ifnet.if_ipackets; #endif return (u_char *) & long_return; case NETSNMP_IFINNUCASTPKTS: #if defined(hpux11) long_return = ifnet.if_entry.ifInNUcastPkts; #else if (hp_fd != -1) long_return = hp_ifEntry.ifInNUcastPkts; else long_return = (u_long) 0; /* XXX */ #endif return (u_char *) & long_return; case NETSNMP_IFINDISCARDS: #if defined(hpux11) long_return = ifnet.if_entry.ifInDiscards; #else if (hp_fd != -1) long_return = hp_ifEntry.ifInDiscards; else long_return = (u_long) 0; /* XXX */ #endif return (u_char *) & long_return; case NETSNMP_IFINERRORS: #if defined(hpux11) long_return = ifnet.if_entry.ifInErrors; #else long_return = ifnet.if_ierrors; #endif return (u_char *) & long_return; case NETSNMP_IFINUNKNOWNPROTOS: #if defined(hpux11) long_return = ifnet.if_entry.ifInUnknownProtos; #else if (hp_fd != -1) long_return = hp_ifEntry.ifInUnknownProtos; else long_return = (u_long) 0; /* XXX */ #endif return (u_char *) & long_return; case NETSNMP_IFOUTOCTETS: #if defined(hpux11) long_return = ifnet.if_entry.ifOutOctets; #else if (hp_fd != -1) long_return = hp_ifEntry.ifOutOctets; else long_return = (u_long) ifnet.if_opackets * 308; /* XXX */ #endif return (u_char *) & long_return; case NETSNMP_IFOUTUCASTPKTS: #if defined(hpux11) long_return = ifnet.if_entry.ifOutUcastPkts; #else if (hp_fd != -1) long_return = hp_ifEntry.ifOutUcastPkts; else long_return = (u_long) ifnet.if_opackets; #endif return (u_char *) & long_return; case NETSNMP_IFOUTNUCASTPKTS: #if defined(hpux11) long_return = ifnet.if_entry.ifOutNUcastPkts; #else if (hp_fd != -1) long_return = hp_ifEntry.ifOutNUcastPkts; else long_return = (u_long) 0; /* XXX */ #endif return (u_char *) & long_return; case NETSNMP_IFOUTDISCARDS: #if defined(hpux11) long_return = ifnet.if_entry.ifOutDiscards; #else long_return = ifnet.if_snd.ifq_drops; #endif return (u_char *) & long_return; case NETSNMP_IFOUTERRORS: #if defined(hpux11) long_return = ifnet.if_entry.ifOutErrors; #else long_return = ifnet.if_oerrors; #endif return (u_char *) & long_return; case NETSNMP_IFOUTQLEN: #if defined(hpux11) long_return = ifnet.if_entry.ifOutQlen; #else long_return = ifnet.if_snd.ifq_len; #endif return (u_char *) & long_return; case NETSNMP_IFSPECIFIC: *var_len = nullOidLen; return (u_char *) nullOid; default: DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ifEntry\n", vp->magic)); } return NULL; } #endif /* hpux */ #else /* solaris2 */ static int IF_cmp(void *addr, void *ep) { DEBUGMSGTL(("mibII/interfaces", "... IF_cmp %d %d\n", ((mib2_ifEntry_t *) ep)->ifIndex, ((mib2_ifEntry_t *) addr)->ifIndex)); if (((mib2_ifEntry_t *) ep)->ifIndex == ((mib2_ifEntry_t *) addr)->ifIndex) return (0); else return (1); } u_char * var_ifEntry(struct variable * vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { int interface; mib2_ifEntry_t ifstat; conf_if_list *if_ptr = NULL; interface = header_ifEntry(vp, name, length, exact, var_len, write_method); if (interface == MATCH_FAILED) return NULL; if (getMibstat(MIB_INTERFACES, &ifstat, sizeof(mib2_ifEntry_t), GET_EXACT, &IF_cmp, &interface) != 0) { DEBUGMSGTL(("mibII/interfaces", "... no mib stats\n")); return NULL; } /* * hmmm.. where to get the interface name to check overrides? * * if_ptr = netsnmp_access_interface_entry_overrides_get(Name); */ switch (vp->magic) { case NETSNMP_IFINDEX: long_return = ifstat.ifIndex; return (u_char *) & long_return; case NETSNMP_IFDESCR: *var_len = ifstat.ifDescr.o_length; (void) memcpy(return_buf, ifstat.ifDescr.o_bytes, *var_len); return (u_char *) return_buf; case NETSNMP_IFTYPE: if (if_ptr) long_return = if_ptr->type; else long_return = (u_long) ifstat.ifType; return (u_char *) & long_return; case NETSNMP_IFMTU: long_return = (u_long) ifstat.ifMtu; return (u_char *) & long_return; case NETSNMP_IFSPEED: if (if_ptr) long_return = if_ptr->speed; else long_return = (u_long) ifstat.ifSpeed; return (u_char *) & long_return; case NETSNMP_IFPHYSADDRESS: *var_len = ifstat.ifPhysAddress.o_length; (void) memcpy(return_buf, ifstat.ifPhysAddress.o_bytes, *var_len); return (u_char *) return_buf; case NETSNMP_IFADMINSTATUS: long_return = (u_long) ifstat.ifAdminStatus; return (u_char *) & long_return; case NETSNMP_IFOPERSTATUS: long_return = (u_long) ifstat.ifOperStatus; return (u_char *) & long_return; case NETSNMP_IFLASTCHANGE: long_return = (u_long) ifstat.ifLastChange; return (u_char *) & long_return; case NETSNMP_IFINOCTETS: long_return = (u_long) ifstat.ifInOctets; return (u_char *) & long_return; case NETSNMP_IFINUCASTPKTS: long_return = (u_long) ifstat.ifInUcastPkts; return (u_char *) & long_return; case NETSNMP_IFINNUCASTPKTS: long_return = (u_long) ifstat.ifInNUcastPkts; return (u_char *) & long_return; case NETSNMP_IFINDISCARDS: long_return = (u_long) ifstat.ifInDiscards; return (u_char *) & long_return; case NETSNMP_IFINERRORS: long_return = (u_long) ifstat.ifInErrors; return (u_char *) & long_return; case NETSNMP_IFINUNKNOWNPROTOS: long_return = (u_long) ifstat.ifInUnknownProtos; return (u_char *) & long_return; case NETSNMP_IFOUTOCTETS: long_return = (u_long) ifstat.ifOutOctets; return (u_char *) & long_return; case NETSNMP_IFOUTUCASTPKTS: long_return = (u_long) ifstat.ifOutUcastPkts; return (u_char *) & long_return; case NETSNMP_IFOUTNUCASTPKTS: long_return = (u_long) ifstat.ifOutNUcastPkts; return (u_char *) & long_return; case NETSNMP_IFOUTDISCARDS: long_return = (u_long) ifstat.ifOutDiscards; return (u_char *) & long_return; case NETSNMP_IFOUTERRORS: long_return = (u_long) ifstat.ifOutErrors; return (u_char *) & long_return; case NETSNMP_IFOUTQLEN: long_return = (u_long) ifstat.ifOutQLen; return (u_char *) & long_return; case NETSNMP_IFSPECIFIC: long_return = (u_long) ifstat.ifSpecific; return (u_char *) & long_return; default: DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ifEntry\n", vp->magic)); } return NULL; } #endif /* solaris2 */ /********************* * * Internal implementation functions * *********************/ #ifndef solaris2 #if !defined(sunV3) && !defined(linux) && !defined(hpux11) static struct in_ifaddr savein_ifaddr; #endif #if !defined(hpux11) static struct ifnet *ifnetaddr, saveifnet, *saveifnetaddr; static char saveName[16]; #endif static int saveIndex = 0; /** * Determines network interface speed. It is system specific. Only linux * realization is made. */ unsigned int getIfSpeed(int fd, struct ifreq ifr, unsigned int defaultspeed) { #ifdef linux return netsnmp_linux_interface_get_if_speed(fd, ifr.ifr_name, defaultspeed); #else /*!linux*/ return defaultspeed; #endif } void Interface_Scan_Init(void) { #ifdef linux char line[256], ifname_buf[64], *ifname, *ptr; struct ifreq ifrq; struct ifnet **ifnetaddr_ptr; FILE *devin; int i, fd; conf_if_list *if_ptr; /* * scanline_2_2: * [ IN ] * byte pkts errs drop fifo frame cmprs mcst | * [ OUT ] * byte pkts errs drop fifo colls carrier compressed */ uintmax_t rec_pkt, rec_oct, rec_err, rec_drop; uintmax_t snd_pkt, snd_oct, snd_err, snd_drop, coll; const char *scan_line_2_2 = "%" SCNuMAX " %" SCNuMAX " %" SCNuMAX " %" SCNuMAX " %*" SCNuMAX " %*" SCNuMAX " %*" SCNuMAX " %*" SCNuMAX " %" SCNuMAX " %" SCNuMAX " %" SCNuMAX " %" SCNuMAX " %*" SCNuMAX " %" SCNuMAX; const char *scan_line_2_0 = "%" SCNuMAX " %" SCNuMAX " %*" SCNuMAX " %*" SCNuMAX " %*" SCNuMAX " %" SCNuMAX " %" SCNuMAX " %*" SCNuMAX " %*" SCNuMAX " %" SCNuMAX; const char *scan_line_to_use; struct timeval et; /* elapsed time */ #endif #if !defined(hpux11) && defined(IFNET_SYMBOL) auto_nlist(IFNET_SYMBOL, (char *) &ifnetaddr, sizeof(ifnetaddr)); #endif saveIndex = 0; #ifdef linux /* disallow reloading of structures too often */ netsnmp_get_monotonic_clock(&et); if ( et.tv_sec < LastLoad + MINLOADFREQ ) { /* only reload so often */ ifnetaddr = ifnetaddr_list; /* initialize pointer */ return; } LastLoad = et.tv_sec; /* * free old list: */ while (ifnetaddr_list) { struct ifnet *old = ifnetaddr_list; ifnetaddr_list = ifnetaddr_list->if_next; free(old->if_name); free(old->if_unit); free(old); } ifnetaddr = 0; ifnetaddr_ptr = &ifnetaddr_list; if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { DEBUGMSGTL(("snmpd", "socket open failure in Interface_Scan_Init\n")); return; /** exit (1); **/ } /* * build up ifnetaddr list by hand: */ /* * at least linux v1.3.53 says EMFILE without reason... */ if (!(devin = fopen("/proc/net/dev", "r"))) { close(fd); NETSNMP_LOGONCE((LOG_ERR, "cannot open /proc/net/dev.\n")); return; /** exit (1); **/ } i = 0; /* * read the second line (a header) and determine the fields we * should read from. This should be done in a better way by * actually looking for the field names we want. But thats too * much work for today. -- Wes */ fgets(line, sizeof(line), devin); fgets(line, sizeof(line), devin); if (strstr(line, "compressed")) { scan_line_to_use = scan_line_2_2; DEBUGMSGTL(("mibII/interfaces", "using linux 2.2 kernel /proc/net/dev\n")); } else { scan_line_to_use = scan_line_2_0; DEBUGMSGTL(("mibII/interfaces", "using linux 2.0 kernel /proc/net/dev\n")); } while (fgets(line, sizeof(line), devin)) { struct ifnet *nnew; char *stats, *ifstart = line; /* Ignore interfaces with no statistics. */ if (strstr(line, "No statistics available.")) continue; if (line[strlen(line) - 1] == '\n') line[strlen(line) - 1] = '\0'; while (*ifstart && *ifstart == ' ') ifstart++; if (!*ifstart || ((stats = strrchr(ifstart, ':')) == NULL)) { snmp_log(LOG_ERR, "/proc/net/dev data format error, line ==|%s|", line); continue; } if ((scan_line_to_use == scan_line_2_2) && ((stats - line) < 6)) { snmp_log(LOG_ERR, "/proc/net/dev data format error, line ==|%s|", line); } *stats = 0; strlcpy(ifname_buf, ifstart, sizeof(ifname_buf)); *stats++ = ':'; while (*stats == ' ') stats++; if ((scan_line_to_use == scan_line_2_2 && sscanf(stats, scan_line_to_use, &rec_oct, &rec_pkt, &rec_err, &rec_drop, &snd_oct, &snd_pkt, &snd_err, &snd_drop, &coll) != 9) || (scan_line_to_use == scan_line_2_0 && sscanf(stats, scan_line_to_use, &rec_pkt, &rec_err, &snd_pkt, &snd_err, &coll) != 5)) { if ((scan_line_to_use == scan_line_2_2) && !strstr(line, "No statistics available")) snmp_log(LOG_DEBUG, "/proc/net/dev data format error, line ==|%s|", line); continue; } nnew = (struct ifnet *) calloc(1, sizeof(struct ifnet)); if (nnew == NULL) break; /* alloc error */ /* * chain in: */ *ifnetaddr_ptr = nnew; ifnetaddr_ptr = &nnew->if_next; i++; /* * linux previous to 1.3.~13 may miss transmitted loopback pkts: */ if (!strcmp(ifname_buf, "lo") && rec_pkt > 0 && !snd_pkt) snd_pkt = rec_pkt; nnew->if_ipackets = rec_pkt & 0xffffffff; nnew->if_ierrors = rec_err; nnew->if_opackets = snd_pkt & 0xffffffff; nnew->if_oerrors = snd_err; nnew->if_collisions = coll; if (scan_line_to_use == scan_line_2_2) { nnew->if_ibytes = rec_oct & 0xffffffff; nnew->if_obytes = snd_oct & 0xffffffff; nnew->if_iqdrops = rec_drop; nnew->if_snd.ifq_drops = snd_drop; } else { nnew->if_ibytes = (rec_pkt * 308) & 0xffffffff; nnew->if_obytes = (snd_pkt * 308) & 0xffffffff; } /* * ifnames are given as `` eth0'': split in ``eth'' and ``0'': */ for (ifname = ifname_buf; *ifname && *ifname == ' '; ifname++); /* * set name and interface# : */ nnew->if_name = (char *) strdup(ifname); for (ptr = nnew->if_name; *ptr && (*ptr < '0' || *ptr > '9'); ptr++); nnew->if_unit = strdup(*ptr ? ptr : ""); *ptr = 0; strlcpy(ifrq.ifr_name, ifname, sizeof(ifrq.ifr_name)); if (ioctl(fd, SIOCGIFADDR, &ifrq) < 0) memset((char *) &nnew->if_addr, 0, sizeof(nnew->if_addr)); else nnew->if_addr = ifrq.ifr_addr; strlcpy(ifrq.ifr_name, ifname, sizeof(ifrq.ifr_name)); if (ioctl(fd, SIOCGIFBRDADDR, &ifrq) < 0) memset((char *) &nnew->ifu_broadaddr, 0, sizeof(nnew->ifu_broadaddr)); else nnew->ifu_broadaddr = ifrq.ifr_broadaddr; strlcpy(ifrq.ifr_name, ifname, sizeof(ifrq.ifr_name)); if (ioctl(fd, SIOCGIFNETMASK, &ifrq) < 0) memset((char *) &nnew->ia_subnetmask, 0, sizeof(nnew->ia_subnetmask)); else nnew->ia_subnetmask = ifrq.ifr_netmask; strlcpy(ifrq.ifr_name, ifname, sizeof(ifrq.ifr_name)); nnew->if_flags = ioctl(fd, SIOCGIFFLAGS, &ifrq) < 0 ? 0 : ifrq.ifr_flags; nnew->if_type = 0; /* * NOTE: this ioctl does not guarantee 6 bytes of a physaddr. * In particular, a 'sit0' interface only appears to get back * 4 bytes of sa_data. */ memset(ifrq.ifr_hwaddr.sa_data, (0), IFHWADDRLEN); strlcpy(ifrq.ifr_name, ifname, sizeof(ifrq.ifr_name)); if (ioctl(fd, SIOCGIFHWADDR, &ifrq) < 0) memset(nnew->if_hwaddr, (0), IFHWADDRLEN); else { memcpy(nnew->if_hwaddr, ifrq.ifr_hwaddr.sa_data, IFHWADDRLEN); #ifdef ARPHRD_LOOPBACK switch (ifrq.ifr_hwaddr.sa_family) { case ARPHRD_ETHER: nnew->if_type = 6; break; case ARPHRD_TUNNEL: case ARPHRD_TUNNEL6: #ifdef ARPHRD_IPGRE case ARPHRD_IPGRE: #endif case ARPHRD_SIT: nnew->if_type = 131; break; /* tunnel */ case ARPHRD_SLIP: case ARPHRD_CSLIP: case ARPHRD_SLIP6: case ARPHRD_CSLIP6: nnew->if_type = 28; break; /* slip */ case ARPHRD_PPP: nnew->if_type = 23; break; /* ppp */ case ARPHRD_LOOPBACK: nnew->if_type = 24; break; /* softwareLoopback */ case ARPHRD_FDDI: nnew->if_type = 15; break; case ARPHRD_ARCNET: nnew->if_type = 35; break; case ARPHRD_LOCALTLK: nnew->if_type = 42; break; #ifdef ARPHRD_HIPPI case ARPHRD_HIPPI: nnew->if_type = 47; break; #endif #ifdef ARPHRD_ATM case ARPHRD_ATM: nnew->if_type = 37; break; #endif /* * XXX: more if_arp.h:ARPHDR_xxx to IANAifType mappings... */ } #endif } strlcpy(ifrq.ifr_name, ifname, sizeof(ifrq.ifr_name)); nnew->if_metric = ioctl(fd, SIOCGIFMETRIC, &ifrq) < 0 ? 0 : ifrq.ifr_metric; #ifdef SIOCGIFMTU strlcpy(ifrq.ifr_name, ifname, sizeof(ifrq.ifr_name)); nnew->if_mtu = (ioctl(fd, SIOCGIFMTU, &ifrq) < 0) ? 0 : ifrq.ifr_mtu; #else nnew->if_mtu = 0; #endif if_ptr = netsnmp_access_interface_entry_overrides_get(ifname); if (if_ptr) { nnew->if_type = if_ptr->type; nnew->if_speed = if_ptr->speed; } else { /* * do only guess if_type from name, if we could not read * * it before from SIOCGIFHWADDR */ unsigned int defaultspeed = NOMINAL_LINK_SPEED; if (!(nnew->if_flags & IFF_RUNNING)) { /* * use speed 0 if the if speed cannot be determined *and* the * interface is down */ defaultspeed = 0; } if (!nnew->if_type) nnew->if_type = if_type_from_name(nnew->if_name); switch(nnew->if_type) { case 6: nnew->if_speed = getIfSpeed(fd, ifrq, defaultspeed); break; case 24: nnew->if_speed = 10000000; break; case 9: nnew->if_speed = 4000000; break; default: nnew->if_speed = 0; } /*Zero speed means link problem*/ if(nnew->if_speed == 0 && nnew->if_flags & IFF_UP){ nnew->if_flags &= ~IFF_RUNNING; } } } /* while (fgets ... */ ifnetaddr = ifnetaddr_list; if (snmp_get_do_debugging()) { { struct ifnet *x = ifnetaddr; DEBUGMSGTL(("mibII/interfaces", "* see: known interfaces:")); while (x) { DEBUGMSG(("mibII/interfaces", " %s", x->if_name)); x = x->if_next; } DEBUGMSG(("mibII/interfaces", "\n")); } /* XXX */ } fclose(devin); close(fd); #endif /* linux */ } #if defined(sunV3) || defined(linux) /* * ** 4.2 BSD doesn't have ifaddr * ** */ int Interface_Scan_Next(short *Index, char *Name, struct ifnet *Retifnet, struct in_ifaddr *dummy) { int returnIndex = 0; int ret; if (Index) returnIndex = *Index; ret = Interface_Scan_NextInt( &returnIndex, Name, Retifnet, dummy ); if (Index) *Index = (returnIndex & 0x8fff); return ret; } int Interface_Scan_NextInt(int *Index, char *Name, struct ifnet *Retifnet, struct in_ifaddr *dummy) { struct ifnet ifnet; #if !defined(linux) register char *cp; #endif while (ifnetaddr) { /* * Get the "ifnet" structure and extract the device name */ #ifndef linux if (!NETSNMP_KLOOKUP(ifnetaddr, (char *) &ifnet, sizeof ifnet)) { DEBUGMSGTL(("mibII/interfaces:Interface_Scan_Next", "klookup failed\n")); break; } if (!NETSNMP_KLOOKUP(ifnet.if_name, (char *) saveName, sizeof saveName)) { DEBUGMSGTL(("mibII/interfaces:Interface_Scan_Next", "klookup failed\n")); break; } /* * The purpose of this comparison is lost in the mists of time. * It's been around at least cmu-snmp 2.1.2 for SUNv3 systems and * was applied to linux systems during the cmu-snmp-linux project. * No-one now knows what it was intended for, and it breaks IPv6 * tunnel interfaces, so it's been moved out of the Linux code block. */ if (strcmp(saveName, "ip") == 0) { ifnetaddr = ifnet.if_next; continue; } #else ifnet = *ifnetaddr; strlcpy(saveName, ifnet.if_name, sizeof(saveName)); #endif saveName[sizeof(saveName) - 1] = '\0'; #ifdef linux strlcat(saveName, ifnet.if_unit, sizeof(saveName)); #else #ifdef NETSNMP_FEATURE_CHECKIN /* this exists here just so we don't copy ifdef logic elsewhere */ netsnmp_feature_require(string_append_int); #endif cp = (char *) strchr(saveName, '\0'); string_append_int(cp, ifnet.if_unit); #endif if (1 || strcmp(saveName, "lo0") != 0) { /* XXX */ if (Index) *Index = ++saveIndex; if (Retifnet) *Retifnet = ifnet; if (Name) strcpy(Name, saveName); saveifnet = ifnet; saveifnetaddr = ifnetaddr; ifnetaddr = ifnet.if_next; return (1); /* DONE */ } ifnetaddr = ifnet.if_next; } return (0); /* EOF */ } #ifdef linux int Interface_Index_By_Name(char *Name, int Len) { int ifIndex = 0; char ifName[20]; Interface_Scan_Init(); while (Interface_Scan_NextInt(&ifIndex, ifName, NULL, NULL) && strcmp(Name, ifName)); return ifIndex; } #endif #else /* sunV3 || linux */ #if defined(netbsd1) || defined(openbsd2) #define ia_next ia_list.tqe_next #define if_next if_list.tqe_next #endif #if defined(hpux11) int Interface_Scan_Next(short *Index, char *Name, nmapi_phystat * Retifnet) { int returnIndex = 0; int ret; if (Index) returnIndex = *Index; ret = Interface_Scan_NextInt( &returnIndex, Name, Retifnet ); if (Index) *Index = (returnIndex & 0x8fff); return ret; } int Interface_Scan_NextInt(int *Index, char *Name, nmapi_phystat * Retifnet) { static nmapi_phystat *if_ptr = (nmapi_phystat *) 0; int count = Interface_Scan_Get_Count(); unsigned int ulen; int ret; if (!if_ptr) { if (count) { if_ptr = (nmapi_phystat *) malloc(sizeof(nmapi_phystat) * count); if (if_ptr == NULL) return (0); } else return (0); /* EOF */ } if (saveIndex >= count) return (0); /* EOF */ ulen = (unsigned int) count *sizeof(nmapi_phystat); if ((ret = get_physical_stat(if_ptr, &ulen)) < 0) return (0); /* EOF */ if (Retifnet) *Retifnet = if_ptr[saveIndex]; if (Name) strcpy(Name, if_ptr[saveIndex].nm_device); saveIndex++; if (Index) *Index = saveIndex; return (1); /* DONE */ } #else /* hpux11 */ int Interface_Scan_Next(short *Index, char *Name, struct ifnet *Retifnet, struct in_ifaddr *Retin_ifaddr) { int returnIndex = 0; int ret; if (Index) returnIndex = *Index; ret = Interface_Scan_NextInt( &returnIndex, Name, Retifnet, Retin_ifaddr ); if (Index) *Index = (returnIndex & 0x8fff); return ret; } int Interface_Scan_NextInt(int *Index, char *Name, struct ifnet *Retifnet, struct in_ifaddr *Retin_ifaddr) { struct ifnet ifnet; struct in_ifaddr *ia, in_ifaddr; short has_ipaddr = 0; #if !HAVE_STRUCT_IFNET_IF_XNAME register char *cp; #endif while (ifnetaddr) { /* * Get the "ifnet" structure and extract the device name */ if (!NETSNMP_KLOOKUP(ifnetaddr, (char *) &ifnet, sizeof ifnet)) { DEBUGMSGTL(("mibII/interfaces:Interface_Scan_Next", "klookup failed\n")); break; } #if HAVE_STRUCT_IFNET_IF_XNAME #if defined(netbsd1) || defined(openbsd2) strlcpy(saveName, ifnet.if_xname, sizeof(saveName)); #else if (!NETSNMP_KLOOKUP(ifnet.if_xname, (char *) saveName, sizeof saveName)) { DEBUGMSGTL(("mibII/interfaces:Interface_Scan_Next", "klookup failed\n")); break; } #endif saveName[sizeof(saveName) - 1] = '\0'; #else if (!NETSNMP_KLOOKUP(ifnet.if_name, (char *) saveName, sizeof saveName)) { DEBUGMSGTL(("mibII/interfaces:Interface_Scan_Next", "klookup failed\n")); break; } saveName[sizeof(saveName) - 1] = '\0'; cp = strchr(saveName, '\0'); #ifdef NETSNMP_FEATURE_CHECKIN /* this exists here just so we don't copy ifdef logic elsewhere */ netsnmp_feature_require(string_append_int); #endif string_append_int(cp, ifnet.if_unit); #endif if (1 || strcmp(saveName, "lo0") != 0) { /* XXX */ /* * Try to find an address for this interface */ #ifdef netbsd1 ia = (struct in_ifaddr *) ifnet.if_addrlist.tqh_first; #elif defined(IFADDR_SYMBOL) auto_nlist(IFADDR_SYMBOL, (char *) &ia, sizeof(ia)); #endif while (ia) { if (!NETSNMP_KLOOKUP(ia, (char *) &in_ifaddr, sizeof(in_ifaddr))) { DEBUGMSGTL(("mibII/interfaces:Interface_Scan_Next", "klookup failed\n")); break; } { #ifdef netbsd1 #define CP(x) ((char *)(x)) char *cp; struct sockaddr *sa; cp = (CP(in_ifaddr.ia_ifa.ifa_addr) - CP(ia)) + CP(&in_ifaddr); sa = (struct sockaddr *) cp; if (sa->sa_family == AF_INET) #endif if (in_ifaddr.ia_ifp == ifnetaddr) { has_ipaddr = 1; /* this IF has IP-address */ break; } } #ifdef netbsd1 ia = (struct in_ifaddr *) in_ifaddr.ia_ifa.ifa_list. tqe_next; #else ia = in_ifaddr.ia_next; #endif } #if !defined(netbsd1) && !defined(freebsd2) && !defined(openbsd2) && !defined(HAVE_STRUCT_IFNET_IF_ADDRLIST) ifnet.if_addrlist = (struct ifaddr *) ia; /* WRONG DATA TYPE; ONLY A FLAG */ #endif /* * ifnet.if_addrlist = (struct ifaddr *)&ia->ia_ifa; * * WRONG DATA TYPE; ONLY A FLAG */ if (Index) *Index = ++saveIndex; if (Retifnet) *Retifnet = ifnet; if (Retin_ifaddr && has_ipaddr) /* assign the in_ifaddr only * if the IF has IP-address */ *Retin_ifaddr = in_ifaddr; if (Name) strcpy(Name, saveName); saveifnet = ifnet; saveifnetaddr = ifnetaddr; savein_ifaddr = in_ifaddr; ifnetaddr = ifnet.if_next; return (1); /* DONE */ } ifnetaddr = ifnet.if_next; } return (0); /* EOF */ } #endif /* hpux11 */ #endif /* sunV3 || linux */ #if defined(hpux11) static int Interface_Scan_By_Index(int Index, char *Name, nmapi_phystat * Retifnet) { int i; Interface_Scan_Init(); while (Interface_Scan_NextInt(&i, Name, Retifnet)) { if (i == Index) break; } if (i != Index) return (-1); /* Error, doesn't exist */ return (0); /* DONE */ } #else /* hpux11 */ static int Interface_Scan_By_Index(int Index, char *Name, struct ifnet *Retifnet, struct in_ifaddr *Retin_ifaddr) { int i; Interface_Scan_Init(); while (Interface_Scan_NextInt(&i, Name, Retifnet, Retin_ifaddr)) { if (i == Index) break; } if (i != Index) return (-1); /* Error, doesn't exist */ return (0); /* DONE */ } #endif /* hpux11 */ static int Interface_Count = 0; #if defined(hpux11) int Interface_Scan_Get_Count(void) { if (!Interface_Count) { int fd; struct nmparms p; int val; unsigned int ulen; int ret; if ((fd = open_mib("/dev/ip", O_RDONLY, 0, NM_ASYNC_OFF)) >= 0) { p.objid = ID_ifNumber; p.buffer = (void *) &val; ulen = sizeof(int); p.len = &ulen; if ((ret = get_mib_info(fd, &p)) == 0) Interface_Count = val; close_mib(fd); } } return (Interface_Count); } #else /* hpux11 */ int Interface_Scan_Get_Count(void) { static time_t scan_time = 0; time_t time_now = time(NULL); if (!Interface_Count || (time_now > scan_time + 60)) { scan_time = time_now; Interface_Scan_Init(); Interface_Count = 0; while (Interface_Scan_NextInt(NULL, NULL, NULL, NULL) != 0) { Interface_Count++; } } return (Interface_Count); } static int Interface_Get_Ether_By_Index(int Index, u_char * EtherAddr) { int i; #if !(defined(linux) || defined(netbsd1) || defined(bsdi2) || defined(openbsd2)) struct arpcom arpcom; #else /* is linux or netbsd1 */ struct arpcom { char ac_enaddr[6]; } arpcom; #if defined(netbsd1) || defined(bsdi2) || defined(openbsd2) struct sockaddr_dl sadl; struct ifaddr ifaddr; u_long ifaddraddr; #endif #endif #if defined(mips) || defined(hpux) || defined(osf4) || defined(osf3) || defined(osf5) memset(arpcom.ac_enaddr, 0, sizeof(arpcom.ac_enaddr)); #else memset(&arpcom.ac_enaddr, 0, sizeof(arpcom.ac_enaddr)); #endif memset(EtherAddr, 0, sizeof(arpcom.ac_enaddr)); if (saveIndex != Index) { /* Optimization! */ Interface_Scan_Init(); while (Interface_Scan_NextInt(&i, NULL, NULL, NULL) != 0) { if (i == Index) break; } if (i != Index) return (-1); /* Error, doesn't exist */ } #ifdef freebsd2 if (saveifnet.if_type != IFT_ETHER) { return (0); /* Not an ethernet if */ } #endif /* * the arpcom structure is an extended ifnet structure which * contains the ethernet address. */ #ifndef linux #if !(defined(netbsd1) || defined(bsdi2) || defined(openbsd2)) if (!NETSNMP_KLOOKUP(saveifnetaddr, (char *) &arpcom, sizeof arpcom)) { DEBUGMSGTL(("mibII/interfaces:Interface_Get_Ether_By_Index", "klookup failed\n")); return 0; } #else /* netbsd1 or bsdi2 or openbsd2 */ #if defined(netbsd1) || defined(openbsd2) #define if_addrlist if_addrlist.tqh_first #define ifa_next ifa_list.tqe_next #endif ifaddraddr = (unsigned long) saveifnet.if_addrlist; while (ifaddraddr) { if (!NETSNMP_KLOOKUP(ifaddraddr, (char *) &ifaddr, sizeof ifaddr)) { DEBUGMSGTL(("mibII/interfaces:Interface_Get_Ether_By_Index", "klookup failed\n")); break; } if (!NETSNMP_KLOOKUP(ifaddr.ifa_addr, (char *) &sadl, sizeof sadl)) { DEBUGMSGTL(("mibII/interfaces:Interface_Get_Ether_By_Index", "klookup failed\n")); break; } if (sadl.sdl_family == AF_LINK && (saveifnet.if_type == IFT_ETHER || saveifnet.if_type == IFT_ISO88025 || saveifnet.if_type == IFT_FDDI)) { memcpy(arpcom.ac_enaddr, sadl.sdl_data + sadl.sdl_nlen, sizeof(arpcom.ac_enaddr)); break; } ifaddraddr = (unsigned long) ifaddr.ifa_next; } #endif /* netbsd1 or bsdi2 or openbsd2 */ #else /* linux */ memcpy(arpcom.ac_enaddr, saveifnetaddr->if_hwaddr, 6); #endif if (strncmp("lo", saveName, 2) == 0) { /* * Loopback doesn't have a HW addr, so return 00:00:00:00:00:00 */ memset(EtherAddr, 0, sizeof(arpcom.ac_enaddr)); } else { #if defined(mips) || defined(hpux) || defined(osf4) || defined(osf3) memcpy(EtherAddr, (char *) arpcom.ac_enaddr, sizeof(arpcom.ac_enaddr)); #else memcpy(EtherAddr, (char *) &arpcom.ac_enaddr, sizeof(arpcom.ac_enaddr)); #endif } return (0); /* DONE */ } #endif /* hpux11 */ #else /* solaris2 */ int Interface_Scan_Get_Count(void) { int i, sd; if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) return (0); if (ioctl(sd, SIOCGIFNUM, &i) == -1) { close(sd); return (0); } else { close(sd); return (i); } } int Interface_Index_By_Name(char *Name, int Len) { return (solaris2_if_nametoindex(Name, Len)); } #endif /* solaris2 */ #else /* HAVE_NET_IF_MIB_H */ /* * This code attempts to do the right thing for FreeBSD. Note that * the statistics could be gathered through use of of the * net.route.0.link.iflist.0 sysctl (which we already use to get the * hardware address of the interfaces), rather than using the ifmib * code, but eventually I will implement dot3Stats and we will have to * use the ifmib interface. ifmib is also a much more natural way of * mapping the SNMP MIB onto sysctl(3). */ #include #include #include #include static int header_interfaces(struct variable *, oid *, size_t *, int, size_t *, WriteMethod ** write); static int header_ifEntry(struct variable *, oid *, size_t *, int, size_t *, WriteMethod ** write); static char *physaddrbuf; static int nphysaddrs; struct sockaddr_dl **physaddrs; void init_interfaces_setup(void) { int naddrs, ilen, bit; static int mib[6] = { CTL_NET, PF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 }; char *cp; size_t len; struct rt_msghdr *rtm; struct if_msghdr *ifm; struct ifa_msghdr *ifam; struct sockaddr *sa; DEBUGMSGTL(("mibII:freebsd", "init_interfaces_setup\n")); naddrs = 0; if (physaddrs) free(physaddrs); if (physaddrbuf) free(physaddrbuf); physaddrbuf = 0; physaddrs = 0; nphysaddrs = 0; len = 0; if (sysctl(mib, 6, 0, &len, 0, 0) < 0) { DEBUGMSGTL(("mibII:freebsd", "sysctl 1 < 0\n")); return; } cp = physaddrbuf = malloc(len); if (physaddrbuf == 0) return; if (sysctl(mib, 6, physaddrbuf, &len, 0, 0) < 0) { free(physaddrbuf); physaddrbuf = 0; DEBUGMSGTL(("mibII:freebsd", "sysctl 2 < 0\n")); return; } loop: ilen = len; cp = physaddrbuf; while (ilen > 0) { rtm = (struct rt_msghdr *) cp; if (rtm->rtm_version != RTM_VERSION || rtm->rtm_type != RTM_IFINFO) { DEBUGMSGTL(("mibII:freebsd", "version:%d/%d type:%d/%d\n", rtm->rtm_version, RTM_VERSION, rtm->rtm_type, RTM_IFINFO)); free(physaddrs); physaddrs = 0; free(physaddrbuf); physaddrbuf = 0; } ifm = (struct if_msghdr *) rtm; #if defined(freebsd3) || defined(freebsd4) || defined(freebsd5) if (physaddrs != 0) physaddrs[naddrs] = (void *) (ifm + 1); naddrs++; #endif ilen -= ifm->ifm_msglen; cp += ifm->ifm_msglen; rtm = (struct rt_msghdr *) cp; while (ilen > 0 && rtm->rtm_type == RTM_NEWADDR) { #if defined(freebsd3) || defined(freebsd4) || defined(freebsd5) ilen -= rtm->rtm_msglen; cp += rtm->rtm_msglen; #else int is_alias = 0; ifam = (struct ifa_msghdr *) rtm; ilen -= sizeof(*ifam); cp += sizeof(*ifam); sa = (struct sockaddr *) cp; #define ROUND(x) (((x) + sizeof(long) - 1) & ~sizeof(long)) for (bit = 1; bit && ilen > 0; bit <<= 1) { if (!(ifam->ifam_addrs & bit)) continue; ilen -= ROUND(sa->sa_len); cp += ROUND(sa->sa_len); if (bit == RTA_IFA) { if (physaddrs) #define satosdl(sa) ((struct sockaddr_dl *)(sa)) physaddrs[naddrs++] = satosdl(sa); else naddrs++; } sa = (struct sockaddr *) cp; } #endif rtm = (struct rt_msghdr *) cp; } } DEBUGMSGTL(("mibII:freebsd", "found %d addrs\n", naddrs)); if (physaddrs) { nphysaddrs = naddrs; return; } physaddrs = malloc(naddrs * sizeof(*physaddrs)); if (physaddrs == 0) return; naddrs = 0; goto loop; } static int get_phys_address(int iindex, char **ap, int *len) { int i; int once = 1; do { for (i = 0; i < nphysaddrs; i++) { if (physaddrs[i]->sdl_index == iindex) break; } if (i < nphysaddrs) break; init_interfaces_setup(); } while (once--); DEBUGMSGTL(("mibII:freebsd", "get_phys_address %d/%d\n", i, nphysaddrs)); if (i < nphysaddrs) { *ap = LLADDR(physaddrs[i]); *len = physaddrs[i]->sdl_alen; return 0; } return -1; } int Interface_Scan_Get_Count(void) { static int count_oid[5] = { CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_SYSTEM, IFMIB_IFCOUNT }; size_t len; int count; len = sizeof count; if (sysctl(count_oid, 5, &count, &len, (void *) 0, (size_t) 0) < 0) { DEBUGMSGTL(("mibII:freebsd", "Interface_Scan_Get_Count err\n")); return -1; } DEBUGMSGTL(("mibII:freebsd", "Interface_Scan_Get_Count %d\n", count)); return count; } u_char * var_ifEntry(struct variable * vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { int interface; static int sname[6] = { CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_IFDATA, 0, IFDATA_GENERAL }; static struct ifmibdata ifmd; size_t len; char *cp; conf_if_list *if_ptr = NULL; interface = header_ifEntry(vp, name, length, exact, var_len, write_method); if (interface == MATCH_FAILED) return NULL; sname[4] = interface; len = sizeof ifmd; if (sysctl(sname, 6, &ifmd, &len, 0, 0) < 0) { DEBUGMSGTL(("mibII:freebsd", "var_ifEntry sysctl err\n")); return NULL; } /* * hmmm.. where to get the interface name to check overrides? * * if_ptr = netsnmp_access_interface_entry_overrides_get(Name); */ switch (vp->magic) { case NETSNMP_IFINDEX: long_return = interface; return (u_char *) & long_return; case NETSNMP_IFDESCR: cp = ifmd.ifmd_name; *var_len = strlen(cp); return (u_char *) cp; case NETSNMP_IFTYPE: if (if_ptr) long_return = if_ptr->type; else long_return = ifmd.ifmd_data.ifi_type; return (u_char *) & long_return; case NETSNMP_IFMTU: long_return = (long) ifmd.ifmd_data.ifi_mtu; return (u_char *) & long_return; case NETSNMP_IFSPEED: if (if_ptr) long_return = if_ptr->speed; else long_return = ifmd.ifmd_data.ifi_baudrate; return (u_char *) & long_return; case NETSNMP_IFPHYSADDRESS: { char *cp; if (get_phys_address(interface, &cp, var_len)) return NULL; else return cp; } case NETSNMP_IFADMINSTATUS: long_return = ifmd.ifmd_flags & IFF_UP ? 1 : 2; return (u_char *) & long_return; case NETSNMP_IFOPERSTATUS: long_return = ifmd.ifmd_flags & IFF_RUNNING ? 1 : 2; return (u_char *) & long_return; case NETSNMP_IFLASTCHANGE: if (ifmd.ifmd_data.ifi_lastchange.tv_sec == 0 && ifmd.ifmd_data.ifi_lastchange.tv_usec == 0) { long_return = 0; } else if (ifmd.ifmd_data.ifi_lastchange.tv_sec < starttime.tv_sec) { long_return = 0; } else { long_return = (u_long) ((ifmd.ifmd_data.ifi_lastchange.tv_sec - starttime.tv_sec) * 100 + ((ifmd.ifmd_data.ifi_lastchange.tv_usec - starttime.tv_usec) / 10000)); } return (u_char *) & long_return; case NETSNMP_IFINOCTETS: long_return = (u_long) ifmd.ifmd_data.ifi_ibytes; return (u_char *) & long_return; case NETSNMP_IFINUCASTPKTS: long_return = (u_long) ifmd.ifmd_data.ifi_ipackets; long_return -= (u_long) ifmd.ifmd_data.ifi_imcasts; return (u_char *) & long_return; case NETSNMP_IFINNUCASTPKTS: long_return = (u_long) ifmd.ifmd_data.ifi_imcasts; return (u_char *) & long_return; case NETSNMP_IFINDISCARDS: long_return = (u_long) ifmd.ifmd_data.ifi_iqdrops; return (u_char *) & long_return; case NETSNMP_IFINERRORS: long_return = ifmd.ifmd_data.ifi_ierrors; return (u_char *) & long_return; case NETSNMP_IFINUNKNOWNPROTOS: long_return = (u_long) ifmd.ifmd_data.ifi_noproto; return (u_char *) & long_return; case NETSNMP_IFOUTOCTETS: long_return = (u_long) ifmd.ifmd_data.ifi_obytes; return (u_char *) & long_return; case NETSNMP_IFOUTUCASTPKTS: long_return = (u_long) ifmd.ifmd_data.ifi_opackets; long_return -= (u_long) ifmd.ifmd_data.ifi_omcasts; return (u_char *) & long_return; case NETSNMP_IFOUTNUCASTPKTS: long_return = (u_long) ifmd.ifmd_data.ifi_omcasts; return (u_char *) & long_return; case NETSNMP_IFOUTDISCARDS: long_return = ifmd.ifmd_snd_drops; return (u_char *) & long_return; case NETSNMP_IFOUTERRORS: long_return = ifmd.ifmd_data.ifi_oerrors; return (u_char *) & long_return; case NETSNMP_IFOUTQLEN: long_return = ifmd.ifmd_snd_len; return (u_char *) & long_return; case NETSNMP_IFSPECIFIC: *var_len = nullOidLen; return (u_char *) nullOid; default: DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ifEntry\n", vp->magic)); } return NULL; } #endif /* HAVE_NET_IF_MIB_H */ #endif /* !USE_SYSCTL_IFLIST */ #elif defined(HAVE_IPHLPAPI_H) /* WIN32 cygwin */ #include #ifndef NETSNMP_NO_WRITE_SUPPORT WriteMethod writeIfEntry; #endif /* !NETSNMP_NO_WRITE_SUPPORT */ long admin_status = 0; long oldadmin_status = 0; void Interface_Scan_Init(void) { } static int header_ifEntry(struct variable *vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { #define IFENTRY_NAME_LENGTH 10 oid newname[MAX_OID_LEN]; register int ifIndex; int result, count; DWORD status = NO_ERROR; DWORD dwActualSize = 0; PMIB_IFTABLE pIfTable = NULL; DEBUGMSGTL(("mibII/interfaces", "var_ifEntry: ")); DEBUGMSGOID(("mibII/interfaces", name, *length)); DEBUGMSG(("mibII/interfaces", " %d\n", exact)); memcpy((char *) newname, (char *) vp->name, (int) vp->namelen * sizeof(oid)); /* * find "next" ifIndex */ status = GetIfTable(pIfTable, &dwActualSize, TRUE); if (status == ERROR_INSUFFICIENT_BUFFER) { pIfTable = malloc(dwActualSize); if (pIfTable) GetIfTable(pIfTable, &dwActualSize, TRUE); } count = pIfTable->dwNumEntries; for (ifIndex = 0; ifIndex < count; ifIndex++) { newname[IFENTRY_NAME_LENGTH] = (oid) pIfTable->table[ifIndex].dwIndex; result = snmp_oid_compare(name, *length, newname, (int) vp->namelen + 1); if ((exact && (result == 0)) || (!exact && (result < 0))) break; } if (ifIndex >= count) { DEBUGMSGTL(("mibII/interfaces", "... index out of range\n")); count = MATCH_FAILED; goto out; } memcpy((char *) name, (char *) newname, ((int) vp->namelen + 1) * sizeof(oid)); *length = vp->namelen + 1; *write_method = 0; *var_len = sizeof(long); /* default to 'long' results */ DEBUGMSGTL(("mibII/interfaces", "... get I/F stats ")); DEBUGMSGOID(("mibII/interfaces", name, *length)); DEBUGMSG(("mibII/interfaces", "\n")); count = pIfTable->table[ifIndex].dwIndex; out: free(pIfTable); return count; } u_char * var_interfaces(struct variable * vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { if (header_generic(vp, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; switch (vp->magic) { case NETSNMP_IFNUMBER: netsnmp_assert(sizeof(DWORD) == sizeof(long_return)); GetNumberOfInterfaces((DWORD *) &long_return); return (u_char *) & long_return; default: DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_interfaces\n", vp->magic)); } return NULL; } u_char * var_ifEntry(struct variable * vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { int ifIndex; static MIB_IFROW ifRow; conf_if_list *if_ptr = NULL; ifIndex = header_ifEntry(vp, name, length, exact, var_len, write_method); if (ifIndex == MATCH_FAILED) return NULL; /* * hmmm.. where to get the interface name to check overrides? * * if_ptr = netsnmp_access_interface_entry_overrides_get(Name); */ /* * Get the If Table Row by passing index as argument */ ifRow.dwIndex = ifIndex; if (GetIfEntry(&ifRow) != NO_ERROR) return NULL; switch (vp->magic) { case NETSNMP_IFINDEX: long_return = ifIndex; return (u_char *) & long_return; case NETSNMP_IFDESCR: *var_len = ifRow.dwDescrLen; return (u_char *) ifRow.bDescr; case NETSNMP_IFTYPE: if (if_ptr) long_return = if_ptr->type; else long_return = ifRow.dwType; return (u_char *) & long_return; case NETSNMP_IFMTU: long_return = (long) ifRow.dwMtu; return (u_char *) & long_return; case NETSNMP_IFSPEED: if (if_ptr) long_return = (long) if_ptr->speed; else long_return = (long) ifRow.dwSpeed; return (u_char *) & long_return; case NETSNMP_IFPHYSADDRESS: *var_len = ifRow.dwPhysAddrLen; memcpy(return_buf, ifRow.bPhysAddr, *var_len); return (u_char *) return_buf; case NETSNMP_IFADMINSTATUS: long_return = ifRow.dwAdminStatus; admin_status = long_return; #ifndef NETSNMP_NO_WRITE_SUPPORT *write_method = writeIfEntry; #endif /* !NETSNMP_NO_WRITE_SUPPORT */ return (u_char *) & long_return; case NETSNMP_IFOPERSTATUS: long_return = (MIB_IF_OPER_STATUS_OPERATIONAL == ifRow.dwOperStatus) ? 1 : 2; return (u_char *) & long_return; case NETSNMP_IFLASTCHANGE: long_return = 0 /* XXX not a UNIX epochal time ifRow.dwLastChange */ ; return (u_char *) & long_return; case NETSNMP_IFINOCTETS: long_return = ifRow.dwInOctets; return (u_char *) & long_return; case NETSNMP_IFINUCASTPKTS: long_return = ifRow.dwInUcastPkts; return (u_char *) & long_return; case NETSNMP_IFINNUCASTPKTS: long_return = ifRow.dwInNUcastPkts; return (u_char *) & long_return; case NETSNMP_IFINDISCARDS: long_return = ifRow.dwInDiscards; return (u_char *) & long_return; case NETSNMP_IFINERRORS: long_return = ifRow.dwInErrors; return (u_char *) & long_return; case NETSNMP_IFINUNKNOWNPROTOS: long_return = ifRow.dwInUnknownProtos; return (u_char *) & long_return; case NETSNMP_IFOUTOCTETS: long_return = ifRow.dwOutOctets; return (u_char *) & long_return; case NETSNMP_IFOUTUCASTPKTS: long_return = ifRow.dwOutUcastPkts; return (u_char *) & long_return; case NETSNMP_IFOUTNUCASTPKTS: long_return = ifRow.dwOutNUcastPkts; return (u_char *) & long_return; case NETSNMP_IFOUTDISCARDS: long_return = ifRow.dwOutDiscards; return (u_char *) & long_return; case NETSNMP_IFOUTERRORS: long_return = ifRow.dwOutErrors; return (u_char *) & long_return; case NETSNMP_IFOUTQLEN: long_return = ifRow.dwOutQLen; return (u_char *) & long_return; case NETSNMP_IFSPECIFIC: *var_len = nullOidLen; return (u_char *) nullOid; default: DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ifEntry\n", vp->magic)); } return NULL; } #ifndef NETSNMP_NO_WRITE_SUPPORT int writeIfEntry(int action, u_char * var_val, u_char var_val_type, size_t var_val_len, u_char * statP, oid * name, size_t name_len) { MIB_IFROW ifEntryRow; if ((char) name[9] != NETSNMP_IFADMINSTATUS) { return SNMP_ERR_NOTWRITABLE; } switch (action) { case RESERVE1: /* Check values for acceptability */ if (var_val_type != ASN_INTEGER) { snmp_log(LOG_ERR, "not integer\n"); return SNMP_ERR_WRONGTYPE; } if (var_val_len > sizeof(int)) { snmp_log(LOG_ERR, "bad length\n"); return SNMP_ERR_WRONGLENGTH; } /* * The dwAdminStatus member can be MIB_IF_ADMIN_STATUS_UP or MIB_IF_ADMIN_STATUS_DOWN */ if (!(((int) (*var_val) == MIB_IF_ADMIN_STATUS_UP) || ((int) (*var_val) == MIB_IF_ADMIN_STATUS_DOWN))) { snmp_log(LOG_ERR, "not supported admin state\n"); return SNMP_ERR_WRONGVALUE; } break; case RESERVE2: /* Allocate memory and similar resources */ break; case ACTION: /* * Save the old value, in case of UNDO */ oldadmin_status = admin_status; admin_status = (int) *var_val; break; case UNDO: /* Reverse the SET action and free resources */ admin_status = oldadmin_status; break; case COMMIT: /* Confirm the SET, performing any irreversible actions, * and free resources */ ifEntryRow.dwIndex = (int) name[10]; ifEntryRow.dwAdminStatus = admin_status; /* * Only UP and DOWN status are supported. Thats why done in COMMIT */ if (SetIfEntry(&ifEntryRow) != NO_ERROR) { snmp_log(LOG_ERR, "Error in writeIfEntry case COMMIT with index: %lu & adminStatus %lu\n", ifEntryRow.dwIndex, ifEntryRow.dwAdminStatus); return SNMP_ERR_COMMITFAILED; } case FREE: /* Free any resources allocated */ /* * No resources have been allocated */ break; } return SNMP_ERR_NOERROR; } /* end of writeIfEntry */ #endif /* !NETSNMP_NO_WRITE_SUPPORT */ #endif /* WIN32 cygwin */