added files
[bcm963xx.git] / userapps / opensource / net-snmp / agent / mibgroup / tunnel / tunnel.c
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 /*
33  * NOTE: This TUNNEL-MIB implementation
34  *
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.
38  *
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. ;-)
42  */
43
44 #include <string.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <unistd.h>
48 #include <sys/types.h>
49 #include <sys/socket.h>
50 #include <sys/time.h>
51 #include <sys/ioctl.h>
52 #include <signal.h>
53 #include <netinet/in.h>
54 #include <arpa/inet.h>
55
56 #include <linux/if.h>
57 #include <linux/ip.h>
58 #include <linux/sockios.h>
59 #include <linux/if_tunnel.h>
60 #include <linux/if_arp.h>
61
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>
65
66 #include "util_funcs.h"
67 #include "tunnel.h"
68
69 #ifndef MIN
70 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
71 #endif
72 #ifndef MAX
73 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
74 #endif
75
76
77
78 /*
79  * This is used, because the TUNNEL-MIB augments ifTable. 
80  */
81 extern unsigned char *var_ifEntry(struct variable *,
82                                   oid *, size_t *,
83                                   int, size_t *, WriteMethod **);
84
85
86 /*
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
90  *   variable below.
91  */
92 oid             tunnel_variables_oid[] =
93     { 1, 3, 6, 1, 2, 1, 10, 131, 1, 1 };
94 const int       tunnel_len = 10;
95
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;
99
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;
103
104
105
106 struct tunnel {
107     oid             ifindex;
108     int             id;
109     char           *ifname;
110     int             active;
111     unsigned long   local;
112     unsigned long   remote;
113     int             encaps;
114     int             hoplimit;
115     int             security;
116     int             tos;
117     oid             config_name[MAX_OID_LEN];
118     size_t          config_length;
119     struct tunnel  *next;
120 };
121
122
123
124 /*
125  * variable4 tunnel_variables:
126  *   this variable defines function callbacks and type return information 
127  *   for the tunnel mib section 
128  */
129
130 struct variable4 tunnel_variables[] = {
131     /*
132      * magic number        , variable type , ro/rw , callback fn  , L, oidsuffix 
133      */
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,
138      {1, 1, 2}},
139 #define   ENCAPSMETHOD          3
140     {ENCAPSMETHOD, ASN_INTEGER, RONLY, var_tunnelIfEntry, 3, {1, 1, 3}},
141 #define   HOPLIMIT              4
142     {HOPLIMIT, ASN_INTEGER, RWRITE, var_tunnelIfEntry, 3, {1, 1, 4}},
143 #define   SECURITY              5
144     {SECURITY, ASN_INTEGER, RONLY, var_tunnelIfEntry, 3, {1, 1, 5}},
145 #define   TOS                   6
146     {TOS, ASN_INTEGER, RWRITE, var_tunnelIfEntry, 3, {1, 1, 6}},
147
148 #define   IFINDEX               7
149     {IFINDEX, ASN_INTEGER, RONLY, var_tunnelConfigEntry, 3, {2, 1, 5}},
150 #define   ROWSTATUS             8
151     {ROWSTATUS, ASN_INTEGER, RWRITE, var_tunnelConfigEntry, 3, {2, 1, 6}},
152 };
153
154
155
156 extern int      register_sysORTable(oid *, size_t, const char *);
157 extern int      unregister_sysORTable(oid *, size_t);
158
159 static oid      sysORTable_reg[] = { 1, 3, 6, 1, 2, 1, 10, 131 };
160 static size_t   sysORTable_reglen = 8;
161
162 static struct tunnel *tunnels;
163
164
165
166 void
167 deinit_tunnel(void)
168 {
169     unregister_sysORTable(sysORTable_reg, sysORTable_reglen);
170 }
171
172
173
174 int
175 term_tunnel(int majorID, int minorID, void *serverarg, void *clientarg)
176 {
177     deinit_tunnel();
178     return 0;
179 }
180
181
182
183 void
184 init_tunnel(void)
185 {
186     register_sysORTable(sysORTable_reg, sysORTable_reglen,
187                         "RFC 2667 TUNNEL-MIB implementation for "
188                         "Linux 2.2.x kernels.");
189
190     netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPTYPE, "snmpd");
191
192     /*
193      * register ourselves with the agent to handle our mib tree 
194      */
195     REGISTER_MIB("tunnel", tunnel_variables, variable4,
196                  tunnel_variables_oid);
197
198     snmp_register_callback(SNMP_CALLBACK_LIBRARY,
199                            SNMP_CALLBACK_SHUTDOWN, term_tunnel, NULL);
200
201     tunnels = NULL;
202 }
203
204
205
206 static int
207 getType(int index)
208 {
209     oid             name[MAX_OID_LEN] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 3 };
210     size_t          length = 10;
211     struct variable ifType_variable =
212         { 3, ASN_INTEGER, RONLY, var_ifEntry, 10,
213         {1, 3, 6, 1, 2, 1, 2, 2, 1, 3}
214     };
215     unsigned char  *p;
216     size_t          var_len;
217     WriteMethod    *write_method;
218
219     name[length] = index;
220     length++;
221
222     p = var_ifEntry(&ifType_variable,
223                     name, &length,
224                     1 /* exact */ , &var_len, &write_method);
225     if (!p)
226         return 0;
227
228     return *(int *) p;
229 }
230
231
232
233 static char    *
234 getName(int index)
235 {
236     oid             name[MAX_OID_LEN] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 2 };
237     size_t          length = 10;
238     struct variable ifName_variable =
239         { 2, ASN_INTEGER, RONLY, var_ifEntry, 10,
240         {1, 3, 6, 1, 2, 1, 2, 2, 1, 2}
241     };
242     unsigned char  *p;
243     size_t          var_len;
244     WriteMethod    *write_method;
245
246     name[length] = index;
247     length++;
248
249     p = var_ifEntry(&ifName_variable,
250                     name, &length,
251                     1 /* exact */ , &var_len, &write_method);
252     if (!p)
253         return NULL;
254
255     return p;
256 }
257
258
259
260 static struct ip_tunnel_parm *
261 getTunnelParm(char *ifname)
262 {
263     struct ifreq    ifrq;
264     int             fd;
265     static struct ip_tunnel_parm parm;
266
267     if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
268         return NULL;
269     }
270
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) {
275         /*
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.
278          */
279         ifrq.ifr_name[strlen(ifrq.ifr_name) - 1] = 0;
280         if (ioctl(fd, SIOCGETTUNNEL, &ifrq) < 0) {
281             close(fd);
282             return NULL;
283         }
284         ifname[strlen(ifname) - 1] = 0;
285     }
286
287     close(fd);
288
289     return &parm;
290 }
291
292
293
294 int
295 setTunnelParm(char *ifname, struct ip_tunnel_parm *parm)
296 {
297     struct ifreq    ifrq;
298     int             fd;
299     int             err;
300
301     if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
302         return -1;
303     }
304
305     strcpy(ifrq.ifr_name, ifname);
306     ifrq.ifr_ifru.ifru_data = (void *) parm;
307     err = ioctl(fd, SIOCCHGTUNNEL, &ifrq);
308     close(fd);
309
310     return err;
311 }
312
313
314
315 /*
316  * update a struct tunnel. its index and ifname elements have to be set.
317  */
318 static struct tunnel *
319 updateTunnel(struct tunnel *tunnel)
320 {
321     struct ip_tunnel_parm *parm;
322     int             fd;
323     struct ifreq    ifrq;
324
325     /*
326      * NOTE: getTunnelParm() may adjust the passed ifname. 
327      */
328     parm = getTunnelParm(tunnel->ifname);
329     if (!parm) {
330         DEBUGMSGTL(("tunnel",
331                     "updateTunnel(): getTunnelParm(\"%s\") returned NULL\n",
332                     tunnel->ifname));
333         tunnel->active = 0;
334         return NULL;
335     }
336
337     tunnel->active = 1;
338
339     tunnel->local = parm->iph.saddr;
340     tunnel->remote = parm->iph.daddr;
341
342     if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
343         DEBUGMSGTL(("snmpd", "socket open failure in updateTunnels()\n"));
344         return NULL;
345     } else {
346         strcpy(ifrq.ifr_name, tunnel->ifname);
347         if (ioctl(fd, SIOCGIFHWADDR, &ifrq) == 0)
348             switch (ifrq.ifr_hwaddr.sa_family) {
349             case ARPHRD_TUNNEL:
350                 tunnel->encaps = 2;
351                 break;;         /* direct */
352             case ARPHRD_TUNNEL6:
353                 tunnel->encaps = 2;
354                 break;;         /* direct */
355             case ARPHRD_IPGRE:
356                 tunnel->encaps = 3;
357                 break;;         /* gre */
358             case ARPHRD_SIT:
359                 tunnel->encaps = 2;
360                 break;;         /* direct */
361             default:
362                 tunnel->encaps = 1;     /* other */
363             }
364         close(fd);
365     }
366
367     tunnel->hoplimit = parm->iph.ttl;
368     tunnel->security = 1;
369     tunnel->tos = (parm->iph.tos & 1) ? -1 : parm->iph.tos;
370     /*
371      * XXX: adjust tos mapping (kernel <-> TUNNEL-MIB::tunnelIfTOS) 
372      */
373
374     return tunnel;
375 }
376
377
378
379 static void
380 updateTunnels(void)
381 {
382     static int      max_index = 1;
383     static struct tunnel *last_tunnel = NULL;
384     struct tunnel  *tunnel;
385     char           *ifname;
386     int             type;
387
388     /*
389      * uptime the tunnels we have so far 
390      */
391     for (tunnel = tunnels; tunnel; tunnel = tunnel->next) {
392         DEBUGMSG(("tunnel",
393                   "updateTunnels(): updating %s (index=%d)\n",
394                   tunnel->ifname, tunnel->ifindex));
395         updateTunnel(tunnel);
396     }
397
398     /*
399      * look for new tunnels 
400      */
401     for (; max_index < 256; max_index++) {
402         DEBUGMSG(("tunnel",
403                   "updateTunnels(): looking for new index=%d\n",
404                   max_index));
405         type = getType(max_index);
406         if (type == 131) {
407             tunnel = (struct tunnel *) malloc(sizeof(struct tunnel));
408             if (!tunnel)
409                 continue;
410
411             tunnel->ifindex = max_index;
412             tunnel->id = 1;
413
414             ifname = getName(max_index);
415             if (!ifname) {
416                 free(tunnel);
417                 continue;
418             }
419
420             tunnel->ifname = strdup(ifname);
421             if (!tunnel->ifname) {
422                 free(tunnel);
423                 continue;
424             }
425
426             if (!updateTunnel(tunnel)) {
427                 free(tunnel);
428                 continue;
429             }
430
431             if (last_tunnel)
432                 last_tunnel->next = tunnel;
433             if (!tunnels)
434                 tunnels = last_tunnel = tunnel;
435             tunnel->next = NULL;
436             last_tunnel = tunnel;
437
438             DEBUGMSG(("tunnel",
439                       "updateTunnels(): added %s (index=%d state=%d)\n",
440                       tunnel->ifname, tunnel->ifindex, tunnel->active));
441         }
442         if (type == 0)
443             break;
444     }
445 }
446
447
448
449 static struct tunnel *
450 getTunnelByIfIndex(int index)
451 {
452     struct tunnel  *tunnel;
453
454     DEBUGMSG(("tunnel", "getTunnelByIfIndex(%d): ", index));
455
456     for (tunnel = tunnels; tunnel; tunnel = tunnel->next) {
457         if (tunnel->ifindex == index) {
458             if (!tunnel->active)
459                 break;
460             DEBUGMSG(("tunnel",
461                       "%s (index=%d)\n", tunnel->ifname, tunnel->ifindex));
462             return tunnel;
463         }
464     }
465     DEBUGMSG(("tunnel", "NONE\n"));
466     return NULL;
467 }
468
469
470
471 static struct tunnel *
472 getNextTunnelByIfIndex(int index)
473 {
474     struct tunnel  *tunnel;
475
476     DEBUGMSG(("tunnel", "getNextTunnelByIfIndex(%d): ", index));
477
478     for (tunnel = tunnels; tunnel; tunnel = tunnel->next) {
479         if (tunnel->ifindex > index) {
480             if (!tunnel->active)
481                 continue;
482             DEBUGMSG(("tunnel",
483                       "%s (index=%d)\n", tunnel->ifname, tunnel->ifindex));
484             return tunnel;
485         }
486     }
487     DEBUGMSG(("tunnel", "NONE\n"));
488     return NULL;
489 }
490
491
492
493 static void
494 fillConfigOid(oid * name, struct tunnel *tunnel)
495 {
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));
507 }
508
509
510
511 static struct tunnel *
512 getTunnelByConfigOid(oid * name, size_t * length)
513 {
514     struct tunnel  *tunnel;
515     oid             tname[4 + 4 + 1 + 1];
516
517     DEBUGMSG(("tunnel", "getTunnelByConfigOid(): "));
518
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)) {
524             if (!tunnel->active)
525                 break;
526             DEBUGMSG(("tunnel",
527                       "%s (index=%d)\n", tunnel->ifname, tunnel->ifindex));
528             return tunnel;
529         }
530     }
531     DEBUGMSG(("tunnel", "NONE\n"));
532     return NULL;
533 }
534
535
536
537 static struct tunnel *
538 getNextTunnelByConfigOid(oid * name, size_t * length)
539 {
540     struct tunnel  *tunnel, *last_tunnel;
541     oid             tname[10], last_tname[10];
542
543     DEBUGMSG(("tunnel", "getNextTunnelByConfigOid("));
544     DEBUGMSGOID(("tunnel", name, *length));
545     DEBUGMSG(("tunnel", "): "));
546
547     last_tunnel = NULL;
548     for (tunnel = tunnels; tunnel; tunnel = tunnel->next) {
549         if (!tunnel->active)
550             continue;
551         fillConfigOid(tname, tunnel);
552         if (snmp_oid_compare(tname, 10,
553                              &name[tunnel_len + 3],
554                              (*length) - tunnel_len - 3) > 0) {
555             if (!last_tunnel) {
556                 last_tunnel = tunnel;
557                 memcpy((char *) last_tname, (char *) tname,
558                        10 * sizeof(oid));
559             } else {
560                 if (snmp_oid_compare(tname, 10, last_tname, 10) < 0) {
561                     last_tunnel = tunnel;
562                     memcpy((char *) last_tname, (char *) tname,
563                            10 * sizeof(oid));
564                 }
565             }
566         }
567     }
568
569     if (last_tunnel) {
570         DEBUGMSG(("tunnel",
571                   "%s (index=%d)\n",
572                   last_tunnel->ifname, last_tunnel->ifindex));
573     } else {
574         DEBUGMSG(("tunnel", "NONE\n"));
575     }
576
577     return last_tunnel;
578 }
579
580
581
582 static int
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)
586 {
587     static struct tunnel *tunnel;
588     struct ip_tunnel_parm *parm;
589
590     switch (action) {
591     case RESERVE1:
592         if (var_val_type != ASN_IPADDRESS) {
593             return SNMP_ERR_WRONGTYPE;
594         }
595         if (var_val_len != 4) {
596             return SNMP_ERR_WRONGLENGTH;
597         }
598     case RESERVE2:
599         tunnel = getTunnelByIfIndex((int) name[name_len - 1]);
600         if (!tunnel) {
601             return SNMP_ERR_NOSUCHNAME;
602         }
603     case FREE:
604         break;
605     case ACTION:
606         break;
607     case UNDO:
608         break;
609     case COMMIT:
610         if (!tunnel) {
611             return SNMP_ERR_NOSUCHNAME;
612         }
613         parm = getTunnelParm(tunnel->ifname);
614         if (!parm) {
615             return SNMP_ERR_NOSUCHNAME;
616         }
617         parm->iph.saddr = *(unsigned long *) var_val;
618         setTunnelParm(tunnel->ifname, parm);
619         break;
620     }
621
622     return SNMP_ERR_NOERROR;
623 }
624
625
626
627 static int
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)
631 {
632     static struct tunnel *tunnel;
633     struct ip_tunnel_parm *parm;
634
635     switch (action) {
636     case RESERVE1:
637         if (var_val_type != ASN_IPADDRESS) {
638             return SNMP_ERR_WRONGTYPE;
639         }
640         if (var_val_len != 4) {
641             return SNMP_ERR_WRONGLENGTH;
642         }
643     case RESERVE2:
644         tunnel = getTunnelByIfIndex((int) name[name_len - 1]);
645         if (!tunnel) {
646             return SNMP_ERR_NOSUCHNAME;
647         }
648     case FREE:
649         break;
650     case ACTION:
651         break;
652     case UNDO:
653         break;
654     case COMMIT:
655         if (!tunnel) {
656             return SNMP_ERR_NOSUCHNAME;
657         }
658         parm = getTunnelParm(tunnel->ifname);
659         if (!parm) {
660             return SNMP_ERR_NOSUCHNAME;
661         }
662         parm->iph.daddr = *(unsigned long *) var_val;
663         setTunnelParm(tunnel->ifname, parm);
664         break;
665     }
666
667     return SNMP_ERR_NOERROR;
668 }
669
670
671
672 static int
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)
676 {
677     static struct tunnel *tunnel;
678     struct ip_tunnel_parm *parm;
679
680     switch (action) {
681     case RESERVE1:
682         if (var_val_type != ASN_INTEGER) {
683             return SNMP_ERR_WRONGTYPE;
684         }
685         if (var_val_len > sizeof(long)) {
686             return SNMP_ERR_WRONGLENGTH;
687         }
688     case RESERVE2:
689         tunnel = getTunnelByIfIndex((int) name[name_len - 1]);
690         if (!tunnel) {
691             return SNMP_ERR_NOSUCHNAME;
692         }
693     case FREE:
694         break;
695     case ACTION:
696         break;
697     case UNDO:
698         break;
699     case COMMIT:
700         if (!tunnel) {
701             return SNMP_ERR_NOSUCHNAME;
702         }
703         parm = getTunnelParm(tunnel->ifname);
704         if (!parm) {
705             return SNMP_ERR_NOSUCHNAME;
706         }
707         parm->iph.ttl = *(long *) var_val;
708         setTunnelParm(tunnel->ifname, parm);
709         break;
710     }
711
712     return SNMP_ERR_NOERROR;
713 }
714
715
716
717 static int
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)
721 {
722     static struct tunnel *tunnel;
723     struct ip_tunnel_parm *parm;
724
725     switch (action) {
726     case RESERVE1:
727         if (var_val_type != ASN_INTEGER) {
728             return SNMP_ERR_WRONGTYPE;
729         }
730         if (var_val_len > sizeof(long)) {
731             return SNMP_ERR_WRONGLENGTH;
732         }
733     case RESERVE2:
734         tunnel = getTunnelByIfIndex((int) name[name_len - 1]);
735         if (!tunnel) {
736             return SNMP_ERR_NOSUCHNAME;
737         }
738     case FREE:
739         break;
740     case ACTION:
741         break;
742     case UNDO:
743         break;
744     case COMMIT:
745         if (!tunnel) {
746             return SNMP_ERR_NOSUCHNAME;
747         }
748         parm = getTunnelParm(tunnel->ifname);
749         if (!parm) {
750             return SNMP_ERR_NOSUCHNAME;
751         }
752         /*
753          * this does not cover all meaningful values: 
754          */
755         parm->iph.tos = (*(long *) var_val == -1) ? 1 : *(long *) var_val;
756         setTunnelParm(tunnel->ifname, parm);
757         break;
758     }
759
760     return SNMP_ERR_NOERROR;
761 }
762
763
764
765 unsigned char  *
766 var_tunnelIfEntry(struct variable *vp,
767                   oid * name, size_t * length,
768                   int exact, size_t * var_len, WriteMethod ** write_method)
769 {
770     static unsigned long ret_addr;
771     static long     ret_int;
772     struct tunnel  *tunnel;
773
774     DEBUGMSGTL(("tunnel", "var_tunnelIfEntry: "));
775     DEBUGMSGOID(("tunnel", name, *length));
776     DEBUGMSG(("tunnel", " %d\n", exact));
777
778     updateTunnels();
779
780     if (exact) {
781         if (*length != tunnel_len + 3 + 1) {
782             return NULL;
783         }
784         tunnel = getTunnelByIfIndex((int) name[*length - 1]);
785     } else {
786         if ((*length) < tunnel_len) {
787             memcpy((char *) name, (char *) tunnel_variables_oid,
788                    tunnel_len * sizeof(oid));
789         }
790         if ((*length) < tunnel_len + 1) {
791             name[tunnel_len] = 1;
792         }
793         if ((*length) < tunnel_len + 2) {
794             name[tunnel_len + 1] = 1;
795         }
796         if ((*length) < tunnel_len + 3) {
797             name[tunnel_len + 2] = 1;
798         }
799         if ((*length) < tunnel_len + 4) {
800             name[tunnel_len + 3] = 0;
801         }
802         *length = tunnel_len + 4;
803
804         tunnel = getNextTunnelByIfIndex(name[*length - 1]);
805         if (!tunnel) {
806             /*
807              * end of column, continue with first row of next column 
808              */
809             tunnel = tunnels;
810             name[tunnel_len + 2]++;
811             if (name[tunnel_len + 2] > 6) {
812                 /*
813                  * there is no next column 
814                  */
815                 return NULL;
816             }
817             if (!tunnel) {
818                 /*
819                  * there is no (next) row 
820                  */
821                 return NULL;
822             }
823         }
824     }
825
826     if (!tunnel) {
827         return NULL;
828     }
829
830     name[*length - 1] = tunnel->ifindex;
831
832     DEBUGMSGTL(("tunnel", "var_tunnelIfEntry: using"));
833     DEBUGMSGOID(("tunnel", name, *length));
834     DEBUGMSG(("tunnel", "\n"));
835
836     switch (name[tunnel_len + 2]) {
837     case 1:                    /* tunnelIfLocalAddress */
838         ret_addr = tunnel->local;
839         *var_len = 4;
840         vp->type = ASN_IPADDRESS;
841         *write_method = writeLocalAddress;
842         return (u_char *) & ret_addr;
843     case 2:                    /* tunnelIfRemoteAddress */
844         ret_addr = tunnel->remote;
845         *var_len = 4;
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;
871     default:
872         return 0;
873     }
874
875     return NULL;
876 }
877
878
879
880 unsigned char  *
881 var_tunnelConfigEntry(struct variable *vp,
882                       oid * name, size_t * length,
883                       int exact, size_t * var_len,
884                       WriteMethod ** write_method)
885 {
886     static long     ret_int;
887     struct tunnel  *tunnel;
888     int             i;
889
890     DEBUGMSGTL(("tunnel", "var_tunnelConfigEntry: "));
891     DEBUGMSGOID(("tunnel", name, *length));
892     DEBUGMSG(("tunnel", " %d\n", exact));
893
894     updateTunnels();
895
896     if (exact) {
897         if (*length != tunnel_len + 3 + 4 + 4 + 1 + 1) {
898             return NULL;
899         }
900         tunnel = getTunnelByConfigOid(name, length);
901     } else {
902         if (snmp_oid_compare(name, *length,
903                              tunnel_configEntry_oid,
904                              tunnel_configEntry_len) < 0) {
905             *length = 0;
906         }
907         if ((*length) < tunnel_len) {
908             memcpy((char *) name, (char *) tunnel_variables_oid,
909                    tunnel_len * sizeof(oid));
910         }
911         if ((*length) < tunnel_len + 1) {
912             name[tunnel_len] = 2;
913         }
914         if ((*length) < tunnel_len + 2) {
915             name[tunnel_len + 1] = 1;
916         }
917         if ((*length) < tunnel_len + 3) {
918             name[tunnel_len + 2] = 5;
919         }
920         for (i = MAX(*length, tunnel_len + 3);
921              i < tunnel_len + 3 + 4 + 4 + 1 + 1; i++) {
922             name[i] = 0;
923         }
924         *length = tunnel_len + 3 + 4 + 4 + 1 + 1;
925         tunnel = getNextTunnelByConfigOid(name, length);
926         if (!tunnel) {
927             /*
928              * end of column, continue with first row of next column 
929              */
930             tunnel = tunnels;
931             name[tunnel_len + 2]++;
932             if (name[tunnel_len + 2] > 6) {
933                 /*
934                  * there is no next column 
935                  */
936                 return NULL;
937             }
938             if (!tunnel) {
939                 /*
940                  * there is no (next) row 
941                  */
942                 return NULL;
943             }
944         }
945     }
946
947     if (!tunnel) {
948         return NULL;
949     }
950
951     fillConfigOid(&name[tunnel_len + 3], tunnel);
952
953     DEBUGMSGTL(("tunnel", "var_tunnelConfigEntry: using "));
954     DEBUGMSGOID(("tunnel", name, *length));
955     DEBUGMSG(("tunnel", "\n"));
956
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;
968     default:
969         return 0;
970     }
971
972     return NULL;
973 }