tunnel.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:26k
源码类别:

SNMP编程

开发平台:

Unix_Linux

  1. /*
  2.  * tunnel.c --
  3.  * 
  4.  *      An implementation of the TUNNEL-MIB for the UCD-SNMP 4.2
  5.  *      agent running on Linux 2.2.x.
  6.  *      
  7.  * Copyright (c) 2000 Frank Strauss <strauss@ibr.cs.tu-bs.de>
  8.  *
  9.  *                          All Rights Reserved
  10.  * 
  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.
  19.  * 
  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
  28.  * SOFTWARE.
  29.  *
  30.  */
  31. /*
  32.  * NOTE: This TUNNEL-MIB implementation
  33.  *
  34.  *       (a) DOES NOT implement write access on the tunnelConfigTable,
  35.  *           i.e. no new tunnels can be created and no existing tunnels
  36.  *           can be removed through SET operations.
  37.  *
  38.  *       (b) DOES implement write access on some tunnelIfTable objects
  39.  *           to allow reconfiguring established tunnels. This violates
  40.  *           RFC 2667! However, the author thinks it makes sense. ;-)
  41.  */
  42. #include <string.h>
  43. #include <stdio.h>
  44. #include <stdlib.h>
  45. #include <unistd.h>
  46. #include <sys/types.h>
  47. #include <sys/socket.h>
  48. #include <sys/time.h>
  49. #include <sys/ioctl.h>
  50. #include <signal.h>
  51. #include <netinet/in.h>
  52. #include <arpa/inet.h>
  53. #include <linux/if.h>
  54. #include <linux/ip.h>
  55. #include <linux/sockios.h>
  56. #include <linux/if_tunnel.h>
  57. #include <linux/if_arp.h>
  58. #include <net-snmp/net-snmp-config.h>
  59. #include <net-snmp/net-snmp-includes.h>
  60. #include <net-snmp/agent/net-snmp-agent-includes.h>
  61. #include "util_funcs.h"
  62. #include "tunnel.h"
  63. #ifndef MIN
  64. #define MIN(a, b) (((a) < (b)) ? (a) : (b))
  65. #endif
  66. #ifndef MAX
  67. #define MAX(a, b) (((a) > (b)) ? (a) : (b))
  68. #endif
  69. /*
  70.  * This is used, because the TUNNEL-MIB augments ifTable. 
  71.  */
  72. extern unsigned char *var_ifEntry(struct variable *,
  73.                                   oid *, size_t *,
  74.                                   int, size_t *, WriteMethod **);
  75. /*
  76.  * tunnel_variables_oid:
  77.  *   this is the top level oid that we want to register under.  This
  78.  *   is essentially a prefix, with the suffix appearing in the
  79.  *   variable below.
  80.  */
  81. oid             tunnel_variables_oid[] =
  82.     { 1, 3, 6, 1, 2, 1, 10, 131, 1, 1 };
  83. const int       tunnel_len = 10;
  84. oid             tunnel_ifEntry_oid[] =
  85.     { 1, 3, 6, 1, 2, 1, 10, 131, 1, 1, 1, 1 };
  86. const int       tunnel_ifEntry_len = 12;
  87. oid             tunnel_configEntry_oid[] =
  88.     { 1, 3, 6, 1, 2, 1, 10, 131, 1, 1, 2, 1 };
  89. const int       tunnel_configEntry_len = 12;
  90. struct tunnel {
  91.     oid             ifindex;
  92.     int             id;
  93.     char           *ifname;
  94.     int             active;
  95.     unsigned long   local;
  96.     unsigned long   remote;
  97.     int             encaps;
  98.     int             hoplimit;
  99.     int             security;
  100.     int             tos;
  101.     oid             config_name[MAX_OID_LEN];
  102.     size_t          config_length;
  103.     struct tunnel  *next;
  104. };
  105. /*
  106.  * variable4 tunnel_variables:
  107.  *   this variable defines function callbacks and type return information 
  108.  *   for the tunnel mib section 
  109.  */
  110. struct variable4 tunnel_variables[] = {
  111.     /*
  112.      * magic number        , variable type , ro/rw , callback fn  , L, oidsuffix 
  113.      */
  114. #define   LOCALADDRESS          1
  115.     {LOCALADDRESS, ASN_IPADDRESS, RWRITE, var_tunnelIfEntry, 3, {1, 1, 1}},
  116. #define   REMOTEADDRESS         2
  117.     {REMOTEADDRESS, ASN_IPADDRESS, RWRITE, var_tunnelIfEntry, 3,
  118.      {1, 1, 2}},
  119. #define   ENCAPSMETHOD          3
  120.     {ENCAPSMETHOD, ASN_INTEGER, RONLY, var_tunnelIfEntry, 3, {1, 1, 3}},
  121. #define   HOPLIMIT              4
  122.     {HOPLIMIT, ASN_INTEGER, RWRITE, var_tunnelIfEntry, 3, {1, 1, 4}},
  123. #define   SECURITY              5
  124.     {SECURITY, ASN_INTEGER, RONLY, var_tunnelIfEntry, 3, {1, 1, 5}},
  125. #define   TOS                   6
  126.     {TOS, ASN_INTEGER, RWRITE, var_tunnelIfEntry, 3, {1, 1, 6}},
  127. #define   IFINDEX               7
  128.     {IFINDEX, ASN_INTEGER, RONLY, var_tunnelConfigEntry, 3, {2, 1, 5}},
  129. #define   ROWSTATUS             8
  130.     {ROWSTATUS, ASN_INTEGER, RWRITE, var_tunnelConfigEntry, 3, {2, 1, 6}},
  131. };
  132. extern int      register_sysORTable(oid *, size_t, const char *);
  133. extern int      unregister_sysORTable(oid *, size_t);
  134. static oid      sysORTable_reg[] = { 1, 3, 6, 1, 2, 1, 10, 131 };
  135. static size_t   sysORTable_reglen = 8;
  136. static struct tunnel *tunnels;
  137. void
  138. deinit_tunnel(void)
  139. {
  140.     unregister_sysORTable(sysORTable_reg, sysORTable_reglen);
  141. }
  142. int
  143. term_tunnel(int majorID, int minorID, void *serverarg, void *clientarg)
  144. {
  145.     deinit_tunnel();
  146.     return 0;
  147. }
  148. void
  149. init_tunnel(void)
  150. {
  151.     register_sysORTable(sysORTable_reg, sysORTable_reglen,
  152.                         "RFC 2667 TUNNEL-MIB implementation for "
  153.                         "Linux 2.2.x kernels.");
  154.     /*
  155.      * register ourselves with the agent to handle our mib tree 
  156.      */
  157.     REGISTER_MIB("tunnel", tunnel_variables, variable4,
  158.                  tunnel_variables_oid);
  159.     snmp_register_callback(SNMP_CALLBACK_LIBRARY,
  160.                            SNMP_CALLBACK_SHUTDOWN, term_tunnel, NULL);
  161.     tunnels = NULL;
  162. }
  163. static int
  164. getType(int index)
  165. {
  166.     oid             name[MAX_OID_LEN] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 3 };
  167.     size_t          length = 10;
  168.     struct variable ifType_variable =
  169.         { 3, ASN_INTEGER, RONLY, var_ifEntry, 10,
  170.         {1, 3, 6, 1, 2, 1, 2, 2, 1, 3}
  171.     };
  172.     unsigned char  *p;
  173.     size_t          var_len;
  174.     WriteMethod    *write_method;
  175.     name[length] = index;
  176.     length++;
  177.     p = var_ifEntry(&ifType_variable,
  178.                     name, &length,
  179.                     1 /* exact */ , &var_len, &write_method);
  180.     if (!p)
  181.         return 0;
  182.     return *(int *) p;
  183. }
  184. static char    *
  185. getName(int index)
  186. {
  187.     oid             name[MAX_OID_LEN] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 2 };
  188.     size_t          length = 10;
  189.     struct variable ifName_variable =
  190.         { 2, ASN_INTEGER, RONLY, var_ifEntry, 10,
  191.         {1, 3, 6, 1, 2, 1, 2, 2, 1, 2}
  192.     };
  193.     unsigned char  *p;
  194.     size_t          var_len;
  195.     WriteMethod    *write_method;
  196.     name[length] = index;
  197.     length++;
  198.     p = var_ifEntry(&ifName_variable,
  199.                     name, &length,
  200.                     1 /* exact */ , &var_len, &write_method);
  201.     if (!p)
  202.         return NULL;
  203.     return p;
  204. }
  205. static struct ip_tunnel_parm *
  206. getTunnelParm(char *ifname)
  207. {
  208.     struct ifreq    ifrq;
  209.     int             fd;
  210.     static struct ip_tunnel_parm parm;
  211.     if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  212.         return NULL;
  213.     }
  214.     memset(&parm, 0, sizeof(struct ip_tunnel_parm));
  215.     strcpy(ifrq.ifr_name, ifname);
  216.     ifrq.ifr_ifru.ifru_data = (void *) &parm;
  217.     if (ioctl(fd, SIOCGETTUNNEL, &ifrq) < 0) {
  218.         /*
  219.          * try again with the last char of the device name cut off.
  220.          * it might have been a zero digit appended by the agent.
  221.          */
  222.         ifrq.ifr_name[strlen(ifrq.ifr_name) - 1] = 0;
  223.         if (ioctl(fd, SIOCGETTUNNEL, &ifrq) < 0) {
  224.             close(fd);
  225.             return NULL;
  226.         }
  227.         ifname[strlen(ifname) - 1] = 0;
  228.     }
  229.     close(fd);
  230.     return &parm;
  231. }
  232. int
  233. setTunnelParm(char *ifname, struct ip_tunnel_parm *parm)
  234. {
  235.     struct ifreq    ifrq;
  236.     int             fd;
  237.     int             err;
  238.     if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  239.         return -1;
  240.     }
  241.     strcpy(ifrq.ifr_name, ifname);
  242.     ifrq.ifr_ifru.ifru_data = (void *) parm;
  243.     err = ioctl(fd, SIOCCHGTUNNEL, &ifrq);
  244.     close(fd);
  245.     return err;
  246. }
  247. /*
  248.  * update a struct tunnel. its index and ifname elements have to be set.
  249.  */
  250. static struct tunnel *
  251. updateTunnel(struct tunnel *tunnel)
  252. {
  253.     struct ip_tunnel_parm *parm;
  254.     int             fd;
  255.     struct ifreq    ifrq;
  256.     /*
  257.      * NOTE: getTunnelParm() may adjust the passed ifname. 
  258.      */
  259.     parm = getTunnelParm(tunnel->ifname);
  260.     if (!parm) {
  261. DEBUGMSGTL(("tunnel",
  262.     "updateTunnel(): getTunnelParm("%s") returned NULLn",
  263.     tunnel->ifname));
  264.         tunnel->active = 0;
  265.         return NULL;
  266.     }
  267.     tunnel->active = 1;
  268.     tunnel->local = parm->iph.saddr;
  269.     tunnel->remote = parm->iph.daddr;
  270.     if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  271.         DEBUGMSGTL(("snmpd", "socket open failure in updateTunnels()n"));
  272.         return NULL;
  273.     } else {
  274.         /*
  275.          * NOTE: this ioctl does not guarantee 6 bytes of a physaddr.
  276.          * In particular, a 'sit0' interface only appears to get back
  277.          * 4 bytes of sa_data. We don't use sa_data here, or we'd
  278.          * need to memset it to 0 before the ioct.
  279.          */
  280.         strcpy(ifrq.ifr_name, tunnel->ifname);
  281.         if (ioctl(fd, SIOCGIFHWADDR, &ifrq) == 0)
  282.             switch (ifrq.ifr_hwaddr.sa_family) {
  283.             case ARPHRD_TUNNEL:
  284.                 tunnel->encaps = 2;
  285.                 break;;         /* direct */
  286.             case ARPHRD_TUNNEL6:
  287.                 tunnel->encaps = 2;
  288.                 break;;         /* direct */
  289.             case ARPHRD_IPGRE:
  290.                 tunnel->encaps = 3;
  291.                 break;;         /* gre */
  292.             case ARPHRD_SIT:
  293.                 tunnel->encaps = 2;
  294.                 break;;         /* direct */
  295.             default:
  296.                 tunnel->encaps = 1;     /* other */
  297.             }
  298.         close(fd);
  299.     }
  300.     tunnel->hoplimit = parm->iph.ttl;
  301.     tunnel->security = 1;
  302.     tunnel->tos = (parm->iph.tos & 1) ? -1 : parm->iph.tos;
  303.     /*
  304.      * XXX: adjust tos mapping (kernel <-> TUNNEL-MIB::tunnelIfTOS) 
  305.      */
  306.     return tunnel;
  307. }
  308. static void
  309. updateTunnels(void)
  310. {
  311.     static int      max_index = 1;
  312.     static struct tunnel *last_tunnel = NULL;
  313.     struct tunnel  *tunnel;
  314.     char           *ifname;
  315.     int             type;
  316.     /*
  317.      * uptime the tunnels we have so far 
  318.      */
  319.     for (tunnel = tunnels; tunnel; tunnel = tunnel->next) {
  320.         DEBUGMSG(("tunnel",
  321.                   "updateTunnels(): updating %s (index=%d)n",
  322.                   tunnel->ifname, tunnel->ifindex));
  323.         updateTunnel(tunnel);
  324.     }
  325.     /*
  326.      * look for new tunnels 
  327.      */
  328.     for (; max_index < 256; max_index++) {
  329.         DEBUGMSG(("tunnel",
  330.                   "updateTunnels(): looking for new index=%dn",
  331.                   max_index));
  332.         type = getType(max_index);
  333.         if (type == 131) {
  334.             tunnel = (struct tunnel *) malloc(sizeof(struct tunnel));
  335.             if (!tunnel)
  336.                 continue;
  337.             tunnel->ifindex = max_index;
  338.             tunnel->id = 1;
  339.             ifname = getName(max_index);
  340.             if (!ifname) {
  341.                 free(tunnel);
  342.                 continue;
  343.             }
  344.             tunnel->ifname = strdup(ifname);
  345.             if (!tunnel->ifname) {
  346.                 free(tunnel);
  347.                 continue;
  348.             }
  349.             if (!updateTunnel(tunnel)) {
  350.                 free(tunnel);
  351.                 continue;
  352.             }
  353.             if (last_tunnel)
  354.                 last_tunnel->next = tunnel;
  355.             if (!tunnels)
  356.                 tunnels = last_tunnel = tunnel;
  357.             tunnel->next = NULL;
  358.             last_tunnel = tunnel;
  359.             DEBUGMSG(("tunnel",
  360.                       "updateTunnels(): added %s (index=%d state=%d)n",
  361.                       tunnel->ifname, tunnel->ifindex, tunnel->active));
  362.         }
  363.         if (type == 0)
  364.             break;
  365.     }
  366. }
  367. static struct tunnel *
  368. getTunnelByIfIndex(int index)
  369. {
  370.     struct tunnel  *tunnel;
  371.     DEBUGMSG(("tunnel", "getTunnelByIfIndex(%d): ", index));
  372.     for (tunnel = tunnels; tunnel; tunnel = tunnel->next) {
  373.         if (tunnel->ifindex == index) {
  374.             if (!tunnel->active)
  375.                 break;
  376.             DEBUGMSG(("tunnel",
  377.                       "%s (index=%d)n", tunnel->ifname, tunnel->ifindex));
  378.             return tunnel;
  379.         }
  380.     }
  381.     DEBUGMSG(("tunnel", "NONEn"));
  382.     return NULL;
  383. }
  384. static struct tunnel *
  385. getNextTunnelByIfIndex(int index)
  386. {
  387.     struct tunnel  *tunnel;
  388.     DEBUGMSG(("tunnel", "getNextTunnelByIfIndex(%d): ", index));
  389.     for (tunnel = tunnels; tunnel; tunnel = tunnel->next) {
  390.         if (tunnel->ifindex > index) {
  391.             if (!tunnel->active)
  392.                 continue;
  393.             DEBUGMSG(("tunnel",
  394.                       "%s (index=%d)n", tunnel->ifname, tunnel->ifindex));
  395.             return tunnel;
  396.         }
  397.     }
  398.     DEBUGMSG(("tunnel", "NONEn"));
  399.     return NULL;
  400. }
  401. static void
  402. fillConfigOid(oid * name, struct tunnel *tunnel)
  403. {
  404.     name[0] = ((unsigned char *) &tunnel->local)[0];
  405.     name[1] = ((unsigned char *) &tunnel->local)[1];
  406.     name[2] = ((unsigned char *) &tunnel->local)[2];
  407.     name[3] = ((unsigned char *) &tunnel->local)[3];
  408.     name[4] = ((unsigned char *) &tunnel->remote)[0];
  409.     name[5] = ((unsigned char *) &tunnel->remote)[1];
  410.     name[6] = ((unsigned char *) &tunnel->remote)[2];
  411.     name[7] = ((unsigned char *) &tunnel->remote)[3];
  412.     name[8] = tunnel->encaps;
  413.     name[9] = tunnel->id;
  414.     DEBUGMSGOID(("tunnel", name, 10));
  415. }
  416. static struct tunnel *
  417. getTunnelByConfigOid(oid * name, size_t * length)
  418. {
  419.     struct tunnel  *tunnel;
  420.     oid             tname[4 + 4 + 1 + 1];
  421.     DEBUGMSG(("tunnel", "getTunnelByConfigOid(): "));
  422.     for (tunnel = tunnels; tunnel; tunnel = tunnel->next) {
  423.         fillConfigOid(tname, tunnel);
  424.         if (!snmp_oid_compare(tname, 4 + 4 + 1 + 1,
  425.                               &name[tunnel_len + 3],
  426.                               (*length) - tunnel_len - 3)) {
  427.             if (!tunnel->active)
  428.                 break;
  429.             DEBUGMSG(("tunnel",
  430.                       "%s (index=%d)n", tunnel->ifname, tunnel->ifindex));
  431.             return tunnel;
  432.         }
  433.     }
  434.     DEBUGMSG(("tunnel", "NONEn"));
  435.     return NULL;
  436. }
  437. static struct tunnel *
  438. getNextTunnelByConfigOid(oid * name, size_t * length)
  439. {
  440.     struct tunnel  *tunnel, *last_tunnel;
  441.     oid             tname[10], last_tname[10];
  442.     DEBUGMSG(("tunnel", "getNextTunnelByConfigOid("));
  443.     DEBUGMSGOID(("tunnel", name, *length));
  444.     DEBUGMSG(("tunnel", "): "));
  445.     last_tunnel = NULL;
  446.     for (tunnel = tunnels; tunnel; tunnel = tunnel->next) {
  447.         if (!tunnel->active)
  448.             continue;
  449.         fillConfigOid(tname, tunnel);
  450.         if (snmp_oid_compare(tname, 10,
  451.                              &name[tunnel_len + 3],
  452.                              (*length) - tunnel_len - 3) > 0) {
  453.             if (!last_tunnel) {
  454.                 last_tunnel = tunnel;
  455.                 memcpy((char *) last_tname, (char *) tname,
  456.                        10 * sizeof(oid));
  457.             } else {
  458.                 if (snmp_oid_compare(tname, 10, last_tname, 10) < 0) {
  459.                     last_tunnel = tunnel;
  460.                     memcpy((char *) last_tname, (char *) tname,
  461.                            10 * sizeof(oid));
  462.                 }
  463.             }
  464.         }
  465.     }
  466.     if (last_tunnel) {
  467.         DEBUGMSG(("tunnel",
  468.                   "%s (index=%d)n",
  469.                   last_tunnel->ifname, last_tunnel->ifindex));
  470.     } else {
  471.         DEBUGMSG(("tunnel", "NONEn"));
  472.     }
  473.     return last_tunnel;
  474. }
  475. static int
  476. writeLocalAddress(int action, unsigned char *var_val,
  477.                   unsigned char var_val_type, size_t var_val_len,
  478.                   unsigned char *statP, oid * name, size_t name_len)
  479. {
  480.     static struct tunnel *tunnel;
  481.     struct ip_tunnel_parm *parm;
  482.     switch (action) {
  483.     case RESERVE1:
  484.         if (var_val_type != ASN_IPADDRESS) {
  485.             return SNMP_ERR_WRONGTYPE;
  486.         }
  487.         if (var_val_len != 4) {
  488.             return SNMP_ERR_WRONGLENGTH;
  489.         }
  490.     case RESERVE2:
  491.         tunnel = getTunnelByIfIndex((int) name[name_len - 1]);
  492.         if (!tunnel) {
  493.             return SNMP_ERR_NOSUCHNAME;
  494.         }
  495.     case FREE:
  496.         break;
  497.     case ACTION:
  498.         break;
  499.     case UNDO:
  500.         break;
  501.     case COMMIT:
  502.         if (!tunnel) {
  503.             return SNMP_ERR_NOSUCHNAME;
  504.         }
  505.         parm = getTunnelParm(tunnel->ifname);
  506.         if (!parm) {
  507.             return SNMP_ERR_NOSUCHNAME;
  508.         }
  509.         parm->iph.saddr = *(unsigned long *) var_val;
  510.         setTunnelParm(tunnel->ifname, parm);
  511.         break;
  512.     }
  513.     return SNMP_ERR_NOERROR;
  514. }
  515. static int
  516. writeRemoteAddress(int action, unsigned char *var_val,
  517.                    unsigned char var_val_type, size_t var_val_len,
  518.                    unsigned char *statP, oid * name, size_t name_len)
  519. {
  520.     static struct tunnel *tunnel;
  521.     struct ip_tunnel_parm *parm;
  522.     switch (action) {
  523.     case RESERVE1:
  524.         if (var_val_type != ASN_IPADDRESS) {
  525.             return SNMP_ERR_WRONGTYPE;
  526.         }
  527.         if (var_val_len != 4) {
  528.             return SNMP_ERR_WRONGLENGTH;
  529.         }
  530.     case RESERVE2:
  531.         tunnel = getTunnelByIfIndex((int) name[name_len - 1]);
  532.         if (!tunnel) {
  533.             return SNMP_ERR_NOSUCHNAME;
  534.         }
  535.     case FREE:
  536.         break;
  537.     case ACTION:
  538.         break;
  539.     case UNDO:
  540.         break;
  541.     case COMMIT:
  542.         if (!tunnel) {
  543.             return SNMP_ERR_NOSUCHNAME;
  544.         }
  545.         parm = getTunnelParm(tunnel->ifname);
  546.         if (!parm) {
  547.             return SNMP_ERR_NOSUCHNAME;
  548.         }
  549.         parm->iph.daddr = *(unsigned long *) var_val;
  550.         setTunnelParm(tunnel->ifname, parm);
  551.         break;
  552.     }
  553.     return SNMP_ERR_NOERROR;
  554. }
  555. static int
  556. writeHopLimit(int action, unsigned char *var_val,
  557.               unsigned char var_val_type, size_t var_val_len,
  558.               unsigned char *statP, oid * name, size_t name_len)
  559. {
  560.     static struct tunnel *tunnel;
  561.     struct ip_tunnel_parm *parm;
  562.     switch (action) {
  563.     case RESERVE1:
  564.         if (var_val_type != ASN_INTEGER) {
  565.             return SNMP_ERR_WRONGTYPE;
  566.         }
  567.         if (var_val_len > sizeof(long)) {
  568.             return SNMP_ERR_WRONGLENGTH;
  569.         }
  570.     case RESERVE2:
  571.         tunnel = getTunnelByIfIndex((int) name[name_len - 1]);
  572.         if (!tunnel) {
  573.             return SNMP_ERR_NOSUCHNAME;
  574.         }
  575.     case FREE:
  576.         break;
  577.     case ACTION:
  578.         break;
  579.     case UNDO:
  580.         break;
  581.     case COMMIT:
  582.         if (!tunnel) {
  583.             return SNMP_ERR_NOSUCHNAME;
  584.         }
  585.         parm = getTunnelParm(tunnel->ifname);
  586.         if (!parm) {
  587.             return SNMP_ERR_NOSUCHNAME;
  588.         }
  589.         parm->iph.ttl = *(long *) var_val;
  590.         setTunnelParm(tunnel->ifname, parm);
  591.         break;
  592.     }
  593.     return SNMP_ERR_NOERROR;
  594. }
  595. static int
  596. writeTOS(int action, unsigned char *var_val,
  597.          unsigned char var_val_type, size_t var_val_len,
  598.          unsigned char *statP, oid * name, size_t name_len)
  599. {
  600.     static struct tunnel *tunnel;
  601.     struct ip_tunnel_parm *parm;
  602.     switch (action) {
  603.     case RESERVE1:
  604.         if (var_val_type != ASN_INTEGER) {
  605.             return SNMP_ERR_WRONGTYPE;
  606.         }
  607.         if (var_val_len > sizeof(long)) {
  608.             return SNMP_ERR_WRONGLENGTH;
  609.         }
  610.     case RESERVE2:
  611.         tunnel = getTunnelByIfIndex((int) name[name_len - 1]);
  612.         if (!tunnel) {
  613.             return SNMP_ERR_NOSUCHNAME;
  614.         }
  615.     case FREE:
  616.         break;
  617.     case ACTION:
  618.         break;
  619.     case UNDO:
  620.         break;
  621.     case COMMIT:
  622.         if (!tunnel) {
  623.             return SNMP_ERR_NOSUCHNAME;
  624.         }
  625.         parm = getTunnelParm(tunnel->ifname);
  626.         if (!parm) {
  627.             return SNMP_ERR_NOSUCHNAME;
  628.         }
  629.         /*
  630.          * this does not cover all meaningful values: 
  631.          */
  632.         parm->iph.tos = (*(long *) var_val == -1) ? 1 : *(long *) var_val;
  633.         setTunnelParm(tunnel->ifname, parm);
  634.         break;
  635.     }
  636.     return SNMP_ERR_NOERROR;
  637. }
  638. unsigned char  *
  639. var_tunnelIfEntry(struct variable *vp,
  640.                   oid * name, size_t * length,
  641.                   int exact, size_t * var_len, WriteMethod ** write_method)
  642. {
  643.     static unsigned long ret_addr;
  644.     static long     ret_int;
  645.     struct tunnel  *tunnel;
  646.     DEBUGMSGTL(("tunnel", "var_tunnelIfEntry: "));
  647.     DEBUGMSGOID(("tunnel", name, *length));
  648.     DEBUGMSG(("tunnel", " %dn", exact));
  649.     updateTunnels();
  650.     if (exact) {
  651.         if (*length != tunnel_len + 3 + 1) {
  652.             return NULL;
  653.         }
  654.         tunnel = getTunnelByIfIndex((int) name[*length - 1]);
  655.     } else {
  656.         if ((*length) < tunnel_len) {
  657.             memcpy((char *) name, (char *) tunnel_variables_oid,
  658.                    tunnel_len * sizeof(oid));
  659.         }
  660.         if ((*length) < tunnel_len + 1) {
  661.             name[tunnel_len] = 1;
  662.         }
  663.         if ((*length) < tunnel_len + 2) {
  664.             name[tunnel_len + 1] = 1;
  665.         }
  666.         if ((*length) < tunnel_len + 3) {
  667.             name[tunnel_len + 2] = 1;
  668.         }
  669.         if ((*length) < tunnel_len + 4) {
  670.             name[tunnel_len + 3] = 0;
  671.         }
  672.         *length = tunnel_len + 4;
  673.         tunnel = getNextTunnelByIfIndex(name[*length - 1]);
  674.         if (!tunnel) {
  675.             /*
  676.              * end of column, continue with first row of next column 
  677.              */
  678.             tunnel = tunnels;
  679.             name[tunnel_len + 2]++;
  680.             if (name[tunnel_len + 2] > 6) {
  681.                 /*
  682.                  * there is no next column 
  683.                  */
  684.                 return NULL;
  685.             }
  686.             if (!tunnel) {
  687.                 /*
  688.                  * there is no (next) row 
  689.                  */
  690.                 return NULL;
  691.             }
  692.         }
  693.     }
  694.     if (!tunnel) {
  695.         return NULL;
  696.     }
  697.     name[*length - 1] = tunnel->ifindex;
  698.     DEBUGMSGTL(("tunnel", "var_tunnelIfEntry: using"));
  699.     DEBUGMSGOID(("tunnel", name, *length));
  700.     DEBUGMSG(("tunnel", "n"));
  701.     switch (name[tunnel_len + 2]) {
  702.     case 1:                    /* tunnelIfLocalAddress */
  703.         ret_addr = tunnel->local;
  704.         *var_len = 4;
  705.         vp->type = ASN_IPADDRESS;
  706.         *write_method = writeLocalAddress;
  707.         return (u_char *) & ret_addr;
  708.     case 2:                    /* tunnelIfRemoteAddress */
  709.         ret_addr = tunnel->remote;
  710.         *var_len = 4;
  711.         vp->type = ASN_IPADDRESS;
  712.         *write_method = writeRemoteAddress;
  713.         return (u_char *) & ret_addr;
  714.     case 3:                    /* tunnelIfEncapsMethod */
  715.         ret_int = tunnel->encaps;
  716.         *var_len = sizeof(ret_int);
  717.         vp->type = ASN_INTEGER;
  718.         return (u_char *) & ret_int;
  719.     case 4:                    /* tunnelIfHopLimit */
  720.         ret_int = tunnel->hoplimit;
  721.         *var_len = sizeof(ret_int);
  722.         vp->type = ASN_INTEGER;
  723.         *write_method = writeHopLimit;
  724.         return (u_char *) & ret_int;
  725.     case 5:                    /* tunnelIfSecurity */
  726.         ret_int = tunnel->security;
  727.         *var_len = sizeof(ret_int);
  728.         vp->type = ASN_INTEGER;
  729.         return (u_char *) & ret_int;
  730.     case 6:                    /* tunnelIfTOS */
  731.         ret_int = tunnel->tos;
  732.         *var_len = sizeof(ret_int);
  733.         vp->type = ASN_INTEGER;
  734.         *write_method = writeTOS;
  735.         return (u_char *) & ret_int;
  736.     default:
  737.         return 0;
  738.     }
  739.     return NULL;
  740. }
  741. unsigned char  *
  742. var_tunnelConfigEntry(struct variable *vp,
  743.                       oid * name, size_t * length,
  744.                       int exact, size_t * var_len,
  745.                       WriteMethod ** write_method)
  746. {
  747.     static long     ret_int;
  748.     struct tunnel  *tunnel;
  749.     int             i;
  750.     DEBUGMSGTL(("tunnel", "var_tunnelConfigEntry: "));
  751.     DEBUGMSGOID(("tunnel", name, *length));
  752.     DEBUGMSG(("tunnel", " %dn", exact));
  753.     updateTunnels();
  754.     if (exact) {
  755.         if (*length != tunnel_len + 3 + 4 + 4 + 1 + 1) {
  756.             return NULL;
  757.         }
  758.         tunnel = getTunnelByConfigOid(name, length);
  759.     } else {
  760.         if (snmp_oid_compare(name, *length,
  761.                              tunnel_configEntry_oid,
  762.                              tunnel_configEntry_len) < 0) {
  763.             *length = 0;
  764.         }
  765.         if ((*length) < tunnel_len) {
  766.             memcpy((char *) name, (char *) tunnel_variables_oid,
  767.                    tunnel_len * sizeof(oid));
  768.         }
  769.         if ((*length) < tunnel_len + 1) {
  770.             name[tunnel_len] = 2;
  771.         }
  772.         if ((*length) < tunnel_len + 2) {
  773.             name[tunnel_len + 1] = 1;
  774.         }
  775.         if ((*length) < tunnel_len + 3) {
  776.             name[tunnel_len + 2] = 5;
  777.         }
  778.         for (i = MAX(*length, tunnel_len + 3);
  779.              i < tunnel_len + 3 + 4 + 4 + 1 + 1; i++) {
  780.             name[i] = 0;
  781.         }
  782.         *length = tunnel_len + 3 + 4 + 4 + 1 + 1;
  783.         tunnel = getNextTunnelByConfigOid(name, length);
  784.         if (!tunnel) {
  785.             /*
  786.              * end of column, continue with first row of next column 
  787.              */
  788.             tunnel = tunnels;
  789.             name[tunnel_len + 2]++;
  790.             if (name[tunnel_len + 2] > 6) {
  791.                 /*
  792.                  * there is no next column 
  793.                  */
  794.                 return NULL;
  795.             }
  796.             if (!tunnel) {
  797.                 /*
  798.                  * there is no (next) row 
  799.                  */
  800.                 return NULL;
  801.             }
  802.         }
  803.     }
  804.     if (!tunnel) {
  805.         return NULL;
  806.     }
  807.     fillConfigOid(&name[tunnel_len + 3], tunnel);
  808.     DEBUGMSGTL(("tunnel", "var_tunnelConfigEntry: using "));
  809.     DEBUGMSGOID(("tunnel", name, *length));
  810.     DEBUGMSG(("tunnel", "n"));
  811.     switch (name[tunnel_len + 2]) {
  812.     case 5:                    /* tunnelConfigIfIndex */
  813.         ret_int = tunnel->ifindex;
  814.         *var_len = sizeof(ret_int);
  815.         vp->type = ASN_INTEGER;
  816.         return (u_char *) & ret_int;
  817.     case 6:                    /* tunnelConfigStatus */
  818.         ret_int = 1;            /* active */
  819.         *var_len = sizeof(ret_int);
  820.         vp->type = ASN_INTEGER;
  821.         return (u_char *) & ret_int;
  822.     default:
  823.         return 0;
  824.     }
  825.     return NULL;
  826. }