Path: blob/main/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_network_tbl.c
107769 views
/*-1* Copyright (c) 2005-2006 The FreeBSD Project2* All rights reserved.3*4* Author: Victor Cruceru <[email protected]>5*6* Redistribution of this software and documentation and use in source and7* binary forms, with or without modification, are permitted provided that8* the following conditions are met:9*10* 1. Redistributions of source code or documentation must retain the above11* copyright notice, this list of conditions and the following disclaimer.12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND17* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE18* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE19* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE20* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL21* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS22* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)23* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT24* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY25* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF26* SUCH DAMAGE.27*/2829/*30* Host Resources MIB implementation for SNMPd: instrumentation for31* hrNetworkTable32*/3334#include <sys/types.h>35#include <sys/ioctl.h>36#include <sys/socket.h>37#include <sys/sysctl.h>3839#include <net/if.h>40#include <net/if_mib.h>4142#include <assert.h>43#include <ctype.h>44#include <err.h>45#include <errno.h>46#include <ifaddrs.h>47#include <stdarg.h>48#include <stdlib.h>49#include <string.h>50#include <syslog.h>51#include <unistd.h>5253#include "hostres_snmp.h"54#include "hostres_oid.h"55#include "hostres_tree.h"5657#include <bsnmp/snmp_mibII.h>5859/*60* This structure is used to hold a SNMP table entry61* for HOST-RESOURCES-MIB's hrNetworkTable62*/63struct network_entry {64int32_t index;65int32_t ifIndex;66TAILQ_ENTRY(network_entry) link;67#define HR_NETWORK_FOUND 0x00168uint32_t flags;6970};71TAILQ_HEAD(network_tbl, network_entry);7273/* the head of the list with hrNetworkTable's entries */74static struct network_tbl network_tbl = TAILQ_HEAD_INITIALIZER(network_tbl);7576/* last (agent) tick when hrNetworkTable was updated */77static uint64_t network_tick;7879/* maximum number of ticks between updates of network table */80uint32_t network_tbl_refresh = HR_NETWORK_TBL_REFRESH * 100;8182/* Constants */83static const struct asn_oid OIDX_hrDeviceNetwork_c = OIDX_hrDeviceNetwork;8485/**86* Create a new entry into the network table87*/88static struct network_entry *89network_entry_create(const struct device_entry *devEntry)90{91struct network_entry *entry;9293assert(devEntry != NULL);94if (devEntry == NULL)95return (NULL);9697if ((entry = malloc(sizeof(*entry))) == NULL) {98syslog(LOG_WARNING, "%s: %m", __func__);99return (NULL);100}101102memset(entry, 0, sizeof(*entry));103entry->index = devEntry->index;104INSERT_OBJECT_INT(entry, &network_tbl);105106return (entry);107}108109/**110* Delete an entry in the network table111*/112static void113network_entry_delete(struct network_entry* entry)114{115116TAILQ_REMOVE(&network_tbl, entry, link);117free(entry);118}119120/**121* Fetch the interfaces from the mibII module, get their real name from the122* kernel and try to find it in the device table.123*/124static void125network_get_interfaces(void)126{127struct device_entry *dev;128struct network_entry *net;129struct mibif *ifp;130int name[6];131size_t len;132char *dname;133134name[0] = CTL_NET;135name[1] = PF_LINK;136name[2] = NETLINK_GENERIC;137name[3] = IFMIB_IFDATA;138name[5] = IFDATA_DRIVERNAME;139140for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp)) {141HRDBG("%s %s", ifp->name, ifp->descr);142143name[4] = ifp->sysindex;144145/* get the original name */146len = 0;147if (sysctl(name, 6, NULL, &len, 0, 0) < 0) {148syslog(LOG_ERR, "sysctl(net.link.ifdata.%d."149"drivername): %m", ifp->sysindex);150continue;151}152if ((dname = malloc(len)) == NULL) {153syslog(LOG_ERR, "malloc: %m");154continue;155}156if (sysctl(name, 6, dname, &len, 0, 0) < 0) {157syslog(LOG_ERR, "sysctl(net.link.ifdata.%d."158"drivername): %m", ifp->sysindex);159free(dname);160continue;161}162163HRDBG("got device %s (%s)", ifp->name, dname);164165if ((dev = device_find_by_name(dname)) == NULL) {166HRDBG("%s not in hrDeviceTable", dname);167free(dname);168continue;169}170HRDBG("%s found in hrDeviceTable", dname);171172dev->type = &OIDX_hrDeviceNetwork_c;173dev->flags |= HR_DEVICE_IMMUTABLE;174175free(dname);176177/* Then check hrNetworkTable for this device */178TAILQ_FOREACH(net, &network_tbl, link)179if (net->index == dev->index)180break;181182if (net == NULL && (net = network_entry_create(dev)) == NULL)183continue;184185net->flags |= HR_NETWORK_FOUND;186net->ifIndex = ifp->index;187}188189network_tick = this_tick;190}191192/**193* Finalization routine for hrNetworkTable.194* It destroys the lists and frees any allocated heap memory.195*/196void197fini_network_tbl(void)198{199struct network_entry *n1;200201while ((n1 = TAILQ_FIRST(&network_tbl)) != NULL) {202TAILQ_REMOVE(&network_tbl, n1, link);203free(n1);204}205}206207/**208* Get the interface list from mibII only at this point to be sure that209* it is there already.210*/211void212start_network_tbl(void)213{214215mib_refresh_iflist();216network_get_interfaces();217}218219/**220* Refresh the table.221*/222static void223refresh_network_tbl(void)224{225struct network_entry *entry, *entry_tmp;226227if (this_tick - network_tick < network_tbl_refresh) {228HRDBG("no refresh needed");229return;230}231232/* mark each entry as missing */233TAILQ_FOREACH(entry, &network_tbl, link)234entry->flags &= ~HR_NETWORK_FOUND;235236network_get_interfaces();237238/*239* Purge items that disappeared240*/241TAILQ_FOREACH_SAFE(entry, &network_tbl, link, entry_tmp) {242if (!(entry->flags & HR_NETWORK_FOUND))243network_entry_delete(entry);244}245246HRDBG("refresh DONE");247}248249/*250* This is the implementation for a generated (by our SNMP tool)251* function prototype, see hostres_tree.h252* It handles the SNMP operations for hrNetworkTable253*/254int255op_hrNetworkTable(struct snmp_context *ctx __unused, struct snmp_value *value,256u_int sub, u_int iidx __unused, enum snmp_op curr_op)257{258struct network_entry *entry;259260refresh_network_tbl();261262switch (curr_op) {263264case SNMP_OP_GETNEXT:265if ((entry = NEXT_OBJECT_INT(&network_tbl,266&value->var, sub)) == NULL)267return (SNMP_ERR_NOSUCHNAME);268value->var.len = sub + 1;269value->var.subs[sub] = entry->index;270goto get;271272case SNMP_OP_GET:273if ((entry = FIND_OBJECT_INT(&network_tbl,274&value->var, sub)) == NULL)275return (SNMP_ERR_NOSUCHNAME);276goto get;277278case SNMP_OP_SET:279if ((entry = FIND_OBJECT_INT(&network_tbl,280&value->var, sub)) == NULL)281return (SNMP_ERR_NO_CREATION);282return (SNMP_ERR_NOT_WRITEABLE);283284case SNMP_OP_ROLLBACK:285case SNMP_OP_COMMIT:286abort();287}288abort();289290get:291switch (value->var.subs[sub - 1]) {292293case LEAF_hrNetworkIfIndex:294value->v.integer = entry->ifIndex;295return (SNMP_ERR_NOERROR);296297}298abort();299}300301302