summaryrefslogtreecommitdiff
path: root/agent/mibgroup/tunnel/tunnel.c
diff options
context:
space:
mode:
Diffstat (limited to 'agent/mibgroup/tunnel/tunnel.c')
-rw-r--r--agent/mibgroup/tunnel/tunnel.c1001
1 files changed, 1001 insertions, 0 deletions
diff --git a/agent/mibgroup/tunnel/tunnel.c b/agent/mibgroup/tunnel/tunnel.c
new file mode 100644
index 0000000..f9649ef
--- /dev/null
+++ b/agent/mibgroup/tunnel/tunnel.c
@@ -0,0 +1,1001 @@
+/*
+ * tunnel.c --
+ *
+ * An implementation of the TUNNEL-MIB for the UCD-SNMP 4.2
+ * agent running on Linux 2.2.x.
+ *
+ * Copyright (c) 2000 Frank Strauss <strauss@ibr.cs.tu-bs.de>
+ *
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of the author and CMU and
+ * The Regents of the University of California not be used in advertising
+ * or publicity pertaining to distribution of the software without
+ * specific written permission.
+ *
+ * THE AUTHOR AND CMU AND THE REGENTS OF THE UNIVERSITY OF CALIFORNIA
+ * DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * THE AUTHOR OR CMU OR THE REGENTS OF THE UNIVERSITY OF CALIFORNIA BE
+ * LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
+ * DAMAGES WHATSOEVER RESULTING FROM THE LOSS OF USE, DATA OR PROFITS,
+ * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ *
+ */
+
+/*
+ * NOTE: This TUNNEL-MIB implementation
+ *
+ * (a) DOES NOT implement write access on the tunnelConfigTable,
+ * i.e. no new tunnels can be created and no existing tunnels
+ * can be removed through SET operations.
+ *
+ * (b) DOES implement write access on some tunnelIfTable objects
+ * to allow reconfiguring established tunnels. This violates
+ * RFC 2667! However, the author thinks it makes sense. ;-)
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <linux/if.h>
+#include <linux/ip.h>
+#include <linux/sockios.h>
+#include <linux/if_tunnel.h>
+#include <linux/if_arp.h>
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#include <net-snmp/agent/sysORTable.h>
+
+#include "tunnel.h"
+
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif
+
+
+
+#ifdef USING_IF_MIB_IFTABLE_IFTABLE_MODULE
+#include "if-mib/ifTable/ifTable.h"
+#include "if-mib/ifTable/ifTable_defs.h"
+#else
+/*
+ * This is used, because the TUNNEL-MIB augments ifTable.
+ */
+extern unsigned char *var_ifEntry(struct variable *,
+ oid *, size_t *,
+ int, size_t *, WriteMethod **);
+#endif
+
+
+/*
+ * tunnel_variables_oid:
+ * this is the top level oid that we want to register under. This
+ * is essentially a prefix, with the suffix appearing in the
+ * variable below.
+ */
+oid tunnel_variables_oid[] =
+ { 1, 3, 6, 1, 2, 1, 10, 131, 1, 1 };
+const int tunnel_len = 10;
+
+oid tunnel_ifEntry_oid[] =
+ { 1, 3, 6, 1, 2, 1, 10, 131, 1, 1, 1, 1 };
+const int tunnel_ifEntry_len = 12;
+
+oid tunnel_configEntry_oid[] =
+ { 1, 3, 6, 1, 2, 1, 10, 131, 1, 1, 2, 1 };
+const int tunnel_configEntry_len = 12;
+
+
+
+struct tunnel {
+ oid ifindex;
+ int id;
+ char *ifname;
+ int active;
+ unsigned long local;
+ unsigned long remote;
+ int encaps;
+ int hoplimit;
+ int security;
+ int tos;
+ oid config_name[MAX_OID_LEN];
+ size_t config_length;
+ struct tunnel *next;
+};
+
+
+
+/*
+ * variable4 tunnel_variables:
+ * this variable defines function callbacks and type return information
+ * for the tunnel mib section
+ */
+
+struct variable4 tunnel_variables[] = {
+ /*
+ * magic number , variable type , ro/rw , callback fn , L, oidsuffix
+ */
+#define LOCALADDRESS 1
+ {LOCALADDRESS, ASN_IPADDRESS, NETSNMP_OLDAPI_RWRITE,
+ var_tunnelIfEntry, 3, {1, 1, 1}},
+#define REMOTEADDRESS 2
+ {REMOTEADDRESS, ASN_IPADDRESS, NETSNMP_OLDAPI_RWRITE,
+ var_tunnelIfEntry, 3, {1, 1, 2}},
+#define ENCAPSMETHOD 3
+ {ENCAPSMETHOD, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
+ var_tunnelIfEntry, 3, {1, 1, 3}},
+#define HOPLIMIT 4
+ {HOPLIMIT, ASN_INTEGER, NETSNMP_OLDAPI_RWRITE,
+ var_tunnelIfEntry, 3, {1, 1, 4}},
+#define SECURITY 5
+ {SECURITY, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
+ var_tunnelIfEntry, 3, {1, 1, 5}},
+#define TOS 6
+ {TOS, ASN_INTEGER, NETSNMP_OLDAPI_RWRITE,
+ var_tunnelIfEntry, 3, {1, 1, 6}},
+
+#define IFINDEX 7
+ {IFINDEX, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
+ var_tunnelConfigEntry, 3, {2, 1, 5}},
+#define ROWSTATUS 8
+ {ROWSTATUS, ASN_INTEGER, NETSNMP_OLDAPI_RWRITE,
+ var_tunnelConfigEntry, 3, {2, 1, 6}},
+};
+
+
+
+static oid sysORTable_reg[] = { 1, 3, 6, 1, 2, 1, 10, 131 };
+
+static struct tunnel *tunnels;
+
+
+
+void
+deinit_tunnel(void)
+{
+ UNREGISTER_SYSOR_ENTRY(sysORTable_reg);
+}
+
+
+
+int
+term_tunnel(int majorID, int minorID, void *serverarg, void *clientarg)
+{
+ deinit_tunnel();
+ return 0;
+}
+
+
+
+void
+init_tunnel(void)
+{
+ REGISTER_SYSOR_ENTRY(sysORTable_reg,
+ "RFC 2667 TUNNEL-MIB implementation for "
+ "Linux 2.2.x kernels.");
+
+ /*
+ * register ourselves with the agent to handle our mib tree
+ */
+ REGISTER_MIB("tunnel", tunnel_variables, variable4,
+ tunnel_variables_oid);
+
+ snmp_register_callback(SNMP_CALLBACK_LIBRARY,
+ SNMP_CALLBACK_SHUTDOWN, term_tunnel, NULL);
+
+ tunnels = NULL;
+}
+
+
+
+static int
+getType(int index)
+{
+#ifndef USING_IF_MIB_IFTABLE_IFTABLE_MODULE
+ oid name[MAX_OID_LEN] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 3 };
+ size_t length = 10;
+ struct variable ifType_variable =
+ { 3, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
+ var_ifEntry, 10, {1, 3, 6, 1, 2, 1, 2, 2, 1, 3}
+ };
+ unsigned char *p;
+ size_t var_len;
+ WriteMethod *write_method;
+
+ name[length] = index;
+ length++;
+
+ p = var_ifEntry(&ifType_variable,
+ name, &length,
+ 1 /* exact */ , &var_len, &write_method);
+ if (!p)
+ return 0;
+
+ return *(int *) p;
+#else
+ ifTable_mib_index imi;
+ ifTable_rowreq_ctx *rr;
+
+ imi.ifIndex = index;
+ rr = ifTable_row_find_by_mib_index(&imi);
+ if (NULL == rr)
+ return 0;
+
+ return rr->data.ifType;
+#endif
+}
+
+
+
+static const char *
+getName(int index)
+{
+#ifndef USING_IF_MIB_IFTABLE_IFTABLE_MODULE
+ oid name[MAX_OID_LEN] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 2 };
+ size_t length = 10;
+ struct variable ifName_variable =
+ { 2, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
+ var_ifEntry, 10, {1, 3, 6, 1, 2, 1, 2, 2, 1, 2}
+ };
+ unsigned char *p;
+ size_t var_len;
+ WriteMethod *write_method;
+
+ name[length] = index;
+ length++;
+
+ p = var_ifEntry(&ifName_variable,
+ name, &length,
+ 1 /* exact */ , &var_len, &write_method);
+ if (!p)
+ return NULL;
+
+ return p;
+#else
+ return netsnmp_access_interface_name_find(index);
+#endif
+}
+
+
+
+static struct ip_tunnel_parm *
+getTunnelParm(char *ifname)
+{
+ struct ifreq ifrq;
+ int fd;
+ static struct ip_tunnel_parm parm;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ return NULL;
+ }
+
+ memset(&parm, 0, sizeof(struct ip_tunnel_parm));
+ strcpy(ifrq.ifr_name, ifname);
+ ifrq.ifr_ifru.ifru_data = (void *) &parm;
+ if (ioctl(fd, SIOCGETTUNNEL, &ifrq) < 0) {
+ /*
+ * try again with the last char of the device name cut off.
+ * it might have been a zero digit appended by the agent.
+ */
+ ifrq.ifr_name[strlen(ifrq.ifr_name) - 1] = 0;
+ if (ioctl(fd, SIOCGETTUNNEL, &ifrq) < 0) {
+ close(fd);
+ return NULL;
+ }
+ ifname[strlen(ifname) - 1] = 0;
+ }
+
+ close(fd);
+
+ return &parm;
+}
+
+
+
+int
+setTunnelParm(char *ifname, struct ip_tunnel_parm *parm)
+{
+ struct ifreq ifrq;
+ int fd;
+ int err;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ return -1;
+ }
+
+ strcpy(ifrq.ifr_name, ifname);
+ ifrq.ifr_ifru.ifru_data = (void *) parm;
+ err = ioctl(fd, SIOCCHGTUNNEL, &ifrq);
+ close(fd);
+
+ return err;
+}
+
+
+
+/*
+ * update a struct tunnel. its index and ifname elements have to be set.
+ */
+static struct tunnel *
+updateTunnel(struct tunnel *tunnel)
+{
+ struct ip_tunnel_parm *parm;
+ int fd;
+ struct ifreq ifrq;
+
+ /*
+ * NOTE: getTunnelParm() may adjust the passed ifname.
+ */
+ parm = getTunnelParm(tunnel->ifname);
+ if (!parm) {
+ DEBUGMSGTL(("tunnel",
+ "updateTunnel(): getTunnelParm(\"%s\") returned NULL\n",
+ tunnel->ifname));
+ tunnel->active = 0;
+ return NULL;
+ }
+
+ tunnel->active = 1;
+
+ tunnel->local = parm->iph.saddr;
+ tunnel->remote = parm->iph.daddr;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ DEBUGMSGTL(("snmpd", "socket open failure in updateTunnels()\n"));
+ return NULL;
+ } 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. We don't use sa_data here, or we'd
+ * need to memset it to 0 before the ioct.
+ */
+ strcpy(ifrq.ifr_name, tunnel->ifname);
+ if (ioctl(fd, SIOCGIFHWADDR, &ifrq) == 0)
+ switch (ifrq.ifr_hwaddr.sa_family) {
+ case ARPHRD_TUNNEL:
+ tunnel->encaps = 2;
+ break;; /* direct */
+ case ARPHRD_TUNNEL6:
+ tunnel->encaps = 2;
+ break;; /* direct */
+ case ARPHRD_IPGRE:
+ tunnel->encaps = 3;
+ break;; /* gre */
+ case ARPHRD_SIT:
+ tunnel->encaps = 2;
+ break;; /* direct */
+ default:
+ tunnel->encaps = 1; /* other */
+ }
+ close(fd);
+ }
+
+ tunnel->hoplimit = parm->iph.ttl;
+ tunnel->security = 1;
+ tunnel->tos = (parm->iph.tos & 1) ? -1 : parm->iph.tos;
+ /*
+ * XXX: adjust tos mapping (kernel <-> TUNNEL-MIB::tunnelIfTOS)
+ */
+
+ return tunnel;
+}
+
+
+
+static void
+updateTunnels(void)
+{
+ static int max_index = 1;
+ static struct tunnel *last_tunnel = NULL;
+ struct tunnel *tunnel;
+ const char *ifname;
+ int type;
+
+ /*
+ * uptime the tunnels we have so far
+ */
+ for (tunnel = tunnels; tunnel; tunnel = tunnel->next) {
+ DEBUGMSG(("tunnel",
+ "updateTunnels(): updating %s (index=%" NETSNMP_PRIo "u)\n",
+ tunnel->ifname, tunnel->ifindex));
+ updateTunnel(tunnel);
+ }
+
+ /*
+ * look for new tunnels
+ */
+ for (; max_index < 256; max_index++) {
+ DEBUGMSG(("tunnel",
+ "updateTunnels(): looking for new index=%d\n",
+ max_index));
+ type = getType(max_index);
+ if (type == 131) {
+ tunnel = (struct tunnel *) malloc(sizeof(struct tunnel));
+ if (!tunnel)
+ continue;
+
+ tunnel->ifindex = max_index;
+ tunnel->id = 1;
+
+ ifname = getName(max_index);
+ if (!ifname) {
+ free(tunnel);
+ continue;
+ }
+
+ tunnel->ifname = strdup(ifname);
+ if (!tunnel->ifname) {
+ free(tunnel);
+ continue;
+ }
+
+ if (!updateTunnel(tunnel)) {
+ free(tunnel);
+ continue;
+ }
+
+ if (last_tunnel)
+ last_tunnel->next = tunnel;
+ if (!tunnels)
+ tunnels = last_tunnel = tunnel;
+ tunnel->next = NULL;
+ last_tunnel = tunnel;
+
+ DEBUGMSG(("tunnel",
+ "updateTunnels(): added %s (index=%" NETSNMP_PRIo
+ "u state=%d)\n",
+ tunnel->ifname, tunnel->ifindex, tunnel->active));
+ }
+ if (type == 0)
+ break;
+ }
+}
+
+
+
+static struct tunnel *
+getTunnelByIfIndex(int index)
+{
+ struct tunnel *tunnel;
+
+ DEBUGMSG(("tunnel", "getTunnelByIfIndex(%d): ", index));
+
+ for (tunnel = tunnels; tunnel; tunnel = tunnel->next) {
+ if (tunnel->ifindex == index) {
+ if (!tunnel->active)
+ break;
+ DEBUGMSG(("tunnel", "%s (index=%" NETSNMP_PRIo "u)\n",
+ tunnel->ifname, tunnel->ifindex));
+ return tunnel;
+ }
+ }
+ DEBUGMSG(("tunnel", "NONE\n"));
+ return NULL;
+}
+
+
+
+static struct tunnel *
+getNextTunnelByIfIndex(int index)
+{
+ struct tunnel *tunnel;
+
+ DEBUGMSG(("tunnel", "getNextTunnelByIfIndex(%d): ", index));
+
+ for (tunnel = tunnels; tunnel; tunnel = tunnel->next) {
+ if (tunnel->ifindex > index) {
+ if (!tunnel->active)
+ continue;
+ DEBUGMSG(("tunnel", "%s (index=%" NETSNMP_PRIo "u)\n",
+ tunnel->ifname, tunnel->ifindex));
+ return tunnel;
+ }
+ }
+ DEBUGMSG(("tunnel", "NONE\n"));
+ return NULL;
+}
+
+
+
+static void
+fillConfigOid(oid * name, struct tunnel *tunnel)
+{
+ name[0] = ((unsigned char *) &tunnel->local)[0];
+ name[1] = ((unsigned char *) &tunnel->local)[1];
+ name[2] = ((unsigned char *) &tunnel->local)[2];
+ name[3] = ((unsigned char *) &tunnel->local)[3];
+ name[4] = ((unsigned char *) &tunnel->remote)[0];
+ name[5] = ((unsigned char *) &tunnel->remote)[1];
+ name[6] = ((unsigned char *) &tunnel->remote)[2];
+ name[7] = ((unsigned char *) &tunnel->remote)[3];
+ name[8] = tunnel->encaps;
+ name[9] = tunnel->id;
+ DEBUGMSGOID(("tunnel", name, 10));
+}
+
+
+
+static struct tunnel *
+getTunnelByConfigOid(oid * name, size_t * length)
+{
+ struct tunnel *tunnel;
+ oid tname[4 + 4 + 1 + 1];
+
+ DEBUGMSG(("tunnel", "getTunnelByConfigOid(): "));
+
+ for (tunnel = tunnels; tunnel; tunnel = tunnel->next) {
+ fillConfigOid(tname, tunnel);
+ if (!snmp_oid_compare(tname, 4 + 4 + 1 + 1,
+ &name[tunnel_len + 3],
+ (*length) - tunnel_len - 3)) {
+ if (!tunnel->active)
+ break;
+ DEBUGMSG(("tunnel", "%s (index=%" NETSNMP_PRIo "u)\n",
+ tunnel->ifname, tunnel->ifindex));
+ return tunnel;
+ }
+ }
+ DEBUGMSG(("tunnel", "NONE\n"));
+ return NULL;
+}
+
+
+
+static struct tunnel *
+getNextTunnelByConfigOid(oid * name, size_t * length)
+{
+ struct tunnel *tunnel, *last_tunnel;
+ oid tname[10], last_tname[10];
+
+ DEBUGMSG(("tunnel", "getNextTunnelByConfigOid("));
+ DEBUGMSGOID(("tunnel", name, *length));
+ DEBUGMSG(("tunnel", "): "));
+
+ last_tunnel = NULL;
+ for (tunnel = tunnels; tunnel; tunnel = tunnel->next) {
+ if (!tunnel->active)
+ continue;
+ fillConfigOid(tname, tunnel);
+ if (snmp_oid_compare(tname, 10,
+ &name[tunnel_len + 3],
+ (*length) - tunnel_len - 3) > 0) {
+ if (!last_tunnel) {
+ last_tunnel = tunnel;
+ memcpy((char *) last_tname, (char *) tname,
+ 10 * sizeof(oid));
+ } else {
+ if (snmp_oid_compare(tname, 10, last_tname, 10) < 0) {
+ last_tunnel = tunnel;
+ memcpy((char *) last_tname, (char *) tname,
+ 10 * sizeof(oid));
+ }
+ }
+ }
+ }
+
+ if (last_tunnel) {
+ DEBUGMSG(("tunnel", "%s (index=%" NETSNMP_PRIo "u)\n",
+ last_tunnel->ifname, last_tunnel->ifindex));
+ } else {
+ DEBUGMSG(("tunnel", "NONE\n"));
+ }
+
+ return last_tunnel;
+}
+
+
+
+static int
+writeLocalAddress(int action, unsigned char *var_val,
+ unsigned char var_val_type, size_t var_val_len,
+ unsigned char *statP, oid * name, size_t name_len)
+{
+ static struct tunnel *tunnel;
+ struct ip_tunnel_parm *parm;
+
+ switch (action) {
+ case RESERVE1:
+ if (var_val_type != ASN_IPADDRESS) {
+ return SNMP_ERR_WRONGTYPE;
+ }
+ if (var_val_len != 4) {
+ return SNMP_ERR_WRONGLENGTH;
+ }
+ case RESERVE2:
+ tunnel = getTunnelByIfIndex((int) name[name_len - 1]);
+ if (!tunnel) {
+ return SNMP_ERR_NOSUCHNAME;
+ }
+ case FREE:
+ break;
+ case ACTION:
+ break;
+ case UNDO:
+ break;
+ case COMMIT:
+ if (!tunnel) {
+ return SNMP_ERR_NOSUCHNAME;
+ }
+ parm = getTunnelParm(tunnel->ifname);
+ if (!parm) {
+ return SNMP_ERR_NOSUCHNAME;
+ }
+ parm->iph.saddr = *(unsigned long *) var_val;
+ setTunnelParm(tunnel->ifname, parm);
+ break;
+ }
+
+ return SNMP_ERR_NOERROR;
+}
+
+
+
+static int
+writeRemoteAddress(int action, unsigned char *var_val,
+ unsigned char var_val_type, size_t var_val_len,
+ unsigned char *statP, oid * name, size_t name_len)
+{
+ static struct tunnel *tunnel;
+ struct ip_tunnel_parm *parm;
+
+ switch (action) {
+ case RESERVE1:
+ if (var_val_type != ASN_IPADDRESS) {
+ return SNMP_ERR_WRONGTYPE;
+ }
+ if (var_val_len != 4) {
+ return SNMP_ERR_WRONGLENGTH;
+ }
+ case RESERVE2:
+ tunnel = getTunnelByIfIndex((int) name[name_len - 1]);
+ if (!tunnel) {
+ return SNMP_ERR_NOSUCHNAME;
+ }
+ case FREE:
+ break;
+ case ACTION:
+ break;
+ case UNDO:
+ break;
+ case COMMIT:
+ if (!tunnel) {
+ return SNMP_ERR_NOSUCHNAME;
+ }
+ parm = getTunnelParm(tunnel->ifname);
+ if (!parm) {
+ return SNMP_ERR_NOSUCHNAME;
+ }
+ parm->iph.daddr = *(unsigned long *) var_val;
+ setTunnelParm(tunnel->ifname, parm);
+ break;
+ }
+
+ return SNMP_ERR_NOERROR;
+}
+
+
+
+static int
+writeHopLimit(int action, unsigned char *var_val,
+ unsigned char var_val_type, size_t var_val_len,
+ unsigned char *statP, oid * name, size_t name_len)
+{
+ static struct tunnel *tunnel;
+ struct ip_tunnel_parm *parm;
+
+ switch (action) {
+ case RESERVE1:
+ if (var_val_type != ASN_INTEGER) {
+ return SNMP_ERR_WRONGTYPE;
+ }
+ if (var_val_len > sizeof(long)) {
+ return SNMP_ERR_WRONGLENGTH;
+ }
+ case RESERVE2:
+ tunnel = getTunnelByIfIndex((int) name[name_len - 1]);
+ if (!tunnel) {
+ return SNMP_ERR_NOSUCHNAME;
+ }
+ case FREE:
+ break;
+ case ACTION:
+ break;
+ case UNDO:
+ break;
+ case COMMIT:
+ if (!tunnel) {
+ return SNMP_ERR_NOSUCHNAME;
+ }
+ parm = getTunnelParm(tunnel->ifname);
+ if (!parm) {
+ return SNMP_ERR_NOSUCHNAME;
+ }
+ parm->iph.ttl = *(long *) var_val;
+ setTunnelParm(tunnel->ifname, parm);
+ break;
+ }
+
+ return SNMP_ERR_NOERROR;
+}
+
+
+
+static int
+writeTOS(int action, unsigned char *var_val,
+ unsigned char var_val_type, size_t var_val_len,
+ unsigned char *statP, oid * name, size_t name_len)
+{
+ static struct tunnel *tunnel;
+ struct ip_tunnel_parm *parm;
+
+ switch (action) {
+ case RESERVE1:
+ if (var_val_type != ASN_INTEGER) {
+ return SNMP_ERR_WRONGTYPE;
+ }
+ if (var_val_len > sizeof(long)) {
+ return SNMP_ERR_WRONGLENGTH;
+ }
+ case RESERVE2:
+ tunnel = getTunnelByIfIndex((int) name[name_len - 1]);
+ if (!tunnel) {
+ return SNMP_ERR_NOSUCHNAME;
+ }
+ case FREE:
+ break;
+ case ACTION:
+ break;
+ case UNDO:
+ break;
+ case COMMIT:
+ if (!tunnel) {
+ return SNMP_ERR_NOSUCHNAME;
+ }
+ parm = getTunnelParm(tunnel->ifname);
+ if (!parm) {
+ return SNMP_ERR_NOSUCHNAME;
+ }
+ /*
+ * this does not cover all meaningful values:
+ */
+ parm->iph.tos = (*(long *) var_val == -1) ? 1 : *(long *) var_val;
+ setTunnelParm(tunnel->ifname, parm);
+ break;
+ }
+
+ return SNMP_ERR_NOERROR;
+}
+
+
+
+unsigned char *
+var_tunnelIfEntry(struct variable *vp,
+ oid * name, size_t * length,
+ int exact, size_t * var_len, WriteMethod ** write_method)
+{
+ static unsigned long ret_addr;
+ static long ret_int;
+ struct tunnel *tunnel;
+
+ DEBUGMSGTL(("tunnel", "var_tunnelIfEntry: "));
+ DEBUGMSGOID(("tunnel", name, *length));
+ DEBUGMSG(("tunnel", " %d\n", exact));
+
+ updateTunnels();
+
+ if (exact) {
+ if (*length != tunnel_len + 3 + 1) {
+ return NULL;
+ }
+ tunnel = getTunnelByIfIndex((int) name[*length - 1]);
+ } else {
+ if ((*length) < tunnel_len) {
+ memcpy((char *) name, (char *) tunnel_variables_oid,
+ tunnel_len * sizeof(oid));
+ }
+ if ((*length) < tunnel_len + 1) {
+ name[tunnel_len] = 1;
+ }
+ if ((*length) < tunnel_len + 2) {
+ name[tunnel_len + 1] = 1;
+ }
+ if ((*length) < tunnel_len + 3) {
+ name[tunnel_len + 2] = 1;
+ }
+ if ((*length) < tunnel_len + 4) {
+ name[tunnel_len + 3] = 0;
+ }
+ *length = tunnel_len + 4;
+
+ tunnel = getNextTunnelByIfIndex(name[*length - 1]);
+ if (!tunnel) {
+ /*
+ * end of column, continue with first row of next column
+ */
+ tunnel = tunnels;
+ name[tunnel_len + 2]++;
+ if (name[tunnel_len + 2] > 6) {
+ /*
+ * there is no next column
+ */
+ return NULL;
+ }
+ if (!tunnel) {
+ /*
+ * there is no (next) row
+ */
+ return NULL;
+ }
+ }
+ }
+
+ if (!tunnel) {
+ return NULL;
+ }
+
+ name[*length - 1] = tunnel->ifindex;
+
+ DEBUGMSGTL(("tunnel", "var_tunnelIfEntry: using"));
+ DEBUGMSGOID(("tunnel", name, *length));
+ DEBUGMSG(("tunnel", "\n"));
+
+ switch (name[tunnel_len + 2]) {
+ case 1: /* tunnelIfLocalAddress */
+ ret_addr = tunnel->local;
+ *var_len = 4;
+ vp->type = ASN_IPADDRESS;
+ *write_method = writeLocalAddress;
+ return (u_char *) & ret_addr;
+ case 2: /* tunnelIfRemoteAddress */
+ ret_addr = tunnel->remote;
+ *var_len = 4;
+ vp->type = ASN_IPADDRESS;
+ *write_method = writeRemoteAddress;
+ return (u_char *) & ret_addr;
+ case 3: /* tunnelIfEncapsMethod */
+ ret_int = tunnel->encaps;
+ *var_len = sizeof(ret_int);
+ vp->type = ASN_INTEGER;
+ return (u_char *) & ret_int;
+ case 4: /* tunnelIfHopLimit */
+ ret_int = tunnel->hoplimit;
+ *var_len = sizeof(ret_int);
+ vp->type = ASN_INTEGER;
+ *write_method = writeHopLimit;
+ return (u_char *) & ret_int;
+ case 5: /* tunnelIfSecurity */
+ ret_int = tunnel->security;
+ *var_len = sizeof(ret_int);
+ vp->type = ASN_INTEGER;
+ return (u_char *) & ret_int;
+ case 6: /* tunnelIfTOS */
+ ret_int = tunnel->tos;
+ *var_len = sizeof(ret_int);
+ vp->type = ASN_INTEGER;
+ *write_method = writeTOS;
+ return (u_char *) & ret_int;
+ default:
+ return 0;
+ }
+
+ return NULL;
+}
+
+
+
+unsigned char *
+var_tunnelConfigEntry(struct variable *vp,
+ oid * name, size_t * length,
+ int exact, size_t * var_len,
+ WriteMethod ** write_method)
+{
+ static long ret_int;
+ struct tunnel *tunnel;
+ int i;
+
+ DEBUGMSGTL(("tunnel", "var_tunnelConfigEntry: "));
+ DEBUGMSGOID(("tunnel", name, *length));
+ DEBUGMSG(("tunnel", " %d\n", exact));
+
+ updateTunnels();
+
+ if (exact) {
+ if (*length != tunnel_len + 3 + 4 + 4 + 1 + 1) {
+ return NULL;
+ }
+ tunnel = getTunnelByConfigOid(name, length);
+ } else {
+ if (snmp_oid_compare(name, *length,
+ tunnel_configEntry_oid,
+ tunnel_configEntry_len) < 0) {
+ *length = 0;
+ }
+ if ((*length) < tunnel_len) {
+ memcpy((char *) name, (char *) tunnel_variables_oid,
+ tunnel_len * sizeof(oid));
+ }
+ if ((*length) < tunnel_len + 1) {
+ name[tunnel_len] = 2;
+ }
+ if ((*length) < tunnel_len + 2) {
+ name[tunnel_len + 1] = 1;
+ }
+ if ((*length) < tunnel_len + 3) {
+ name[tunnel_len + 2] = 5;
+ }
+ for (i = MAX(*length, tunnel_len + 3);
+ i < tunnel_len + 3 + 4 + 4 + 1 + 1; i++) {
+ name[i] = 0;
+ }
+ *length = tunnel_len + 3 + 4 + 4 + 1 + 1;
+ tunnel = getNextTunnelByConfigOid(name, length);
+ if (!tunnel) {
+ /*
+ * end of column, continue with first row of next column
+ */
+ tunnel = tunnels;
+ name[tunnel_len + 2]++;
+ if (name[tunnel_len + 2] > 6) {
+ /*
+ * there is no next column
+ */
+ return NULL;
+ }
+ if (!tunnel) {
+ /*
+ * there is no (next) row
+ */
+ return NULL;
+ }
+ }
+ }
+
+ if (!tunnel) {
+ return NULL;
+ }
+
+ fillConfigOid(&name[tunnel_len + 3], tunnel);
+
+ DEBUGMSGTL(("tunnel", "var_tunnelConfigEntry: using "));
+ DEBUGMSGOID(("tunnel", name, *length));
+ DEBUGMSG(("tunnel", "\n"));
+
+ switch (name[tunnel_len + 2]) {
+ case 5: /* tunnelConfigIfIndex */
+ ret_int = tunnel->ifindex;
+ *var_len = sizeof(ret_int);
+ vp->type = ASN_INTEGER;
+ return (u_char *) & ret_int;
+ case 6: /* tunnelConfigStatus */
+ ret_int = 1; /* active */
+ *var_len = sizeof(ret_int);
+ vp->type = ASN_INTEGER;
+ return (u_char *) & ret_int;
+ default:
+ return 0;
+ }
+
+ return NULL;
+}