4 * An implementation of the TUNNEL-MIB for the UCD-SNMP 4.2
5 * agent running on Linux 2.2.x.
7 * Copyright (c) 2000 Frank Strauss <strauss@ibr.cs.tu-bs.de>
11 * Permission to use, copy, modify and distribute this software and its
12 * documentation for any purpose and without fee is hereby granted,
13 * provided that the above copyright notice appears in all copies and
14 * that both that copyright notice and this permission notice appear in
15 * supporting documentation, and that the name of the author and CMU and
16 * The Regents of the University of California not be used in advertising
17 * or publicity pertaining to distribution of the software without
18 * specific written permission.
20 * THE AUTHOR AND CMU AND THE REGENTS OF THE UNIVERSITY OF CALIFORNIA
21 * DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
23 * THE AUTHOR OR CMU OR THE REGENTS OF THE UNIVERSITY OF CALIFORNIA BE
24 * LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
25 * DAMAGES WHATSOEVER RESULTING FROM THE LOSS OF USE, DATA OR PROFITS,
26 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
27 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
33 * NOTE: This TUNNEL-MIB implementation
35 * (a) DOES NOT implement write access on the tunnelConfigTable,
36 * i.e. no new tunnels can be created and no existing tunnels
37 * can be removed through SET operations.
39 * (b) DOES implement write access on some tunnelIfTable objects
40 * to allow reconfiguring established tunnels. This violates
41 * RFC 2667! However, the author thinks it makes sense. ;-)
48 #include <sys/types.h>
49 #include <sys/socket.h>
51 #include <sys/ioctl.h>
53 #include <netinet/in.h>
54 #include <arpa/inet.h>
58 #include <linux/sockios.h>
59 #include <linux/if_tunnel.h>
60 #include <linux/if_arp.h>
62 #include <net-snmp/net-snmp-config.h>
63 #include <net-snmp/net-snmp-includes.h>
64 #include <net-snmp/agent/net-snmp-agent-includes.h>
66 #include "util_funcs.h"
70 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
73 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
79 * This is used, because the TUNNEL-MIB augments ifTable.
81 extern unsigned char *var_ifEntry(struct variable *,
83 int, size_t *, WriteMethod **);
87 * tunnel_variables_oid:
88 * this is the top level oid that we want to register under. This
89 * is essentially a prefix, with the suffix appearing in the
92 oid tunnel_variables_oid[] =
93 { 1, 3, 6, 1, 2, 1, 10, 131, 1, 1 };
94 const int tunnel_len = 10;
96 oid tunnel_ifEntry_oid[] =
97 { 1, 3, 6, 1, 2, 1, 10, 131, 1, 1, 1, 1 };
98 const int tunnel_ifEntry_len = 12;
100 oid tunnel_configEntry_oid[] =
101 { 1, 3, 6, 1, 2, 1, 10, 131, 1, 1, 2, 1 };
102 const int tunnel_configEntry_len = 12;
112 unsigned long remote;
117 oid config_name[MAX_OID_LEN];
118 size_t config_length;
125 * variable4 tunnel_variables:
126 * this variable defines function callbacks and type return information
127 * for the tunnel mib section
130 struct variable4 tunnel_variables[] = {
132 * magic number , variable type , ro/rw , callback fn , L, oidsuffix
134 #define LOCALADDRESS 1
135 {LOCALADDRESS, ASN_IPADDRESS, RWRITE, var_tunnelIfEntry, 3, {1, 1, 1}},
136 #define REMOTEADDRESS 2
137 {REMOTEADDRESS, ASN_IPADDRESS, RWRITE, var_tunnelIfEntry, 3,
139 #define ENCAPSMETHOD 3
140 {ENCAPSMETHOD, ASN_INTEGER, RONLY, var_tunnelIfEntry, 3, {1, 1, 3}},
142 {HOPLIMIT, ASN_INTEGER, RWRITE, var_tunnelIfEntry, 3, {1, 1, 4}},
144 {SECURITY, ASN_INTEGER, RONLY, var_tunnelIfEntry, 3, {1, 1, 5}},
146 {TOS, ASN_INTEGER, RWRITE, var_tunnelIfEntry, 3, {1, 1, 6}},
149 {IFINDEX, ASN_INTEGER, RONLY, var_tunnelConfigEntry, 3, {2, 1, 5}},
151 {ROWSTATUS, ASN_INTEGER, RWRITE, var_tunnelConfigEntry, 3, {2, 1, 6}},
156 extern int register_sysORTable(oid *, size_t, const char *);
157 extern int unregister_sysORTable(oid *, size_t);
159 static oid sysORTable_reg[] = { 1, 3, 6, 1, 2, 1, 10, 131 };
160 static size_t sysORTable_reglen = 8;
162 static struct tunnel *tunnels;
169 unregister_sysORTable(sysORTable_reg, sysORTable_reglen);
175 term_tunnel(int majorID, int minorID, void *serverarg, void *clientarg)
186 register_sysORTable(sysORTable_reg, sysORTable_reglen,
187 "RFC 2667 TUNNEL-MIB implementation for "
188 "Linux 2.2.x kernels.");
190 netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPTYPE, "snmpd");
193 * register ourselves with the agent to handle our mib tree
195 REGISTER_MIB("tunnel", tunnel_variables, variable4,
196 tunnel_variables_oid);
198 snmp_register_callback(SNMP_CALLBACK_LIBRARY,
199 SNMP_CALLBACK_SHUTDOWN, term_tunnel, NULL);
209 oid name[MAX_OID_LEN] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 3 };
211 struct variable ifType_variable =
212 { 3, ASN_INTEGER, RONLY, var_ifEntry, 10,
213 {1, 3, 6, 1, 2, 1, 2, 2, 1, 3}
217 WriteMethod *write_method;
219 name[length] = index;
222 p = var_ifEntry(&ifType_variable,
224 1 /* exact */ , &var_len, &write_method);
236 oid name[MAX_OID_LEN] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 2 };
238 struct variable ifName_variable =
239 { 2, ASN_INTEGER, RONLY, var_ifEntry, 10,
240 {1, 3, 6, 1, 2, 1, 2, 2, 1, 2}
244 WriteMethod *write_method;
246 name[length] = index;
249 p = var_ifEntry(&ifName_variable,
251 1 /* exact */ , &var_len, &write_method);
260 static struct ip_tunnel_parm *
261 getTunnelParm(char *ifname)
265 static struct ip_tunnel_parm parm;
267 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
271 memset(&parm, 0, sizeof(struct ip_tunnel_parm));
272 strcpy(ifrq.ifr_name, ifname);
273 ifrq.ifr_ifru.ifru_data = (void *) &parm;
274 if (ioctl(fd, SIOCGETTUNNEL, &ifrq) < 0) {
276 * try again with the last char of the device name cut off.
277 * it might have been a zero digit appended by the agent.
279 ifrq.ifr_name[strlen(ifrq.ifr_name) - 1] = 0;
280 if (ioctl(fd, SIOCGETTUNNEL, &ifrq) < 0) {
284 ifname[strlen(ifname) - 1] = 0;
295 setTunnelParm(char *ifname, struct ip_tunnel_parm *parm)
301 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
305 strcpy(ifrq.ifr_name, ifname);
306 ifrq.ifr_ifru.ifru_data = (void *) parm;
307 err = ioctl(fd, SIOCCHGTUNNEL, &ifrq);
316 * update a struct tunnel. its index and ifname elements have to be set.
318 static struct tunnel *
319 updateTunnel(struct tunnel *tunnel)
321 struct ip_tunnel_parm *parm;
326 * NOTE: getTunnelParm() may adjust the passed ifname.
328 parm = getTunnelParm(tunnel->ifname);
330 DEBUGMSGTL(("tunnel",
331 "updateTunnel(): getTunnelParm(\"%s\") returned NULL\n",
339 tunnel->local = parm->iph.saddr;
340 tunnel->remote = parm->iph.daddr;
342 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
343 DEBUGMSGTL(("snmpd", "socket open failure in updateTunnels()\n"));
346 strcpy(ifrq.ifr_name, tunnel->ifname);
347 if (ioctl(fd, SIOCGIFHWADDR, &ifrq) == 0)
348 switch (ifrq.ifr_hwaddr.sa_family) {
362 tunnel->encaps = 1; /* other */
367 tunnel->hoplimit = parm->iph.ttl;
368 tunnel->security = 1;
369 tunnel->tos = (parm->iph.tos & 1) ? -1 : parm->iph.tos;
371 * XXX: adjust tos mapping (kernel <-> TUNNEL-MIB::tunnelIfTOS)
382 static int max_index = 1;
383 static struct tunnel *last_tunnel = NULL;
384 struct tunnel *tunnel;
389 * uptime the tunnels we have so far
391 for (tunnel = tunnels; tunnel; tunnel = tunnel->next) {
393 "updateTunnels(): updating %s (index=%d)\n",
394 tunnel->ifname, tunnel->ifindex));
395 updateTunnel(tunnel);
399 * look for new tunnels
401 for (; max_index < 256; max_index++) {
403 "updateTunnels(): looking for new index=%d\n",
405 type = getType(max_index);
407 tunnel = (struct tunnel *) malloc(sizeof(struct tunnel));
411 tunnel->ifindex = max_index;
414 ifname = getName(max_index);
420 tunnel->ifname = strdup(ifname);
421 if (!tunnel->ifname) {
426 if (!updateTunnel(tunnel)) {
432 last_tunnel->next = tunnel;
434 tunnels = last_tunnel = tunnel;
436 last_tunnel = tunnel;
439 "updateTunnels(): added %s (index=%d state=%d)\n",
440 tunnel->ifname, tunnel->ifindex, tunnel->active));
449 static struct tunnel *
450 getTunnelByIfIndex(int index)
452 struct tunnel *tunnel;
454 DEBUGMSG(("tunnel", "getTunnelByIfIndex(%d): ", index));
456 for (tunnel = tunnels; tunnel; tunnel = tunnel->next) {
457 if (tunnel->ifindex == index) {
461 "%s (index=%d)\n", tunnel->ifname, tunnel->ifindex));
465 DEBUGMSG(("tunnel", "NONE\n"));
471 static struct tunnel *
472 getNextTunnelByIfIndex(int index)
474 struct tunnel *tunnel;
476 DEBUGMSG(("tunnel", "getNextTunnelByIfIndex(%d): ", index));
478 for (tunnel = tunnels; tunnel; tunnel = tunnel->next) {
479 if (tunnel->ifindex > index) {
483 "%s (index=%d)\n", tunnel->ifname, tunnel->ifindex));
487 DEBUGMSG(("tunnel", "NONE\n"));
494 fillConfigOid(oid * name, struct tunnel *tunnel)
496 name[0] = ((unsigned char *) &tunnel->local)[0];
497 name[1] = ((unsigned char *) &tunnel->local)[1];
498 name[2] = ((unsigned char *) &tunnel->local)[2];
499 name[3] = ((unsigned char *) &tunnel->local)[3];
500 name[4] = ((unsigned char *) &tunnel->remote)[0];
501 name[5] = ((unsigned char *) &tunnel->remote)[1];
502 name[6] = ((unsigned char *) &tunnel->remote)[2];
503 name[7] = ((unsigned char *) &tunnel->remote)[3];
504 name[8] = tunnel->encaps;
505 name[9] = tunnel->id;
506 DEBUGMSGOID(("tunnel", name, 10));
511 static struct tunnel *
512 getTunnelByConfigOid(oid * name, size_t * length)
514 struct tunnel *tunnel;
515 oid tname[4 + 4 + 1 + 1];
517 DEBUGMSG(("tunnel", "getTunnelByConfigOid(): "));
519 for (tunnel = tunnels; tunnel; tunnel = tunnel->next) {
520 fillConfigOid(tname, tunnel);
521 if (!snmp_oid_compare(tname, 4 + 4 + 1 + 1,
522 &name[tunnel_len + 3],
523 (*length) - tunnel_len - 3)) {
527 "%s (index=%d)\n", tunnel->ifname, tunnel->ifindex));
531 DEBUGMSG(("tunnel", "NONE\n"));
537 static struct tunnel *
538 getNextTunnelByConfigOid(oid * name, size_t * length)
540 struct tunnel *tunnel, *last_tunnel;
541 oid tname[10], last_tname[10];
543 DEBUGMSG(("tunnel", "getNextTunnelByConfigOid("));
544 DEBUGMSGOID(("tunnel", name, *length));
545 DEBUGMSG(("tunnel", "): "));
548 for (tunnel = tunnels; tunnel; tunnel = tunnel->next) {
551 fillConfigOid(tname, tunnel);
552 if (snmp_oid_compare(tname, 10,
553 &name[tunnel_len + 3],
554 (*length) - tunnel_len - 3) > 0) {
556 last_tunnel = tunnel;
557 memcpy((char *) last_tname, (char *) tname,
560 if (snmp_oid_compare(tname, 10, last_tname, 10) < 0) {
561 last_tunnel = tunnel;
562 memcpy((char *) last_tname, (char *) tname,
572 last_tunnel->ifname, last_tunnel->ifindex));
574 DEBUGMSG(("tunnel", "NONE\n"));
583 writeLocalAddress(int action, unsigned char *var_val,
584 unsigned char var_val_type, size_t var_val_len,
585 unsigned char *statP, oid * name, size_t name_len)
587 static struct tunnel *tunnel;
588 struct ip_tunnel_parm *parm;
592 if (var_val_type != ASN_IPADDRESS) {
593 return SNMP_ERR_WRONGTYPE;
595 if (var_val_len != 4) {
596 return SNMP_ERR_WRONGLENGTH;
599 tunnel = getTunnelByIfIndex((int) name[name_len - 1]);
601 return SNMP_ERR_NOSUCHNAME;
611 return SNMP_ERR_NOSUCHNAME;
613 parm = getTunnelParm(tunnel->ifname);
615 return SNMP_ERR_NOSUCHNAME;
617 parm->iph.saddr = *(unsigned long *) var_val;
618 setTunnelParm(tunnel->ifname, parm);
622 return SNMP_ERR_NOERROR;
628 writeRemoteAddress(int action, unsigned char *var_val,
629 unsigned char var_val_type, size_t var_val_len,
630 unsigned char *statP, oid * name, size_t name_len)
632 static struct tunnel *tunnel;
633 struct ip_tunnel_parm *parm;
637 if (var_val_type != ASN_IPADDRESS) {
638 return SNMP_ERR_WRONGTYPE;
640 if (var_val_len != 4) {
641 return SNMP_ERR_WRONGLENGTH;
644 tunnel = getTunnelByIfIndex((int) name[name_len - 1]);
646 return SNMP_ERR_NOSUCHNAME;
656 return SNMP_ERR_NOSUCHNAME;
658 parm = getTunnelParm(tunnel->ifname);
660 return SNMP_ERR_NOSUCHNAME;
662 parm->iph.daddr = *(unsigned long *) var_val;
663 setTunnelParm(tunnel->ifname, parm);
667 return SNMP_ERR_NOERROR;
673 writeHopLimit(int action, unsigned char *var_val,
674 unsigned char var_val_type, size_t var_val_len,
675 unsigned char *statP, oid * name, size_t name_len)
677 static struct tunnel *tunnel;
678 struct ip_tunnel_parm *parm;
682 if (var_val_type != ASN_INTEGER) {
683 return SNMP_ERR_WRONGTYPE;
685 if (var_val_len > sizeof(long)) {
686 return SNMP_ERR_WRONGLENGTH;
689 tunnel = getTunnelByIfIndex((int) name[name_len - 1]);
691 return SNMP_ERR_NOSUCHNAME;
701 return SNMP_ERR_NOSUCHNAME;
703 parm = getTunnelParm(tunnel->ifname);
705 return SNMP_ERR_NOSUCHNAME;
707 parm->iph.ttl = *(long *) var_val;
708 setTunnelParm(tunnel->ifname, parm);
712 return SNMP_ERR_NOERROR;
718 writeTOS(int action, unsigned char *var_val,
719 unsigned char var_val_type, size_t var_val_len,
720 unsigned char *statP, oid * name, size_t name_len)
722 static struct tunnel *tunnel;
723 struct ip_tunnel_parm *parm;
727 if (var_val_type != ASN_INTEGER) {
728 return SNMP_ERR_WRONGTYPE;
730 if (var_val_len > sizeof(long)) {
731 return SNMP_ERR_WRONGLENGTH;
734 tunnel = getTunnelByIfIndex((int) name[name_len - 1]);
736 return SNMP_ERR_NOSUCHNAME;
746 return SNMP_ERR_NOSUCHNAME;
748 parm = getTunnelParm(tunnel->ifname);
750 return SNMP_ERR_NOSUCHNAME;
753 * this does not cover all meaningful values:
755 parm->iph.tos = (*(long *) var_val == -1) ? 1 : *(long *) var_val;
756 setTunnelParm(tunnel->ifname, parm);
760 return SNMP_ERR_NOERROR;
766 var_tunnelIfEntry(struct variable *vp,
767 oid * name, size_t * length,
768 int exact, size_t * var_len, WriteMethod ** write_method)
770 static unsigned long ret_addr;
772 struct tunnel *tunnel;
774 DEBUGMSGTL(("tunnel", "var_tunnelIfEntry: "));
775 DEBUGMSGOID(("tunnel", name, *length));
776 DEBUGMSG(("tunnel", " %d\n", exact));
781 if (*length != tunnel_len + 3 + 1) {
784 tunnel = getTunnelByIfIndex((int) name[*length - 1]);
786 if ((*length) < tunnel_len) {
787 memcpy((char *) name, (char *) tunnel_variables_oid,
788 tunnel_len * sizeof(oid));
790 if ((*length) < tunnel_len + 1) {
791 name[tunnel_len] = 1;
793 if ((*length) < tunnel_len + 2) {
794 name[tunnel_len + 1] = 1;
796 if ((*length) < tunnel_len + 3) {
797 name[tunnel_len + 2] = 1;
799 if ((*length) < tunnel_len + 4) {
800 name[tunnel_len + 3] = 0;
802 *length = tunnel_len + 4;
804 tunnel = getNextTunnelByIfIndex(name[*length - 1]);
807 * end of column, continue with first row of next column
810 name[tunnel_len + 2]++;
811 if (name[tunnel_len + 2] > 6) {
813 * there is no next column
819 * there is no (next) row
830 name[*length - 1] = tunnel->ifindex;
832 DEBUGMSGTL(("tunnel", "var_tunnelIfEntry: using"));
833 DEBUGMSGOID(("tunnel", name, *length));
834 DEBUGMSG(("tunnel", "\n"));
836 switch (name[tunnel_len + 2]) {
837 case 1: /* tunnelIfLocalAddress */
838 ret_addr = tunnel->local;
840 vp->type = ASN_IPADDRESS;
841 *write_method = writeLocalAddress;
842 return (u_char *) & ret_addr;
843 case 2: /* tunnelIfRemoteAddress */
844 ret_addr = tunnel->remote;
846 vp->type = ASN_IPADDRESS;
847 *write_method = writeRemoteAddress;
848 return (u_char *) & ret_addr;
849 case 3: /* tunnelIfEncapsMethod */
850 ret_int = tunnel->encaps;
851 *var_len = sizeof(ret_int);
852 vp->type = ASN_INTEGER;
853 return (u_char *) & ret_int;
854 case 4: /* tunnelIfHopLimit */
855 ret_int = tunnel->hoplimit;
856 *var_len = sizeof(ret_int);
857 vp->type = ASN_INTEGER;
858 *write_method = writeHopLimit;
859 return (u_char *) & ret_int;
860 case 5: /* tunnelIfSecurity */
861 ret_int = tunnel->security;
862 *var_len = sizeof(ret_int);
863 vp->type = ASN_INTEGER;
864 return (u_char *) & ret_int;
865 case 6: /* tunnelIfTOS */
866 ret_int = tunnel->tos;
867 *var_len = sizeof(ret_int);
868 vp->type = ASN_INTEGER;
869 *write_method = writeTOS;
870 return (u_char *) & ret_int;
881 var_tunnelConfigEntry(struct variable *vp,
882 oid * name, size_t * length,
883 int exact, size_t * var_len,
884 WriteMethod ** write_method)
887 struct tunnel *tunnel;
890 DEBUGMSGTL(("tunnel", "var_tunnelConfigEntry: "));
891 DEBUGMSGOID(("tunnel", name, *length));
892 DEBUGMSG(("tunnel", " %d\n", exact));
897 if (*length != tunnel_len + 3 + 4 + 4 + 1 + 1) {
900 tunnel = getTunnelByConfigOid(name, length);
902 if (snmp_oid_compare(name, *length,
903 tunnel_configEntry_oid,
904 tunnel_configEntry_len) < 0) {
907 if ((*length) < tunnel_len) {
908 memcpy((char *) name, (char *) tunnel_variables_oid,
909 tunnel_len * sizeof(oid));
911 if ((*length) < tunnel_len + 1) {
912 name[tunnel_len] = 2;
914 if ((*length) < tunnel_len + 2) {
915 name[tunnel_len + 1] = 1;
917 if ((*length) < tunnel_len + 3) {
918 name[tunnel_len + 2] = 5;
920 for (i = MAX(*length, tunnel_len + 3);
921 i < tunnel_len + 3 + 4 + 4 + 1 + 1; i++) {
924 *length = tunnel_len + 3 + 4 + 4 + 1 + 1;
925 tunnel = getNextTunnelByConfigOid(name, length);
928 * end of column, continue with first row of next column
931 name[tunnel_len + 2]++;
932 if (name[tunnel_len + 2] > 6) {
934 * there is no next column
940 * there is no (next) row
951 fillConfigOid(&name[tunnel_len + 3], tunnel);
953 DEBUGMSGTL(("tunnel", "var_tunnelConfigEntry: using "));
954 DEBUGMSGOID(("tunnel", name, *length));
955 DEBUGMSG(("tunnel", "\n"));
957 switch (name[tunnel_len + 2]) {
958 case 5: /* tunnelConfigIfIndex */
959 ret_int = tunnel->ifindex;
960 *var_len = sizeof(ret_int);
961 vp->type = ASN_INTEGER;
962 return (u_char *) & ret_int;
963 case 6: /* tunnelConfigStatus */
964 ret_int = 1; /* active */
965 *var_len = sizeof(ret_int);
966 vp->type = ASN_INTEGER;
967 return (u_char *) & ret_int;