/* * Interface MIB architecture support * * $Id: interface_ioctl.c,v 1.8 2004/10/17 01:52:52 rstory Exp $ */ #include #include #include "mibII/mibII_common.h" #include "if-mib/ifTable/ifTable_constants.h" #include #include #include "if-mib/data_access/interface.h" #ifdef HAVE_NET_IF_H #include #endif #ifdef HAVE_NET_IF_ARP_H #include #endif #ifdef HAVE_SYS_IOCTL_H #include #endif /** * ioctl wrapper * * @param fd : socket fd to use w/ioctl, or -1 to open/close one * @param ifentry : ifentry to update * * @retval 0 : success * @retval -1 : invalid parameters * @retval -2 : couldn't create socket * @retval -3 : ioctl call failed */ static int _ioctl_get(int fd, int which, struct ifreq *ifrq, const char* name) { int ourfd = -1, rc = 0; DEBUGMSGTL(("verbose:access:interface:ioctl", "ioctl %d for %s\n", which, name)); /* * sanity checks */ if(NULL == name) { snmp_log(LOG_ERR, "invalid ifentry\n"); return -1; } /* * create socket for ioctls */ if(fd < 0) { fd = ourfd = socket(AF_INET, SOCK_DGRAM, 0); if(ourfd < 0) { snmp_log(LOG_ERR,"couldn't create socket\n"); return -2; } } strncpy(ifrq->ifr_name, name, sizeof(ifrq->ifr_name)); ifrq->ifr_name[ sizeof(ifrq->ifr_name)-1 ] = 0; rc = ioctl(fd, which, ifrq); if (rc < 0) { snmp_log(LOG_ERR,"ioctl %d returned %d\n", which, rc); rc = -3; } if(ourfd >= 0) close(ourfd); return rc; } #ifdef SIOCGIFHWADDR /** * interface entry physaddr ioctl wrapper * * @param fd : socket fd to use w/ioctl, or -1 to open/close one * @param ifentry : ifentry to update * * @retval 0 : success * @retval -1 : invalid parameters * @retval -2 : couldn't create socket * @retval -3 : ioctl call failed * @retval -4 : malloc error */ int netsnmp_access_interface_ioctl_physaddr_get(int fd, netsnmp_interface_entry *ifentry) { struct ifreq ifrq; int rc = 0; DEBUGMSGTL(("access:interface:ioctl", "physaddr_get\n")); if((NULL != ifentry->paddr) && (ifentry->paddr_len != IFHWADDRLEN)) { SNMP_FREE(ifentry->paddr); } if(NULL == ifentry->paddr) ifentry->paddr = malloc(IFHWADDRLEN); if(NULL == ifentry->paddr) { rc = -4; } else { /* * NOTE: this ioctl does not guarantee 6 bytes of a physaddr. * In particular, a 'sit0' interface only appears to get back * 4 bytes of sa_data. Uncomment this memset, and suddenly * the sit interface will be 0:0:0:0:?:? where ? is whatever was * in the memory before. Not sure if this memset should be done * for every ioctl, as the rest seem to work ok... */ memset(ifrq.ifr_hwaddr.sa_data, (0), IFHWADDRLEN); ifentry->paddr_len = IFHWADDRLEN; rc = _ioctl_get(fd, SIOCGIFHWADDR, &ifrq, ifentry->name); if (rc < 0) { memset(ifentry->paddr, (0), IFHWADDRLEN); rc = -3; /* msg already logged */ } else { memcpy(ifentry->paddr, ifrq.ifr_hwaddr.sa_data, IFHWADDRLEN); /* * arphrd defines vary greatly. ETHER seems to be the only common one */ #ifdef ARPHRD_ETHER switch (ifrq.ifr_hwaddr.sa_family) { case ARPHRD_ETHER: ifentry->type = 6; break; #if defined(ARPHRD_TUNNEL) || defined(ARPHRD_IPGRE) || defined(ARPHRD_SIT) #ifdef ARPHRD_TUNNEL case ARPHRD_TUNNEL: case ARPHRD_TUNNEL6: #endif #ifdef ARPHRD_IPGRE case ARPHRD_IPGRE: #endif #ifdef ARPHRD_SIT case ARPHRD_SIT: #endif ifentry->type = 131; break; /* tunnel */ #endif #ifdef ARPHRD_SLIP case ARPHRD_SLIP: case ARPHRD_CSLIP: case ARPHRD_SLIP6: case ARPHRD_CSLIP6: ifentry->type = 28; break; /* slip */ #endif #ifdef ARPHRD_PPP case ARPHRD_PPP: ifentry->type = 23; break; /* ppp */ #endif #ifdef ARPHRD_LOOPBACK case ARPHRD_LOOPBACK: ifentry->type = 24; break; /* softwareLoopback */ #endif #ifdef ARPHRD_FDDI case ARPHRD_FDDI: ifentry->type = 15; break; #endif #ifdef ARPHRD_ARCNET case ARPHRD_ARCNET: ifentry->type = 35; break; #endif #ifdef ARPHRD_LOCALTLK case ARPHRD_LOCALTLK: ifentry->type = 42; break; #endif #ifdef ARPHRD_HIPPI case ARPHRD_HIPPI: ifentry->type = 47; break; #endif #ifdef ARPHRD_ATM case ARPHRD_ATM: ifentry->type = 37; break; #endif /* * XXX: more if_arp.h:ARPHRD_xxx to IANAifType mappings... */ default: DEBUGMSGTL(("access:interface:ioctl", "unknown entry type %d\n", ifrq.ifr_hwaddr.sa_family)); } /* switch */ #endif /* ARPHRD_LOOPBACK */ } } return rc; } #endif /* SIOCGIFHWADDR */ #ifdef SIOCGIFFLAGS /** * interface entry flags ioctl wrapper * * @param fd : socket fd to use w/ioctl, or -1 to open/close one * @param ifentry : ifentry to update * * @retval 0 : success * @retval -1 : invalid parameters * @retval -2 : couldn't create socket * @retval -3 : ioctl call failed */ int netsnmp_access_interface_ioctl_flags_get(int fd, netsnmp_interface_entry *ifentry) { struct ifreq ifrq; int rc = 0; DEBUGMSGTL(("access:interface:ioctl", "flags_get\n")); rc = _ioctl_get(fd, SIOCGIFFLAGS, &ifrq, ifentry->name); if (rc < 0) { ifentry->ns_flags &= ~NETSNMP_INTERFACE_FLAGS_HAS_IF_FLAGS; return rc; /* msg already logged */ } else { ifentry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_IF_FLAGS; ifentry->os_flags = ifrq.ifr_flags; /* * ifOperStatus description: * If ifAdminStatus is down(2) then ifOperStatus should be down(2). */ if(ifentry->os_flags & IFF_UP) { ifentry->admin_status = IFADMINSTATUS_UP; if(ifentry->os_flags & IFF_RUNNING) ifentry->oper_status = IFOPERSTATUS_UP; else ifentry->oper_status = IFOPERSTATUS_DOWN; } else { ifentry->admin_status = IFADMINSTATUS_DOWN; ifentry->oper_status = IFOPERSTATUS_DOWN; } } return rc; } /** * interface entry flags ioctl wrapper * * @param fd : socket fd to use w/ioctl, or -1 to open/close one * @param ifentry : ifentry to update * * @retval 0 : success * @retval -1 : invalid parameters * @retval -2 : couldn't create socket * @retval -3 : ioctl get call failed * @retval -4 : ioctl set call failed */ int netsnmp_access_interface_ioctl_flags_set(int fd, netsnmp_interface_entry *ifentry, unsigned int flags, int and_complement) { struct ifreq ifrq; int ourfd = -1, rc = 0; DEBUGMSGTL(("access:interface:ioctl", "flags_set\n")); /* * sanity checks */ if((NULL == ifentry) || (NULL == ifentry->name)) { snmp_log(LOG_ERR, "invalid ifentry\n"); return -1; } /* * create socket for ioctls */ if(fd < 0) { fd = ourfd = socket(AF_INET, SOCK_DGRAM, 0); if(ourfd < 0) { snmp_log(LOG_ERR,"couldn't create socket\n"); return -2; } } strncpy(ifrq.ifr_name, ifentry->name, sizeof(ifrq.ifr_name)); ifrq.ifr_name[ sizeof(ifrq.ifr_name)-1 ] = 0; rc = ioctl(fd, SIOCGIFFLAGS, &ifrq); if(rc < 0) { snmp_log(LOG_ERR,"error getting flags\n"); close(fd); return -3; } if(0 == and_complement) ifrq.ifr_flags |= flags; else ifrq.ifr_flags &= ~flags; rc = ioctl(fd, SIOCSIFFLAGS, &ifrq); if(rc < 0) { close(fd); snmp_log(LOG_ERR,"error setting flags\n"); ifentry->os_flags = 0; return -4; } if(ourfd >= 0) close(ourfd); ifentry->os_flags = ifrq.ifr_flags; return 0; } #endif /* SIOCGIFFLAGS */ #ifdef SIOCGIFMTU /** * interface entry mtu ioctl wrapper * * @param fd : socket fd to use w/ioctl, or -1 to open/close one * @param ifentry : ifentry to update * * @retval 0 : success * @retval -1 : invalid parameters * @retval -2 : couldn't create socket * @retval -3 : ioctl call failed */ int netsnmp_access_interface_ioctl_mtu_get(int fd, netsnmp_interface_entry *ifentry) { struct ifreq ifrq; int rc = 0; DEBUGMSGTL(("access:interface:ioctl", "mtu_get\n")); rc = _ioctl_get(fd, SIOCGIFMTU, &ifrq, ifentry->name); if (rc < 0) { ifentry->mtu = 0; return rc; /* msg already logged */ } else { ifentry->mtu = ifrq.ifr_mtu; } return rc; } #endif /* SIOCGIFMTU */ /** * interface entry ifIndex ioctl wrapper * * @param fd : socket fd to use w/ioctl, or -1 to open/close one * @param ifentry : ifentry to update * * @retval 0 : not found * @retval !0 : ifIndex */ oid netsnmp_access_interface_ioctl_ifindex_get(int fd, const char *name) { #ifndef SIOCGIFINDEX return 0; #else struct ifreq ifrq; int rc = 0; DEBUGMSGTL(("access:interface:ioctl", "mtu_get\n")); rc = _ioctl_get(fd, SIOCGIFINDEX, &ifrq, name); if (rc < 0) return 0; return ifrq.ifr_ifindex; #endif /* SIOCGIFINDEX */ }