# BRCM_VERSION=3
[bcm963xx.git] / userapps / opensource / net-snmp / agent / mibgroup / mibII / var_route.c
1 /*
2  * snmp_var_route.c - return a pointer to the named variable.
3  *
4  *
5  */
6 /***********************************************************
7         Copyright 1988, 1989 by Carnegie Mellon University
8         Copyright 1989  TGV, Incorporated
9
10                       All Rights Reserved
11
12 Permission to use, copy, modify, and distribute this software and its
13 documentation for any purpose and without fee is hereby granted,
14 provided that the above copyright notice appear in all copies and that
15 both that copyright notice and this permission notice appear in
16 supporting documentation, and that the name of CMU and TGV not be used
17 in advertising or publicity pertaining to distribution of the software
18 without specific, written prior permission.
19
20 CMU AND TGV DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
21 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
22 EVENT SHALL CMU OR TGV BE LIABLE FOR ANY SPECIAL, INDIRECT OR
23 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
24 USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
25 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
26 PERFORMANCE OF THIS SOFTWARE.
27 ******************************************************************/
28 /*
29  * additions, fixes and enhancements for Linux by Erik Schoenfelder
30  * (schoenfr@ibr.cs.tu-bs.de) 1994/1995.
31  * Linux additions taken from CMU to UCD stack by Jennifer Bray of Origin
32  * (jbray@origin-at.co.uk) 1997
33  * Support for system({CTL_NET,PF_ROUTE,...) by Simon Leinen
34  * (simon@switch.ch) 1997
35  */
36
37 #include <net-snmp/net-snmp-config.h>
38
39 #if !defined(CAN_USE_SYSCTL)
40
41 #define GATEWAY                 /* MultiNet is always configured this way! */
42 #include <stdio.h>
43 #include <sys/types.h>
44 #if HAVE_SYS_PARAM_H
45 #include <sys/param.h>
46 #endif
47 #if HAVE_SYS_SOCKET_H
48 #include <sys/socket.h>
49 #endif
50 #if TIME_WITH_SYS_TIME
51 # ifdef WIN32
52 #  include <sys/timeb.h>
53 # else
54 # include <sys/time.h>
55 # endif
56 # include <time.h>
57 #else
58 # if HAVE_SYS_TIME_H
59 #  include <sys/time.h>
60 # else
61 #  include <time.h>
62 # endif
63 #endif
64 #if HAVE_SYS_SELECT_H
65 #include <sys/select.h>
66 #endif
67 #if HAVE_NETINET_IN_H
68 #include <netinet/in.h>
69 #endif
70 #if HAVE_ARPA_INET_H
71 #include <arpa/inet.h>
72 #endif
73 #if HAVE_SYSLOG_H
74 #include <syslog.h>
75 #endif
76 #if HAVE_MACHINE_PARAM_H
77 #include <machine/param.h>
78 #endif
79 #if HAVE_SYS_MBUF_H
80 #include <sys/mbuf.h>
81 #endif
82 #if HAVE_NET_IF_H
83 #include <net/if.h>
84 #endif
85 #ifdef HAVE_NET_IF_VAR_H
86 #include <net/if_var.h>
87 #endif
88 #if HAVE_SYS_HASHING_H
89 #include <sys/hashing.h>
90 #endif
91 #if HAVE_NETINET_IN_VAR_H
92 #include <netinet/in_var.h>
93 #endif
94 #define KERNEL                  /* to get routehash and RTHASHSIZ */
95 #if HAVE_SYS_STREAM_H
96 #include <sys/stream.h>
97 #endif
98 #if HAVE_NET_ROUTE_H
99 #include <net/route.h>
100 #endif
101 #undef  KERNEL
102 #ifdef RTENTRY_4_4
103 #ifndef STRUCT_RTENTRY_HAS_RT_UNIT
104 #define rt_unit rt_refcnt       /* Reuse this field for device # */
105 #endif
106 #ifndef STRUCT_RTENTRY_HAS_RT_DST
107 #define rt_dst rt_nodes->rn_key
108 #endif
109 #else                           /* RTENTRY_4_3 */
110 #ifndef STRUCT_RTENTRY_HAS_RT_DST
111 #define rt_dst rt_nodes->rn_key
112 #endif
113 #ifndef STRUCT_RTENTRY_HAS_RT_HASH
114 #define rt_hash rt_pad1
115 #endif
116 #ifndef STRUCT_RTENTRY_HAS_RT_REFCNT
117 #ifndef hpux10
118 #define rt_refcnt rt_pad2
119 #endif
120 #endif
121 #ifndef STRUCT_RTENTRY_HAS_RT_USE
122 #define rt_use rt_pad3
123 #endif
124 #ifndef STRUCT_RTENTRY_HAS_RT_UNIT
125 #define rt_unit rt_refcnt       /* Reuse this field for device # */
126 #endif
127 #endif
128 #ifndef NULL
129 #define NULL 0
130 #endif
131 #if HAVE_KVM_OPENFILES
132 #include <fcntl.h>
133 #endif
134 #if HAVE_KVM_H
135 #include <kvm.h>
136 #endif
137
138 #if HAVE_STRING_H
139 #include <string.h>
140 #else
141 #include <strings.h>
142 #endif
143 #if HAVE_STDLIB_H
144 #include <stdlib.h>
145 #endif
146 #if HAVE_INET_MIB2_H
147 #include <inet/mib2.h>
148 #endif
149 #if HAVE_SYS_SYSCTL_H
150 #include <sys/sysctl.h>
151 #endif
152 #if HAVE_NET_IF_DL_H
153 #ifndef dynix
154 #include <net/if_dl.h>
155 #else
156 #include <sys/net/if_dl.h>
157 #endif
158 #endif
159
160 #if HAVE_WINSOCK_H
161 #include <winsock.h>
162 #endif
163
164 #if HAVE_NLIST_H
165 #include <nlist.h>
166 #endif
167
168 #if solaris2
169 #include "kernel_sunos5.h"
170 #endif
171
172 #ifdef HAVE_SYS_SYSCTL_H
173 # ifdef CTL_NET
174 #  ifdef PF_ROUTE
175 #   ifdef NET_RT_DUMP
176 #    define USE_SYSCTL_ROUTE_DUMP
177 #   endif
178 #  endif
179 # endif
180 #endif
181
182 #if HAVE_DMALLOC_H
183 #include <dmalloc.h>
184 #endif
185
186 #ifdef cygwin
187 #define WIN32
188 #include <windows.h>
189 #endif
190
191 #define CACHE_TIME (120)        /* Seconds */
192
193 #include <net-snmp/net-snmp-includes.h>
194 #include <net-snmp/agent/net-snmp-agent-includes.h>
195 #include <net-snmp/agent/auto_nlist.h>
196
197 #include "ip.h"
198 #include "kernel.h"
199 #include "interfaces.h"
200 #include "struct.h"
201 #include "util_funcs.h"
202
203 #ifndef  MIN
204 #define  MIN(a,b)                     (((a) < (b)) ? (a) : (b))
205 #endif
206
207 #ifdef hpux11
208 #include <sys/mib.h>
209 #include <netinet/mib_kern.h>
210 #endif                          /* hpux */
211
212 extern WriteMethod write_rte;
213
214 #ifndef WIN32
215
216 #ifdef USE_SYSCTL_ROUTE_DUMP
217
218 static void     Route_Scan_Reload(void);
219
220 static unsigned char *all_routes = 0;
221 static unsigned char *all_routes_end;
222 static size_t   all_routes_size;
223
224 extern const struct sockaddr *get_address(const void *, int, int);
225 extern const struct in_addr *get_in_address(const void *, int, int);
226
227 /*
228  * var_ipRouteEntry(...
229  * Arguments:
230  * vp           IN      - pointer to variable entry that points here
231  * name          IN/OUT  - IN/name requested, OUT/name found
232  * length        IN/OUT  - length of IN/OUT oid's 
233  * exact         IN      - TRUE if an exact match was requested
234  * var_len       OUT     - length of variable or 0 if function returned
235  * write_method  out     - pointer to function to set variable, otherwise 0
236  */
237 u_char         *
238 var_ipRouteEntry(struct variable *vp,
239                  oid * name,
240                  size_t * length,
241                  int exact, size_t * var_len, WriteMethod ** write_method)
242 {
243     /*
244      * object identifier is of form:
245      * 1.3.6.1.2.1.4.21.1.1.A.B.C.D,  where A.B.C.D is IP address.
246      * IPADDR starts at offset 10.
247      */
248     struct rt_msghdr *rtp, *saveRtp = 0;
249     register int    Save_Valid, result;
250     static int      saveNameLen = 0, saveExact = 0;
251     static oid      saveName[MAX_OID_LEN], Current[MAX_OID_LEN];
252     u_char         *cp;
253     u_char         *ap;
254     oid            *op;
255 #if 0
256   /** 
257   ** this optimisation fails, if there is only a single route avail.
258   ** it is a very special case, but better leave it out ...
259   **/
260 #if 0
261     if (rtsize <= 1)
262         Save_Valid = 0;
263     else
264 #endif                          /* 0 */
265         /*
266          *  OPTIMIZATION:
267          *
268          *  If the name was the same as the last name, with the possible
269          *  exception of the [9]th token, then don't read the routing table
270          *
271          */
272
273     if ((saveNameLen == *length) && (saveExact == exact)) {
274         register int    temp = name[9];
275         name[9] = 0;
276         Save_Valid =
277             (snmp_oid_compare(name, *length, saveName, saveNameLen) == 0);
278         name[9] = temp;
279     } else
280         Save_Valid = 0;
281
282     if (Save_Valid && saveRtp) {
283         register int    temp = name[9]; /* Fix up 'lowest' found entry */
284         memcpy((char *) name, (char *) Current, 14 * sizeof(oid));
285         name[9] = temp;
286         *length = 14;
287         rtp = saveRtp;
288     } else {
289 #endif                          /* 0 */
290         /*
291          * fill in object part of name for current (less sizeof instance part) 
292          */
293
294         memcpy((char *) Current, (char *) vp->name,
295                (int) (vp->namelen) * sizeof(oid));
296
297 #if 0
298         /*
299          *  Only reload if this is the start of a wildcard
300          */
301         if (*length < 14) {
302             Route_Scan_Reload();
303         }
304 #else
305         Route_Scan_Reload();
306 #endif
307         for (ap = all_routes; ap < all_routes_end; ap += rtp->rtm_msglen) {
308             rtp = (struct rt_msghdr *) ap;
309             if (rtp->rtm_type == 0)
310                 break;
311             if (rtp->rtm_version != RTM_VERSION) {
312                 snmp_log(LOG_ERR,
313                          "routing socket message version mismatch (%d instead of %d)\n",
314                          rtp->rtm_version, RTM_VERSION);
315                 break;
316             }
317             if (rtp->rtm_type != RTM_GET) {
318                 snmp_log(LOG_ERR,
319                          "routing socket returned message other than GET (%d)\n",
320                          rtp->rtm_type);
321                 continue;
322             }
323             if (!(rtp->rtm_addrs & RTA_DST))
324                 continue;
325             cp = (u_char *) get_in_address((struct sockaddr *) (rtp + 1),
326                                            rtp->rtm_addrs, RTA_DST);
327             if (cp == NULL)
328                 return NULL;
329
330             op = Current + 10;
331             *op++ = *cp++;
332             *op++ = *cp++;
333             *op++ = *cp++;
334             *op++ = *cp++;
335
336             result = snmp_oid_compare(name, *length, Current, 14);
337             if ((exact && (result == 0)) || (!exact && (result < 0)))
338                 break;
339         }
340         if (ap >= all_routes_end || rtp->rtm_type == 0)
341             return 0;
342         /*
343          *  Save in the 'cache'
344          */
345         memcpy((char *) saveName, (char *) name,
346                SNMP_MIN(*length, MAX_OID_LEN) * sizeof(oid));
347         saveName[9] = '\0';
348         saveNameLen = *length;
349         saveExact = exact;
350         saveRtp = rtp;
351         /*
352          *  Return the name
353          */
354         memcpy((char *) name, (char *) Current, 14 * sizeof(oid));
355         *length = 14;
356 #if 0
357     }
358 #endif                          /* 0 */
359
360     *write_method = write_rte;
361     *var_len = sizeof(long_return);
362
363     switch (vp->magic) {
364     case IPROUTEDEST:
365         return (u_char *) get_in_address((struct sockaddr *) (rtp + 1),
366                                          rtp->rtm_addrs, RTA_DST);
367     case IPROUTEIFINDEX:
368         long_return = (u_long) rtp->rtm_index;
369         return (u_char *) & long_return;
370     case IPROUTEMETRIC1:
371         long_return = (rtp->rtm_flags & RTF_UP) ? 1 : 0;
372         return (u_char *) & long_return;
373     case IPROUTEMETRIC2:
374 #if NO_DUMMY_VALUES
375         return NULL;
376 #endif
377         long_return = -1;
378         return (u_char *) & long_return;
379     case IPROUTEMETRIC3:
380 #if NO_DUMMY_VALUES
381         return NULL;
382 #endif
383         long_return = -1;
384         return (u_char *) & long_return;
385     case IPROUTEMETRIC4:
386 #if NO_DUMMY_VALUES
387         return NULL;
388 #endif
389         long_return = -1;
390         return (u_char *) & long_return;
391     case IPROUTEMETRIC5:
392 #if NO_DUMMY_VALUES
393         return NULL;
394 #endif
395         long_return = -1;
396         return (u_char *) & long_return;
397     case IPROUTENEXTHOP:
398         return (u_char *) get_in_address((struct sockaddr *) (rtp + 1),
399                                          rtp->rtm_addrs, RTA_GATEWAY);
400     case IPROUTETYPE:
401         if (rtp->rtm_flags & RTF_UP) {
402             if (rtp->rtm_flags & RTF_GATEWAY) {
403                 long_return = 4;        /*  indirect(4)  */
404             } else {
405                 long_return = 3;        /*  direct(3)  */
406             }
407         } else {
408             long_return = 2;    /*  invalid(2)  */
409         }
410         return (u_char *) & long_return;
411     case IPROUTEPROTO:
412         long_return = (rtp->rtm_flags & RTF_DYNAMIC)
413             ? 10 : (rtp->rtm_flags & RTF_STATIC)
414             ? 2 : (rtp->rtm_flags & RTF_DYNAMIC) ? 4 : 1;
415         return (u_char *) & long_return;
416     case IPROUTEAGE:
417 #if NO_DUMMY_VALUES
418         return NULL;
419 #endif
420         long_return = 0;
421         return (u_char *) & long_return;
422     case IPROUTEMASK:
423         if (rtp->rtm_flags & RTF_HOST) {
424             long_return = 0x00000001;
425             return (u_char *) & long_return;
426         } else {
427             return (u_char *) get_in_address((struct sockaddr *) (rtp + 1),
428                                              rtp->rtm_addrs, RTA_NETMASK);
429         }
430     case IPROUTEINFO:
431         *var_len = nullOidLen;
432         return (u_char *) nullOid;
433     default:
434         DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ipRouteEntry\n",
435                     vp->magic));
436     }
437     return NULL;
438 }
439
440 #else                           /* not USE_SYSCTL_ROUTE_DUMP */
441
442 static void     Route_Scan_Reload(void);
443
444 #ifdef hpux11
445 static int      rtsize = 0;
446 static mib_ipRouteEnt *rt = (mib_ipRouteEnt *) 0;
447 #else                           /* hpux11 */
448 static RTENTRY **rthead = 0;
449 static int      rtsize = 0, rtallocate = 0;
450 #endif                          /* hpux11 */
451
452 #if !(defined(linux) || defined(solaris2) || defined(hpux11))
453 #define NUM_ROUTE_SYMBOLS 2
454 static char    *route_symbols[] = {
455     RTHOST_SYMBOL,
456     RTNET_SYMBOL
457 };
458 #endif
459 #endif
460
461 #ifdef USE_SYSCTL_ROUTE_DUMP
462
463 void
464 init_var_route(void)
465 {
466 #ifdef solaris2
467     init_kernel_sunos5();
468 #endif
469 }
470
471 static void
472 Route_Scan_Reload(void)
473 {
474     size_t          size = 0;
475     int             name[] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_DUMP, 0 };
476
477     if (sysctl(name, sizeof(name) / sizeof(int), 0, &size, 0, 0) == -1) {
478         snmp_log(LOG_ERR, "sysctl(CTL_NET,PF_ROUTE,0,0,NET_RT_DUMP,0)\n");
479     } else {
480         if (all_routes == 0 || all_routes_size < size) {
481             if (all_routes != 0) {
482                 free(all_routes);
483                 all_routes = 0;
484             }
485             if ((all_routes = malloc(size)) == 0) {
486                 snmp_log(LOG_ERR,
487                          "out of memory allocating route table\n");
488             }
489             all_routes_size = size;
490         } else {
491             size = all_routes_size;
492         }
493         if (sysctl(name, sizeof(name) / sizeof(int),
494                    all_routes, &size, 0, 0) == -1) {
495             snmp_log(LOG_ERR,
496                      "sysctl(CTL_NET,PF_ROUTE,0,0,NET_RT_DUMP,0)\n");
497         }
498         all_routes_end = all_routes + size;
499     }
500 }
501
502 #else                           /* not USE_SYSCTL_ROUTE_DUMP */
503
504 void
505 init_var_route(void)
506 {
507 #ifdef RTTABLES_SYMBOL
508     auto_nlist(RTTABLES_SYMBOL, 0, 0);
509 #endif
510 #ifdef RTHASHSIZE_SYMBOL
511     auto_nlist(RTHASHSIZE_SYMBOL, 0, 0);
512 #endif
513 #ifdef RTHOST_SYMBOL
514     auto_nlist(RTHOST_SYMBOL, 0, 0);
515 #endif
516 #ifdef RTNET_SYMBOL
517     auto_nlist(RTNET_SYMBOL, 0, 0);
518 #endif
519 }
520
521 #ifndef solaris2
522
523 #if NEED_KLGETSA
524 static union {
525     struct sockaddr_in sin;
526     u_short         data[128];
527 } klgetsatmp;
528
529 struct sockaddr_in *
530 klgetsa(struct sockaddr_in *dst)
531 {
532     klookup((u_long) dst, (char *) &klgetsatmp.sin, sizeof klgetsatmp.sin);
533     if (klgetsatmp.sin.sin_len > sizeof(klgetsatmp.sin))
534         klookup((u_long) dst, (char *) &klgetsatmp.sin,
535                 klgetsatmp.sin.sin_len);
536     return (&klgetsatmp.sin);
537 }
538 #endif
539
540 u_char         *
541 var_ipRouteEntry(struct variable * vp,
542                  oid * name,
543                  size_t * length,
544                  int exact, size_t * var_len, WriteMethod ** write_method)
545 {
546     /*
547      * object identifier is of form:
548      * 1.3.6.1.2.1.4.21.1.1.A.B.C.D,  where A.B.C.D is IP address.
549      * IPADDR starts at offset 10.
550      */
551     register int    Save_Valid, result, RtIndex;
552     static int      saveNameLen = 0, saveExact = 0, saveRtIndex = 0;
553     static oid      saveName[MAX_OID_LEN], Current[MAX_OID_LEN];
554     u_char         *cp;
555     oid            *op;
556 #if NEED_KLGETSA
557     struct sockaddr_in *sa;
558 #endif
559 #if !defined(linux) && !defined(hpux11)
560     struct ifnet    rt_ifnet;
561     struct in_ifaddr rt_ifnetaddr;
562 #endif
563     /** 
564      ** this optimisation fails, if there is only a single route avail.
565      ** it is a very special case, but better leave it out ...
566      **/
567 #if NO_DUMMY_VALUES
568     saveNameLen = 0;
569 #endif
570
571     if (rtsize <= 1)
572         Save_Valid = 0;
573     else
574         /*
575          *  OPTIMIZATION:
576          *
577          *  If the name was the same as the last name, with the possible
578          *  exception of the [9]th token, then don't read the routing table
579          *
580          */
581
582     if ((saveNameLen == *length) && (saveExact == exact)) {
583         register int    temp = name[9];
584         name[9] = 0;
585         Save_Valid =
586             (snmp_oid_compare(name, *length, saveName, saveNameLen) == 0);
587         name[9] = temp;
588     } else
589         Save_Valid = 0;
590
591     if (Save_Valid) {
592         register int    temp = name[9]; /* Fix up 'lowest' found entry */
593         memcpy((char *) name, (char *) Current, 14 * sizeof(oid));
594         name[9] = temp;
595         *length = 14;
596         RtIndex = saveRtIndex;
597     } else {
598         /*
599          * fill in object part of name for current (less sizeof instance part) 
600          */
601
602         memcpy((char *) Current, (char *) vp->name,
603                (int) (vp->namelen) * sizeof(oid));
604
605 #if 0
606         /*
607          *  Only reload if this is the start of a wildcard
608          */
609         if (*length < 14) {
610             Route_Scan_Reload();
611         }
612 #else
613         Route_Scan_Reload();
614 #endif
615         for (RtIndex = 0; RtIndex < rtsize; RtIndex++) {
616 #if NEED_KLGETSA
617             sa = klgetsa((struct sockaddr_in *) rthead[RtIndex]->rt_dst);
618             cp = (u_char *) & (sa->sin_addr.s_addr);
619 #elif defined(hpux11)
620             cp = (u_char *) & rt[RtIndex].Dest;
621 #else
622             cp = (u_char *) &
623                 (((struct sockaddr_in *) &(rthead[RtIndex]->rt_dst))->
624                  sin_addr.s_addr);
625 #endif
626             op = Current + 10;
627             *op++ = *cp++;
628             *op++ = *cp++;
629             *op++ = *cp++;
630             *op++ = *cp++;
631
632             result = snmp_oid_compare(name, *length, Current, 14);
633             if ((exact && (result == 0)) || (!exact && (result < 0)))
634                 break;
635         }
636         if (RtIndex >= rtsize)
637             return (NULL);
638         /*
639          *  Save in the 'cache'
640          */
641         memcpy((char *) saveName, (char *) name,
642                SNMP_MIN(*length, MAX_OID_LEN) * sizeof(oid));
643         saveName[9] = 0;
644         saveNameLen = *length;
645         saveExact = exact;
646         saveRtIndex = RtIndex;
647         /*
648          *  Return the name
649          */
650         memcpy((char *) name, (char *) Current, 14 * sizeof(oid));
651         *length = 14;
652     }
653
654 #ifdef BRCM_SNMP_WRITE_SUPPORT
655     *write_method = write_rte;
656 #else
657     *write_method = NULL;
658 #endif
659     *var_len = sizeof(long_return);
660
661     switch (vp->magic) {
662     case IPROUTEDEST:
663 #if NEED_KLGETSA
664         sa = klgetsa((struct sockaddr_in *) rthead[RtIndex]->rt_dst);
665         return (u_char *) & (sa->sin_addr.s_addr);
666 #elif defined(hpux11)
667         long_return = rt[RtIndex].Dest;
668         return (u_char *) & long_return;
669 #else
670         return (u_char *) & ((struct sockaddr_in *) &rthead[RtIndex]->
671                              rt_dst)->sin_addr.s_addr;
672 #endif
673     case IPROUTEIFINDEX:
674 #ifdef hpux11
675         long_return = rt[RtIndex].IfIndex;
676 #else
677         long_return = (u_long) rthead[RtIndex]->rt_unit;
678 #endif
679         return (u_char *) & long_return;
680     case IPROUTEMETRIC1:
681 #ifdef hpux11
682         long_return = rt[RtIndex].Metric1;
683 #else
684         long_return = (rthead[RtIndex]->rt_flags & RTF_GATEWAY) ? 1 : 0;
685 #endif
686         return (u_char *) & long_return;
687     case IPROUTEMETRIC2:
688 #ifdef hpux11
689         long_return = rt[RtIndex].Metric2;
690         return (u_char *) & long_return;
691 #elif defined(NO_DUMMY_VALUES)
692         return NULL;
693 #endif
694         long_return = -1;
695         return (u_char *) & long_return;
696     case IPROUTEMETRIC3:
697 #ifdef hpux11
698         long_return = rt[RtIndex].Metric3;
699         return (u_char *) & long_return;
700 #elif defined(NO_DUMMY_VALUES)
701         return NULL;
702 #endif
703         long_return = -1;
704         return (u_char *) & long_return;
705     case IPROUTEMETRIC4:
706 #ifdef hpux11
707         long_return = rt[RtIndex].Metric4;
708         return (u_char *) & long_return;
709 #elif defined(NO_DUMMY_VALUES)
710         return NULL;
711 #endif
712         long_return = -1;
713         return (u_char *) & long_return;
714     case IPROUTEMETRIC5:
715 #if NO_DUMMY_VALUES
716         return NULL;
717 #endif
718         long_return = -1;
719         return (u_char *) & long_return;
720     case IPROUTENEXTHOP:
721 #if NEED_KLGETSA
722         sa = klgetsa((struct sockaddr_in *) rthead[RtIndex]->rt_gateway);
723         return (u_char *) & (sa->sin_addr.s_addr);
724 #elif defined(hpux11)
725         long_return = rt[RtIndex].NextHop;
726         return (u_char *) & long_return;
727 #else
728         return (u_char *) & ((struct sockaddr_in *) &rthead[RtIndex]->
729                              rt_gateway)->sin_addr.s_addr;
730 #endif                          /* *bsd */
731     case IPROUTETYPE:
732 #ifdef hpux11
733         long_return = rt[RtIndex].Type;
734 #else
735         if (rthead[RtIndex]->rt_flags & RTF_UP) {
736             if (rthead[RtIndex]->rt_flags & RTF_GATEWAY) {
737                 long_return = 4;        /*  indirect(4)  */
738             } else {
739                 long_return = 3;        /*  direct(3)  */
740             }
741         } else {
742             long_return = 2;    /*  invalid(2)  */
743         }
744 #endif
745         return (u_char *) & long_return;
746     case IPROUTEPROTO:
747 #ifdef hpux11
748         long_return = rt[RtIndex].Proto;
749 #else
750         long_return = (rthead[RtIndex]->rt_flags & RTF_DYNAMIC) ? 4 : 2;
751 #endif
752         return (u_char *) & long_return;
753     case IPROUTEAGE:
754 #ifdef hpux11
755         long_return = rt[RtIndex].Age;
756         return (u_char *) & long_return;
757 #elif defined(NO_DUMMY_VALUES)
758         return NULL;
759 #endif
760         long_return = 0;
761         return (u_char *) & long_return;
762     case IPROUTEMASK:
763 #if NEED_KLGETSA
764         /*
765          * XXX - Almost certainly not right
766          * but I don't have a suitable system to test this on 
767          */
768 #if NO_DUMMY_VALUES
769         return NULL;
770 #endif
771         long_return = 0;
772 #elif defined(hpux11)
773         long_return = rt[RtIndex].Mask;
774         return (u_char *) & long_return;
775 #else                           /* !NEED_KLGETSA && !hpux11 */
776         if (((struct sockaddr_in *) &rthead[RtIndex]->rt_dst)->sin_addr.
777             s_addr == 0)
778             long_return = 0;    /* Default route */
779         else {
780 #ifndef linux
781             klookup((unsigned long) rthead[RtIndex]->rt_ifp,
782                     (char *) &rt_ifnet, sizeof(rt_ifnet));
783             klookup((unsigned long) rt_ifnet.if_addrlist,
784                     (char *) &rt_ifnetaddr, sizeof(rt_ifnetaddr));
785
786             long_return = rt_ifnetaddr.ia_subnetmask;
787 #else                           /* linux */
788             cp = (u_char *) &
789                 (((struct sockaddr_in *) &(rthead[RtIndex]->rt_dst))->
790                  sin_addr.s_addr);
791             return (u_char *) &
792                 (((struct sockaddr_in *) &(rthead[RtIndex]->rt_genmask))->
793                  sin_addr.s_addr);
794 #endif                          /* linux */
795         }
796 #endif                          /* NEED_KLGETSA */
797         return (u_char *) & long_return;
798     case IPROUTEINFO:
799         *var_len = nullOidLen;
800         return (u_char *) nullOid;
801     default:
802         DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ipRouteEntry\n",
803                     vp->magic));
804     }
805     return NULL;
806 }
807
808 #else                           /* solaris2 */
809
810 static int
811 IP_Cmp_Route(void *addr, void *ep)
812 {
813     mib2_ipRouteEntry_t *Ep = ep, *Addr = addr;
814
815     if ((Ep->ipRouteDest == Addr->ipRouteDest) &&
816         (Ep->ipRouteNextHop == Addr->ipRouteNextHop) &&
817         (Ep->ipRouteType == Addr->ipRouteType) &&
818         (Ep->ipRouteProto == Addr->ipRouteProto) &&
819         (Ep->ipRouteMask == Addr->ipRouteMask) &&
820         (Ep->ipRouteInfo.re_max_frag == Addr->ipRouteInfo.re_max_frag) &&
821         (Ep->ipRouteInfo.re_rtt == Addr->ipRouteInfo.re_rtt) &&
822         (Ep->ipRouteInfo.re_ref == Addr->ipRouteInfo.re_ref) &&
823         (Ep->ipRouteInfo.re_frag_flag == Addr->ipRouteInfo.re_frag_flag) &&
824         (Ep->ipRouteInfo.re_src_addr == Addr->ipRouteInfo.re_src_addr) &&
825         (Ep->ipRouteInfo.re_ire_type == Addr->ipRouteInfo.re_ire_type) &&
826         (Ep->ipRouteInfo.re_obpkt == Addr->ipRouteInfo.re_obpkt) &&
827         (Ep->ipRouteInfo.re_ibpkt == Addr->ipRouteInfo.re_ibpkt)
828         )
829         return (0);
830     else
831         return (1);             /* Not found */
832 }
833
834 u_char         *
835 var_ipRouteEntry(struct variable * vp,
836                  oid * name,
837                  size_t * length,
838                  int exact, size_t * var_len, WriteMethod ** write_method)
839 {
840     /*
841      * object identifier is of form:
842      * 1.3.6.1.2.1.4.21.1.1.A.B.C.D,  where A.B.C.D is IP address.
843      * IPADDR starts at offset 10.
844      */
845 #define IP_ROUTENAME_LENGTH     14
846 #define IP_ROUTEADDR_OFF        10
847     oid             current[IP_ROUTENAME_LENGTH],
848         lowest[IP_ROUTENAME_LENGTH];
849     u_char         *cp;
850     oid            *op;
851     mib2_ipRouteEntry_t Lowentry, Nextentry, entry;
852     int             Found = 0;
853     req_e           req_type;
854
855     /*
856      * fill in object part of name for current (less sizeof instance part) 
857      */
858
859     memcpy((char *) current, (char *) vp->name, vp->namelen * sizeof(oid));
860     if (*length == IP_ROUTENAME_LENGTH) /* Assume that the input name is the lowest */
861         memcpy((char *) lowest, (char *) name,
862                IP_ROUTENAME_LENGTH * sizeof(oid));
863     else
864         name[IP_ROUTEADDR_OFF] = (oid) - 1;     /* Grhhh: to prevent accidental comparison :-( */
865     for (Nextentry.ipRouteDest = (u_long) - 2, req_type = GET_FIRST;;
866          Nextentry = entry, req_type = GET_NEXT) {
867         if (getMibstat(MIB_IP_ROUTE, &entry, sizeof(mib2_ipRouteEntry_t),
868                        req_type, &IP_Cmp_Route, &Nextentry) != 0)
869             break;
870         COPY_IPADDR(cp, (u_char *) & entry.ipRouteDest, op,
871                     current + IP_ROUTEADDR_OFF);
872         if (exact) {
873             if (snmp_oid_compare
874                 (current, IP_ROUTENAME_LENGTH, name, *length) == 0) {
875                 memcpy((char *) lowest, (char *) current,
876                        IP_ROUTENAME_LENGTH * sizeof(oid));
877                 Lowentry = entry;
878                 Found++;
879                 break;          /* no need to search further */
880             }
881         } else {
882             if ((snmp_oid_compare
883                  (current, IP_ROUTENAME_LENGTH, name, *length) > 0)
884                 && ((Nextentry.ipRouteDest == (u_long) - 2)
885                     ||
886                     (snmp_oid_compare
887                      (current, IP_ROUTENAME_LENGTH, lowest,
888                       IP_ROUTENAME_LENGTH) < 0)
889                     ||
890                     (snmp_oid_compare
891                      (name, IP_ROUTENAME_LENGTH, lowest,
892                       IP_ROUTENAME_LENGTH) == 0))) {
893
894                 /*
895                  * if new one is greater than input and closer to input than
896                  * * previous lowest, and is not equal to it, save this one as the "next" one.
897                  */
898                 memcpy((char *) lowest, (char *) current,
899                        IP_ROUTENAME_LENGTH * sizeof(oid));
900                 Lowentry = entry;
901                 Found++;
902             }
903         }
904     }
905     if (Found == 0)
906         return (NULL);
907     memcpy((char *) name, (char *) lowest,
908            IP_ROUTENAME_LENGTH * sizeof(oid));
909     *length = IP_ROUTENAME_LENGTH;
910     *write_method = write_rte;
911     *var_len = sizeof(long_return);
912
913     switch (vp->magic) {
914     case IPROUTEDEST:
915         long_return = Lowentry.ipRouteDest;
916         return (u_char *) & long_return;
917     case IPROUTEIFINDEX:
918         long_return =
919             Interface_Index_By_Name(Lowentry.ipRouteIfIndex.o_bytes,
920                                     Lowentry.ipRouteIfIndex.o_length);
921         return (u_char *) & long_return;
922     case IPROUTEMETRIC1:
923         long_return = Lowentry.ipRouteMetric1;
924         return (u_char *) & long_return;
925     case IPROUTEMETRIC2:
926         long_return = Lowentry.ipRouteMetric2;
927         return (u_char *) & long_return;
928     case IPROUTEMETRIC3:
929         long_return = Lowentry.ipRouteMetric3;
930         return (u_char *) & long_return;
931     case IPROUTEMETRIC4:
932         long_return = Lowentry.ipRouteMetric4;
933         return (u_char *) & long_return;
934     case IPROUTENEXTHOP:
935         long_return = Lowentry.ipRouteNextHop;
936         return (u_char *) & long_return;
937     case IPROUTETYPE:
938         long_return = Lowentry.ipRouteType;
939         return (u_char *) & long_return;
940     case IPROUTEPROTO:
941         long_return = Lowentry.ipRouteProto;
942         if (long_return == -1)
943             long_return = 1;
944         return (u_char *) & long_return;
945     case IPROUTEAGE:
946         long_return = Lowentry.ipRouteAge;
947         return (u_char *) & long_return;
948     case IPROUTEMASK:
949         long_return = Lowentry.ipRouteMask;
950         return (u_char *) & long_return;
951     default:
952         DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ipRouteEntry\n",
953                     vp->magic));
954     };
955     return NULL;
956 }
957
958 #endif                          /* solaris2 - var_IProute */
959
960 #ifndef solaris2
961 static int      qsort_compare(const void *, const void *);
962 #endif
963
964 #if defined(RTENTRY_4_4) || defined(RTENTRY_RT_NEXT)
965
966 #if defined(RTENTRY_4_4) && !defined(hpux11)
967 void
968 load_rtentries(struct radix_node *pt)
969 {
970     struct radix_node node;
971     RTENTRY         rt;
972     struct ifnet    ifnet;
973     char            name[16], temp[16];
974 #if !STRUCT_IFNET_HAS_IF_XNAME
975     register char  *cp;
976 #endif
977
978     if (!klookup
979         ((unsigned long) pt, (char *) &node, sizeof(struct radix_node))) {
980         DEBUGMSGTL(("mibII/var_route", "Fail\n"));
981         return;
982     }
983     if (node.rn_b >= 0) {
984         load_rtentries(node.rn_r);
985         load_rtentries(node.rn_l);
986     } else {
987         if (node.rn_flags & RNF_ROOT) {
988             /*
989              * root node 
990              */
991             if (node.rn_dupedkey)
992                 load_rtentries(node.rn_dupedkey);
993             return;
994         }
995         /*
996          * get the route 
997          */
998         klookup((unsigned long) pt, (char *) &rt, sizeof(RTENTRY));
999
1000         if (rt.rt_ifp != 0) {
1001             klookup((unsigned long) rt.rt_ifp, (char *) &ifnet,
1002                     sizeof(ifnet));
1003 #if STRUCT_IFNET_HAS_IF_XNAME
1004 #if defined(netbsd1) || defined(openbsd2)
1005             strncpy(name, ifnet.if_xname, sizeof name);
1006 #else
1007             klookup((unsigned long) ifnet.if_xname, name, sizeof name);
1008 #endif
1009             name[sizeof(name) - 1] = '\0';
1010 #else
1011             klookup((unsigned long) ifnet.if_name, name, sizeof name);
1012             name[sizeof(name) - 1] = '\0';
1013             cp = (char *) strchr(name, '\0');
1014             string_append_int(cp, ifnet.if_unit);
1015 #endif
1016             Interface_Scan_Init();
1017             rt.rt_unit = 0;
1018             while (Interface_Scan_Next
1019                    ((short *) &(rt.rt_unit), temp, NULL, NULL) != 0) {
1020                 if (strcmp(name, temp) == 0)
1021                     break;
1022             }
1023         }
1024 #if CHECK_RT_FLAGS
1025         if (((rt.rt_flags & RTF_CLONING) != RTF_CLONING)
1026             && ((rt.rt_flags & RTF_LLINFO) != RTF_LLINFO)) {
1027 #endif
1028             /*
1029              * check for space and malloc 
1030              */
1031             if (rtsize >= rtallocate) {
1032                 rthead =
1033                     (RTENTRY **) realloc((char *) rthead,
1034                                          2 * rtallocate *
1035                                          sizeof(RTENTRY *));
1036                 memset((char *) &rthead[rtallocate], (0),
1037                        rtallocate * sizeof(RTENTRY *));
1038
1039                 rtallocate *= 2;
1040             }
1041             if (!rthead[rtsize])
1042                 rthead[rtsize] = (RTENTRY *) malloc(sizeof(RTENTRY));
1043             /*
1044              *      Add this to the database
1045              */
1046             memcpy((char *) rthead[rtsize], (char *) &rt, sizeof(RTENTRY));
1047             rtsize++;
1048 #if CHECK_RT_FLAGS
1049         }
1050 #endif
1051
1052         if (node.rn_dupedkey)
1053             load_rtentries(node.rn_dupedkey);
1054     }
1055 }
1056 #endif                          /* RTENTRY_4_4 && !hpux11 */
1057
1058 static void
1059 Route_Scan_Reload(void)
1060 {
1061 #ifdef hpux11
1062
1063     int             fd;
1064     struct nmparms  p;
1065     int             val;
1066     unsigned int    ulen;
1067     int             ret;
1068
1069     if (rt)
1070         free(rt);
1071     rt = (mib_ipRouteEnt *) 0;
1072     rtsize = 0;
1073
1074     if ((fd = open_mib("/dev/ip", O_RDONLY, 0, NM_ASYNC_OFF)) >= 0) {
1075         p.objid = ID_ipRouteNumEnt;
1076         p.buffer = (void *) &val;
1077         ulen = sizeof(int);
1078         p.len = &ulen;
1079         if ((ret = get_mib_info(fd, &p)) == 0)
1080             rtsize = val;
1081
1082         if (rtsize > 0) {
1083             ulen = (unsigned) rtsize *sizeof(mib_ipRouteEnt);
1084             rt = (mib_ipRouteEnt *) malloc(ulen);
1085             p.objid = ID_ipRouteTable;
1086             p.buffer = (void *) rt;
1087             p.len = &ulen;
1088             if ((ret = get_mib_info(fd, &p)) < 0)
1089                 rtsize = 0;
1090         }
1091
1092         close_mib(fd);
1093     }
1094
1095     /*
1096      *  Sort it!
1097      */
1098     qsort((char *) rt, rtsize, sizeof(rt[0]),
1099 #ifdef __STDC__
1100           (int (*)(const void *, const void *)) qsort_compare
1101 #else
1102           qsort_compare
1103 #endif
1104         );
1105
1106 #else                           /* hpux11 */
1107 #if defined(RTENTRY_4_4)
1108     struct radix_node_head head, *rt_table[AF_MAX + 1];
1109     int             i;
1110 #else
1111     RTENTRY       **routehash, mb;
1112     register RTENTRY *m;
1113     RTENTRY        *rt;
1114     struct ifnet    ifnet;
1115     int             i, table;
1116     register char  *cp;
1117     char            name[16], temp[16];
1118     int             hashsize;
1119 #endif
1120     static int      Time_Of_Last_Reload = 0;
1121     struct timeval  now;
1122
1123     gettimeofday(&now, (struct timezone *) 0);
1124     if (Time_Of_Last_Reload + CACHE_TIME > now.tv_sec)
1125         return;
1126     Time_Of_Last_Reload = now.tv_sec;
1127
1128     /*
1129      * *  Makes sure we have SOME space allocated for new routing entries
1130      */
1131     if (!rthead) {
1132         rthead = (RTENTRY **) malloc(100 * sizeof(RTENTRY *));
1133         if (!rthead) {
1134             snmp_log(LOG_ERR, "route table malloc fail\n");
1135             return;
1136         }
1137         memset((char *) rthead, (0), 100 * sizeof(RTENTRY *));
1138         rtallocate = 100;
1139     }
1140
1141     /*
1142      * reset the routing table size to zero -- was a CMU memory leak 
1143      */
1144     rtsize = 0;
1145
1146 #ifdef RTENTRY_4_4
1147     /*
1148      * rtentry is a BSD 4.4 compat 
1149      */
1150
1151 #if !defined(AF_UNSPEC)
1152 #define AF_UNSPEC AF_INET
1153 #endif
1154
1155     auto_nlist(RTTABLES_SYMBOL, (char *) rt_table, sizeof(rt_table));
1156     for (i = 0; i <= AF_MAX; i++) {
1157         if (rt_table[i] == 0)
1158             continue;
1159         if (klookup
1160             ((unsigned long) rt_table[i], (char *) &head, sizeof(head))) {
1161             load_rtentries(head.rnh_treetop);
1162         }
1163     }
1164
1165 #else                           /* rtentry is a BSD 4.3 compat */
1166     for (table = 0; table < NUM_ROUTE_SYMBOLS; table++) {
1167         auto_nlist(RTHASHSIZE_SYMBOL, (char *) &hashsize,
1168                    sizeof(hashsize));
1169         routehash = (RTENTRY **) malloc(hashsize * sizeof(struct mbuf *));
1170         auto_nlist(route_symbols[table], (char *) routehash,
1171                    hashsize * sizeof(struct mbuf *));
1172         for (i = 0; i < hashsize; i++) {
1173             if (routehash[i] == 0)
1174                 continue;
1175             m = routehash[i];
1176             while (m) {
1177                 /*
1178                  *      Dig the route out of the kernel...
1179                  */
1180                 klookup(m, (char *) &mb, sizeof(mb));
1181                 m = mb.rt_next;
1182
1183                 rt = &mb;
1184                 if (rt->rt_ifp != 0) {
1185                     klookup(rt->rt_ifp, (char *) &ifnet, sizeof(ifnet));
1186                     klookup(ifnet.if_name, name, 16);
1187                     name[15] = '\0';
1188                     cp = (char *) strchr(name, '\0');
1189                     string_append_int(cp, ifnet.if_unit);
1190
1191                     Interface_Scan_Init();
1192                     while (Interface_Scan_Next
1193                            ((short *) &rt->rt_unit, temp, NULL,
1194                             NULL) != 0) {
1195                         if (strcmp(name, temp) == 0)
1196                             break;
1197                     }
1198                 }
1199                 /*
1200                  *      Allocate a block to hold it and add it to the database
1201                  */
1202                 if (rtsize >= rtallocate) {
1203                     rthead =
1204                         (RTENTRY **) realloc((char *) rthead,
1205                                              2 * rtallocate *
1206                                              sizeof(RTENTRY *));
1207                     memset((char *) &rthead[rtallocate], (0),
1208                            rtallocate * sizeof(RTENTRY *));
1209
1210                     rtallocate *= 2;
1211                 }
1212                 if (!rthead[rtsize])
1213                     rthead[rtsize] = (RTENTRY *) malloc(sizeof(RTENTRY));
1214                 /*
1215                  *      Add this to the database
1216                  */
1217                 memcpy((char *) rthead[rtsize], (char *) rt,
1218                        sizeof(RTENTRY));
1219                 rtsize++;
1220             }
1221         }
1222         free(routehash);
1223     }
1224 #endif
1225     /*
1226      *  Sort it!
1227      */
1228     qsort((char *) rthead, rtsize, sizeof(rthead[0]),
1229 #ifdef __STDC__
1230           (int (*)(const void *, const void *)) qsort_compare
1231 #else
1232           qsort_compare
1233 #endif
1234         );
1235 #endif                          /* hpux11 */
1236 }
1237
1238 #else
1239
1240 #if HAVE_SYS_MBUF_H
1241 static void
1242 Route_Scan_Reload(void)
1243 {
1244     struct mbuf   **routehash, mb;
1245     register struct mbuf *m;
1246     struct ifnet    ifnet;
1247     RTENTRY        *rt;
1248     int             i, table;
1249     register char  *cp;
1250     char            name[16], temp[16];
1251     static int      Time_Of_Last_Reload = 0;
1252     struct timeval  now;
1253     int             hashsize;
1254
1255     gettimeofday(&now, (struct timezone *) 0);
1256     if (Time_Of_Last_Reload + CACHE_TIME > now.tv_sec)
1257         return;
1258     Time_Of_Last_Reload = now.tv_sec;
1259
1260     /*
1261      *  Makes sure we have SOME space allocated for new routing entries
1262      */
1263     if (!rthead) {
1264         rthead = (RTENTRY **) malloc(100 * sizeof(RTENTRY *));
1265         if (!rthead) {
1266             snmp_log(LOG_ERR, "route table malloc fail\n");
1267             return;
1268         }
1269         memset((char *) rthead, (0), 100 * sizeof(RTENTRY *));
1270         rtallocate = 100;
1271     }
1272
1273     /*
1274      * reset the routing table size to zero -- was a CMU memory leak 
1275      */
1276     rtsize = 0;
1277
1278     for (table = 0; table < NUM_ROUTE_SYMBOLS; table++) {
1279 #ifdef sunV3
1280         hashsize = RTHASHSIZ;
1281 #else
1282         auto_nlist(RTHASHSIZE_SYMBOL, (char *) &hashsize,
1283                    sizeof(hashsize));
1284 #endif
1285         routehash =
1286             (struct mbuf **) malloc(hashsize * sizeof(struct mbuf *));
1287         auto_nlist(route_symbols[table], (char *) routehash,
1288                    hashsize * sizeof(struct mbuf *));
1289         for (i = 0; i < hashsize; i++) {
1290             if (routehash[i] == 0)
1291                 continue;
1292             m = routehash[i];
1293             while (m) {
1294                 /*
1295                  *  Dig the route out of the kernel...
1296                  */
1297                 klookup((unsigned long) m, (char *) &mb, sizeof(mb));
1298                 m = mb.m_next;
1299                 rt = mtod(&mb, RTENTRY *);
1300
1301                 if (rt->rt_ifp != 0) {
1302
1303                     klookup((unsigned long) rt->rt_ifp, (char *) &ifnet,
1304                             sizeof(ifnet));
1305                     klookup((unsigned long) ifnet.if_name, name, 16);
1306                     name[15] = '\0';
1307                     cp = (char *) strchr(name, '\0');
1308                     string_append_int(cp, ifnet.if_unit);
1309                     if (strcmp(name, "lo0") == 0)
1310                         continue;
1311
1312                     Interface_Scan_Init();
1313                     while (Interface_Scan_Next
1314                            ((short *) &rt->rt_unit, temp, NULL,
1315                             NULL) != 0) {
1316                         if (strcmp(name, temp) == 0)
1317                             break;
1318                     }
1319                 }
1320                 /*
1321                  *  Allocate a block to hold it and add it to the database
1322                  */
1323                 if (rtsize >= rtallocate) {
1324                     rthead =
1325                         (RTENTRY **) realloc((char *) rthead,
1326                                              2 * rtallocate *
1327                                              sizeof(RTENTRY *));
1328                     memset((char *) &rthead[rtallocate], (0),
1329                            rtallocate * sizeof(RTENTRY *));
1330
1331                     rtallocate *= 2;
1332                 }
1333                 if (!rthead[rtsize])
1334                     rthead[rtsize] = (RTENTRY *) malloc(sizeof(RTENTRY));
1335                 /*
1336                  * *      Add this to the database
1337                  */
1338                 memcpy((char *) rthead[rtsize], (char *) rt,
1339                        sizeof(RTENTRY));
1340                 rtsize++;
1341             }
1342         }
1343         free(routehash);
1344     }
1345     /*
1346      *  Sort it!
1347      */
1348     qsort((char *) rthead, rtsize, sizeof(rthead[0]), qsort_compare);
1349 }
1350 #else
1351 #ifdef linux
1352 static void
1353 Route_Scan_Reload(void)
1354 {
1355     FILE           *in;
1356     char            line[256];
1357     struct rtentry *rt;
1358     char            name[16], temp[16];
1359     static int      Time_Of_Last_Reload = 0;
1360     struct timeval  now;
1361
1362     /*
1363      * allow 20 seconds in cache: 
1364      */
1365     gettimeofday(&now, (struct timezone *) 0);
1366     if (Time_Of_Last_Reload + 20 > now.tv_sec)
1367         return;
1368     Time_Of_Last_Reload = now.tv_sec;
1369
1370     /*
1371      *  Makes sure we have SOME space allocated for new routing entries
1372      */
1373     if (!rthead) {
1374         rthead = (struct rtentry **) calloc(100, sizeof(struct rtentry *));
1375         if (!rthead) {
1376             snmp_log(LOG_ERR, "route table malloc fail\n");
1377             return;
1378         }
1379         rtallocate = 100;
1380     }
1381
1382     /*
1383      * fetch routes from the proc file-system:
1384      */
1385
1386     rtsize = 0;
1387
1388     if (!(in = fopen("/proc/net/route", "r"))) {
1389         snmp_log(LOG_ERR, "cannot open /proc/net/route - burps\n");
1390         return;
1391     }
1392
1393     while (fgets(line, sizeof(line), in)) {
1394         struct rtentry  rtent;
1395         char            rtent_name[32];
1396         int             refcnt, flags, metric;
1397         unsigned        use;
1398
1399         rt = &rtent;
1400         memset((char *) rt, (0), sizeof(*rt));
1401         rt->rt_dev = rtent_name;
1402
1403         /*
1404          * as with 1.99.14:
1405          * Iface Dest GW Flags RefCnt Use Metric Mask MTU Win IRTT
1406          * eth0 0A0A0A0A 00000000 05 0 0 0 FFFFFFFF 1500 0 0 
1407          */
1408         if (8 != sscanf(line, "%s %x %x %x %u %d %d %x %*d %*d %*d\n",
1409                         rt->rt_dev,
1410                         &(((struct sockaddr_in *) &(rtent.rt_dst))->
1411                           sin_addr.s_addr),
1412                         &(((struct sockaddr_in *) &(rtent.rt_gateway))->
1413                           sin_addr.s_addr),
1414                         /*
1415                          * XXX: fix type of the args 
1416                          */
1417                         &flags, &refcnt, &use, &metric,
1418                         &(((struct sockaddr_in *) &(rtent.rt_genmask))->
1419                           sin_addr.s_addr)))
1420             continue;
1421
1422         strncpy(name, rt->rt_dev, sizeof(name));
1423         name[ sizeof(name)-1 ] = 0;
1424         /*
1425          * linux says ``lo'', but the interface is stored as ``lo0'': 
1426          */
1427         if (!strcmp(name, "lo"))
1428             strcat(name, "0");
1429
1430         rt->rt_flags = flags, rt->rt_refcnt = refcnt;
1431         rt->rt_use = use, rt->rt_metric = metric;
1432
1433         Interface_Scan_Init();
1434         while (Interface_Scan_Next
1435                ((short *) &rt->rt_unit, temp, NULL, NULL) != 0)
1436             if (strcmp(name, temp) == 0)
1437                 break;
1438
1439         /*
1440          *  Allocate a block to hold it and add it to the database
1441          */
1442         if (rtsize >= rtallocate) {
1443             rthead = (struct rtentry **) realloc((char *) rthead,
1444                                                  2 * rtallocate *
1445                                                  sizeof(struct rtentry *));
1446             memset(&rthead[rtallocate], 0,
1447                    rtallocate * sizeof(struct rtentry *));
1448             rtallocate *= 2;
1449         }
1450         if (!rthead[rtsize])
1451             rthead[rtsize] =
1452                 (struct rtentry *) malloc(sizeof(struct rtentry));
1453         /*
1454          *  Add this to the database
1455          */
1456         memcpy((char *) rthead[rtsize], (char *) rt,
1457                sizeof(struct rtentry));
1458         rtsize++;
1459     }
1460
1461     fclose(in);
1462
1463     /*
1464      *  Sort it!
1465      */
1466     qsort((char *) rthead, rtsize, sizeof(rthead[0]), qsort_compare);
1467 }
1468 #endif
1469 #endif
1470 #endif
1471
1472
1473 #ifndef solaris2
1474 /*
1475  *      Create a host table
1476  */
1477 #ifdef hpux11
1478 static int
1479 qsort_compare(const void *v1, const void *v2)
1480 {
1481     mib_ipRouteEnt * const *r1 = (mib_ipRouteEnt * const *) v1;
1482     mib_ipRouteEnt * const *r2 = (mib_ipRouteEnt * const *) v2;
1483     /*
1484      *      Do the comparison
1485      */
1486     if ((*r1)->Dest == (*r2)->Dest)
1487         return (0);
1488     if ((*r1)->Dest  > (*r2)->Dest)
1489         return (1);
1490     return (-1);
1491 }
1492 #else
1493 static int
1494 qsort_compare(const void *v1, const void *v2)
1495 {
1496     RTENTRY * const *r1 = (RTENTRY * const *) v1;
1497     RTENTRY * const *r2 = (RTENTRY * const *) v2;
1498 #if NEED_KLGETSA
1499     register u_long dst1 =
1500         ntohl(klgetsa((const struct sockaddr_in *) (*r1)->rt_dst)->
1501               sin_addr.s_addr);
1502     register u_long dst2 =
1503         ntohl(klgetsa((const struct sockaddr_in *) (*r2)->rt_dst)->
1504               sin_addr.s_addr);
1505 #else
1506     register u_long dst1 =
1507         ntohl(((const struct sockaddr_in *) &((*r1)->rt_dst))->sin_addr.
1508               s_addr);
1509     register u_long dst2 =
1510         ntohl(((const struct sockaddr_in *) &((*r2)->rt_dst))->sin_addr.
1511               s_addr);
1512 #endif                          /* NEED_KLGETSA */
1513
1514     /*
1515      *      Do the comparison
1516      */
1517     if (dst1 == dst2)
1518         return (0);
1519     if (dst1 > dst2)
1520         return (1);
1521     return (-1);
1522 }
1523 #endif                          /* hpux11 */
1524 #endif                          /* not USE_SYSCTL_ROUTE_DUMP */
1525
1526 #endif                          /* solaris2 */
1527
1528 #else                           /* WIN32 */
1529 #include <iphlpapi.h>
1530 #ifndef MIB_IPPROTO_NETMGMT
1531 #define MIB_IPPROTO_NETMGMT 3
1532 #endif
1533
1534 PMIB_IPFORWARDROW route_row;
1535 int             create_flag;
1536 void
1537 init_var_route(void)
1538 {
1539 }
1540
1541 u_char         *
1542 var_ipRouteEntry(struct variable *vp,
1543                  oid * name,
1544                  size_t * length,
1545                  int exact, size_t * var_len, WriteMethod ** write_method)
1546 {
1547     /*
1548      * object identifier is of form:
1549      * 1.3.6.1.2.1.4.21.1.?.A.B.C.D,  where A.B.C.D is IP address.
1550      * IPADDR starts at offset 10.
1551      */
1552     register int    Save_Valid, result, RtIndex;
1553     static int      saveNameLen = 0, saveExact = 0, saveRtIndex =
1554         0, rtsize = 0;
1555     static oid      saveName[MAX_OID_LEN], Current[MAX_OID_LEN];
1556     u_char         *cp;
1557     oid            *op;
1558     DWORD           status = NO_ERROR;
1559     DWORD           dwActualSize = 0;
1560     static PMIB_IPFORWARDTABLE pIpRtrTable = NULL;
1561     struct timeval  now;
1562     static long     Time_Of_Last_Reload = 0;
1563     u_char          dest_addr[4];
1564     MIB_IPFORWARDROW temp_row;
1565
1566
1567     /** 
1568      ** this optimisation fails, if there is only a single route avail.
1569      ** it is a very special case, but better leave it out ...
1570      **/
1571 #if NO_DUMMY_VALUES
1572     saveNameLen = 0;
1573 #endif
1574     if (route_row == NULL) {
1575         /*
1576          * Free allocated memory in case of SET request's FREE phase 
1577          */
1578         route_row = (PMIB_IPFORWARDROW) malloc(sizeof(MIB_IPFORWARDROW));
1579     }
1580     gettimeofday(&now, (struct timezone *) 0);
1581     if ((rtsize <= 1) || (Time_Of_Last_Reload + 5 <= now.tv_sec))
1582         Save_Valid = 0;
1583     else
1584         /*
1585          *  OPTIMIZATION:
1586          *
1587          *  If the name was the same as the last name, with the possible
1588          *  exception of the [9]th token, then don't read the routing table
1589          *
1590          */
1591
1592     if ((saveNameLen == (int) *length) && (saveExact == exact)) {
1593         register int    temp = name[9];
1594         name[9] = 0;
1595         Save_Valid =
1596             (snmp_oid_compare(name, *length, saveName, saveNameLen) == 0);
1597         name[9] = temp;
1598     } else
1599         Save_Valid = 0;
1600
1601     if (Save_Valid) {
1602         register int    temp = name[9]; /* Fix up 'lowest' found entry */
1603         memcpy((char *) name, (char *) Current, 14 * sizeof(oid));
1604         name[9] = temp;
1605         *length = 14;
1606         RtIndex = saveRtIndex;
1607     } else {
1608         /*
1609          * fill in object part of name for current(less sizeof instance part) 
1610          */
1611
1612         memcpy((char *) Current, (char *) vp->name,
1613                (int) (vp->namelen) * sizeof(oid));
1614
1615
1616         if ((Time_Of_Last_Reload + 5 <= now.tv_sec)
1617             || (pIpRtrTable == NULL)) {
1618             if (pIpRtrTable != NULL)
1619                 free(pIpRtrTable);
1620             Time_Of_Last_Reload = now.tv_sec;
1621             /*
1622              * query for buffer size needed 
1623              */
1624             status = GetIpForwardTable(pIpRtrTable, &dwActualSize, TRUE);
1625             if (status == ERROR_INSUFFICIENT_BUFFER) {
1626                 pIpRtrTable = (PMIB_IPFORWARDTABLE) malloc(dwActualSize);
1627                 if (pIpRtrTable != NULL) {
1628                     /*
1629                      * Get the sorted IP Route Table 
1630                      */
1631                     status =
1632                         GetIpForwardTable(pIpRtrTable, &dwActualSize,
1633                                           TRUE);
1634                 }
1635             }
1636         }
1637         if (status == NO_ERROR) {
1638             rtsize = pIpRtrTable->dwNumEntries;
1639             for (RtIndex = 0; RtIndex < rtsize; RtIndex++) {
1640                 cp = (u_char *) & pIpRtrTable->table[RtIndex].
1641                     dwForwardDest;
1642                 op = Current + 10;
1643                 *op++ = *cp++;
1644                 *op++ = *cp++;
1645                 *op++ = *cp++;
1646                 *op++ = *cp++;
1647
1648                 result = snmp_oid_compare(name, *length, Current, 14);
1649                 if ((exact && (result == 0)) || (!exact && (result < 0)))
1650                     break;
1651             }
1652         }
1653         if (RtIndex >= rtsize) {
1654             /*
1655              * for creation of new row, only ipNetToMediaTable case is considered 
1656              */
1657             if (*length == 14) {
1658                 create_flag = 1;
1659                 *write_method = write_rte;
1660                 dest_addr[0] = (u_char) name[10];
1661                 dest_addr[1] = (u_char) name[11];
1662                 dest_addr[2] = (u_char) name[12];
1663                 dest_addr[3] = (u_char) name[13];
1664                 temp_row.dwForwardDest = *((DWORD *) dest_addr);
1665                 temp_row.dwForwardPolicy = 0;
1666                 temp_row.dwForwardProto = MIB_IPPROTO_NETMGMT;
1667                 *route_row = temp_row;
1668             }
1669             free(pIpRtrTable);
1670             pIpRtrTable = NULL;
1671             rtsize = 0;
1672             return (NULL);
1673         }
1674         create_flag = 0;
1675         /*
1676          *  Save in the 'cache'
1677          */
1678         memcpy((char *) saveName, (char *) name,
1679                SNMP_MIN(*length, MAX_OID_LEN) * sizeof(oid));
1680         saveName[9] = 0;
1681         saveNameLen = *length;
1682         saveExact = exact;
1683         saveRtIndex = RtIndex;
1684
1685         /*
1686          *  Return the name
1687          */
1688         memcpy((char *) name, (char *) Current, 14 * sizeof(oid));
1689         *length = 14;
1690     }
1691     *var_len = sizeof(long_return);
1692     *route_row = pIpRtrTable->table[RtIndex];
1693
1694     switch (vp->magic) {
1695     case IPROUTEDEST:
1696         *write_method = write_rte;
1697         long_return = pIpRtrTable->table[RtIndex].dwForwardDest;
1698         return (u_char *) & long_return;
1699     case IPROUTEIFINDEX:
1700         *write_method = write_rte;
1701         long_return = pIpRtrTable->table[RtIndex].dwForwardIfIndex;
1702         return (u_char *) & long_return;
1703     case IPROUTEMETRIC1:
1704         *write_method = write_rte;
1705         long_return = pIpRtrTable->table[RtIndex].dwForwardMetric1;
1706         return (u_char *) & long_return;
1707     case IPROUTEMETRIC2:
1708         *write_method = write_rte;
1709         long_return = pIpRtrTable->table[RtIndex].dwForwardMetric2;
1710         return (u_char *) & long_return;
1711     case IPROUTEMETRIC3:
1712         *write_method = write_rte;
1713         long_return = pIpRtrTable->table[RtIndex].dwForwardMetric3;
1714         return (u_char *) & long_return;
1715     case IPROUTEMETRIC4:
1716         *write_method = write_rte;
1717         long_return = pIpRtrTable->table[RtIndex].dwForwardMetric4;
1718         return (u_char *) & long_return;
1719     case IPROUTEMETRIC5:
1720         *write_method = write_rte;
1721         long_return = pIpRtrTable->table[RtIndex].dwForwardMetric5;
1722         return (u_char *) & long_return;
1723     case IPROUTENEXTHOP:
1724         *write_method = write_rte;
1725         long_return = pIpRtrTable->table[RtIndex].dwForwardNextHop;
1726         return (u_char *) & long_return;
1727     case IPROUTETYPE:
1728         *write_method = write_rte;
1729         long_return = pIpRtrTable->table[RtIndex].dwForwardType;
1730         return (u_char *) & long_return;
1731     case IPROUTEPROTO:
1732         long_return = pIpRtrTable->table[RtIndex].dwForwardProto;
1733         return (u_char *) & long_return;
1734     case IPROUTEAGE:
1735         *write_method = write_rte;
1736         long_return = pIpRtrTable->table[RtIndex].dwForwardAge;
1737         return (u_char *) & long_return;
1738     case IPROUTEMASK:
1739         *write_method = write_rte;
1740         long_return = pIpRtrTable->table[RtIndex].dwForwardMask;
1741         return (u_char *) & long_return;
1742     case IPROUTEINFO:
1743         *var_len = nullOidLen;
1744         return (u_char *) nullOid;
1745     default:
1746         DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ipRouteEntry\n",
1747                     vp->magic));
1748     }
1749     return NULL;
1750 }
1751
1752 #endif                          /* WIN32 */
1753
1754 #else                           /* CAN_USE_SYSCTL */
1755
1756 #include <stddef.h>
1757 #include <stdlib.h>
1758 #include <syslog.h>
1759 #include <time.h>
1760
1761 #include <sys/types.h>
1762 #include <sys/param.h>
1763 #include <sys/queue.h>
1764 #include <sys/socket.h>
1765 #include <sys/sysctl.h>
1766 #if HAVE_SYS_TIME_H
1767 #include <sys/time.h>
1768 #endif
1769
1770 #include <net/if_dl.h>
1771 #if HAVE_SYS_STREAM_H
1772 #include <sys/stream.h>
1773 #endif
1774 #include <net/route.h>
1775 #include <netinet/in.h>
1776
1777 #define CACHE_TIME (120)        /* Seconds */
1778
1779 #include <net-snmp/net-snmp-includes.h>
1780 #include <net-snmp/agent/net-snmp-agent-includes.h>
1781
1782 #include "ip.h"
1783 #include "kernel.h"
1784 #include "interfaces.h"
1785 #include "struct.h"
1786 #include "util_funcs.h"
1787
1788 static
1789 TAILQ_HEAD(, snmprt)
1790     rthead;
1791      static char    *rtbuf;
1792      static size_t   rtbuflen;
1793      static time_t   lasttime;
1794
1795      struct snmprt {
1796          TAILQ_ENTRY(snmprt) link;
1797          struct rt_msghdr *hdr;
1798          struct in_addr  dest;
1799          struct in_addr  gateway;
1800          struct in_addr  netmask;
1801          int             index;
1802          struct in_addr  ifa;
1803      };
1804
1805      static void
1806                      rtmsg(struct rt_msghdr *rtm)
1807 {
1808     struct snmprt  *rt;
1809     struct sockaddr *sa;
1810     int             bit, gotdest, gotmask;
1811
1812     rt = malloc(sizeof *rt);
1813     if (rt == 0)
1814         return;
1815     rt->hdr = rtm;
1816     rt->ifa.s_addr = 0;
1817     rt->dest = rt->gateway = rt->netmask = rt->ifa;
1818     rt->index = rtm->rtm_index;
1819
1820     gotdest = gotmask = 0;
1821     sa = (struct sockaddr *) (rtm + 1);
1822     for (bit = 1; ((char *) sa < (char *) rtm + rtm->rtm_msglen) && bit;
1823          bit <<= 1) {
1824         if ((rtm->rtm_addrs & bit) == 0)
1825             continue;
1826         switch (bit) {
1827         case RTA_DST:
1828 #define satosin(sa) ((struct sockaddr_in *)(sa))
1829             rt->dest = satosin(sa)->sin_addr;
1830             gotdest = 1;
1831             break;
1832         case RTA_GATEWAY:
1833             if (sa->sa_family == AF_INET)
1834                 rt->gateway = satosin(sa)->sin_addr;
1835             break;
1836         case RTA_NETMASK:
1837             if (sa->sa_len >= offsetof(struct sockaddr_in, sin_addr))
1838                                 rt->netmask = satosin(sa)->sin_addr;
1839             gotmask = 1;
1840             break;
1841         case RTA_IFA:
1842             if (sa->sa_family == AF_INET)
1843                 rt->ifa = satosin(sa)->sin_addr;
1844             break;
1845         }
1846         /*
1847          * from rtsock.c 
1848          */
1849 #define ROUNDUP(a) \
1850         ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
1851         sa = (struct sockaddr *) ((char *) sa + ROUNDUP(sa->sa_len));
1852     }
1853     if (!gotdest) {
1854         /*
1855          * XXX can't happen if code above is correct 
1856          */
1857         snmp_log(LOG_ERR, "route no dest?\n");
1858         free(rt);
1859     } else {
1860         /*
1861          * If no mask provided, it was a host route. 
1862          */
1863         if (!gotmask)
1864             rt->netmask.s_addr = ~0;
1865         TAILQ_INSERT_TAIL(&rthead, rt, link);
1866     }
1867 }
1868
1869 static int
1870 suck_krt(int force)
1871 {
1872     time_t          now;
1873     struct snmprt  *rt, *next;
1874     size_t          len;
1875     static int      name[6] =
1876         { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0 };
1877     char           *cp;
1878     struct rt_msghdr *rtm;
1879
1880     time(&now);
1881     if (now < (lasttime + CACHE_TIME) && !force)
1882         return 0;
1883     lasttime = now;
1884
1885     for (rt = rthead.tqh_first; rt; rt = next) {
1886         next = rt->link.tqe_next;
1887         free(rt);
1888     }
1889     TAILQ_INIT(&rthead);
1890
1891     if (sysctl(name, 6, 0, &len, 0, 0) < 0) {
1892         syslog(LOG_WARNING, "sysctl net-route-dump: %m");
1893         return -1;
1894     }
1895
1896     if (len > rtbuflen) {
1897         char           *newbuf;
1898         newbuf = realloc(rtbuf, len);
1899         if (newbuf == 0)
1900             return -1;
1901         rtbuf = newbuf;
1902         rtbuflen = len;
1903     }
1904
1905     if (sysctl(name, 6, rtbuf, &len, 0, 0) < 0) {
1906         syslog(LOG_WARNING, "sysctl net-route-dump: %m");
1907         return -1;
1908     }
1909
1910     cp = rtbuf;
1911     while (cp < rtbuf + len) {
1912         rtm = (struct rt_msghdr *) cp;
1913         /*
1914          * NB:
1915          * You might want to exclude routes with RTF_WASCLONED
1916          * set.  This keeps the cloned host routes (and thus also
1917          * ARP entries) out of the routing table.  Thus, it also
1918          * presents management stations with an incomplete view.
1919          * I believe that it should be possible for a management
1920          * station to examine (and perhaps delete) such routes.
1921          */
1922         if (rtm->rtm_version == RTM_VERSION && rtm->rtm_type == RTM_GET)
1923             rtmsg(rtm);
1924         cp += rtm->rtm_msglen;
1925     }
1926     return 0;
1927 }
1928
1929 u_char         *
1930 var_ipRouteEntry(struct variable * vp,
1931                  oid * name,
1932                  size_t * length,
1933                  int exact, size_t * var_len, WriteMethod ** write_method)
1934 {
1935     /*
1936      * object identifier is of form:
1937      * 1.3.6.1.2.1.4.21.1.1.A.B.C.D,  where A.B.C.D is IP address.
1938      * IPADDR starts at offset 10.
1939      */
1940     int             Save_Valid, result;
1941     u_char         *cp;
1942     oid            *op;
1943     struct snmprt  *rt;
1944     static struct snmprt *savert;
1945     static int      saveNameLen, saveExact;
1946     static oid      saveName[14], Current[14];
1947
1948 #if 0
1949     /*
1950      *      OPTIMIZATION:
1951      *
1952      *      If the name was the same as the last name, with the possible
1953      *      exception of the [9]th token, then don't read the routing table
1954      *
1955      */
1956
1957     if ((saveNameLen == *length) && (saveExact == exact)) {
1958         int             temp = name[9];
1959         name[9] = 0;
1960         Save_Valid =
1961             !snmp_oid_compare(name, *length, saveName, saveNameLen);
1962         name[9] = temp;
1963     } else {
1964         Save_Valid = 0;
1965     }
1966 #else
1967     Save_Valid = 0;
1968 #endif
1969
1970     if (Save_Valid) {
1971         int             temp = name[9];
1972         memcpy(name, Current, 14 * sizeof(oid));
1973         name[9] = temp;
1974         *length = 14;
1975         rt = savert;
1976     } else {
1977         /*
1978          * fill in object part of name for current
1979          * (less sizeof instance part) 
1980          */
1981
1982         memcpy(Current, vp->name, SNMP_MIN(sizeof(Current), (int)(vp->namelen) * sizeof(oid)));
1983
1984         suck_krt(0);
1985
1986         for (rt = rthead.tqh_first; rt; rt = rt->link.tqe_next) {
1987             op = Current + 10;
1988             cp = (u_char *) & rt->dest;
1989             *op++ = *cp++;
1990             *op++ = *cp++;
1991             *op++ = *cp++;
1992             *op++ = *cp++;
1993             result = snmp_oid_compare(name, *length, Current, 14);
1994             if ((exact && (result == 0))
1995                 || (!exact && (result < 0)))
1996                 break;
1997         }
1998         if (rt == NULL)
1999             return NULL;
2000
2001         /*
2002          *  Save in the 'cache'
2003          */
2004         memcpy(saveName, name, SNMP_MIN(sizeof(saveName), *length * sizeof(oid)));
2005         saveName[9] = 0;
2006         saveNameLen = *length;
2007         saveExact = exact;
2008         savert = rt;
2009
2010         /*
2011          *  Return the name
2012          */
2013         memcpy(name, Current, 14 * sizeof(oid));
2014         *length = 14;
2015     }
2016
2017     *write_method = write_rte;
2018     *var_len = sizeof long_return;
2019
2020     switch (vp->magic) {
2021     case IPROUTEDEST:
2022         long_return = rt->dest.s_addr;
2023         return (u_char *) & long_return;
2024
2025     case IPROUTEIFINDEX:
2026         long_return = rt->index;
2027         return (u_char *) & long_return;
2028
2029     case IPROUTEMETRIC1:
2030         long_return = (rt->hdr->rtm_flags & RTF_GATEWAY) ? 1 : 0;
2031         return (u_char *) & long_return;
2032     case IPROUTEMETRIC2:
2033         long_return = rt->hdr->rtm_rmx.rmx_rtt;
2034         return (u_char *) & long_return;
2035     case IPROUTEMETRIC3:
2036         long_return = rt->hdr->rtm_rmx.rmx_rttvar;
2037         return (u_char *) & long_return;
2038     case IPROUTEMETRIC4:
2039         long_return = rt->hdr->rtm_rmx.rmx_ssthresh;
2040         return (u_char *) & long_return;
2041     case IPROUTEMETRIC5:
2042         long_return = rt->hdr->rtm_rmx.rmx_mtu;
2043         return (u_char *) & long_return;
2044
2045     case IPROUTENEXTHOP:
2046         if (rt->gateway.s_addr == 0 && rt->ifa.s_addr == 0)
2047             long_return = 0;
2048         else if (rt->gateway.s_addr == 0)
2049             long_return = rt->ifa.s_addr;
2050         else
2051             long_return = rt->gateway.s_addr;
2052         return (u_char *) & long_return;
2053
2054     case IPROUTETYPE:
2055         if (rt->hdr->rtm_flags & RTF_UP) {
2056             if (rt->hdr->rtm_flags & RTF_GATEWAY) {
2057                 long_return = 4;        /*  indirect(4)  */
2058             } else {
2059                 long_return = 3;        /*  direct(3)  */
2060             }
2061         } else {
2062             long_return = 2;    /*  invalid(2)  */
2063         }
2064         return (u_char *) & long_return;
2065
2066     case IPROUTEPROTO:
2067         long_return = (rt->hdr->rtm_flags & RTF_DYNAMIC) ? 4 : 2;
2068         return (u_char *) & long_return;
2069
2070     case IPROUTEAGE:
2071 #if NO_DUMMY_VALUES
2072         return NULL;
2073 #endif
2074         long_return = 0;
2075         return (u_char *) & long_return;
2076
2077     case IPROUTEMASK:
2078         long_return = rt->netmask.s_addr;
2079         return (u_char *) & long_return;
2080
2081     case IPROUTEINFO:
2082         *var_len = nullOidLen;
2083         return (u_char *) nullOid;
2084     default:
2085         DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ipRouteEntry\n",
2086                     vp->magic));
2087     }
2088     return NULL;
2089 }
2090
2091 void
2092 init_var_route(void)
2093 {
2094     ;
2095 }
2096
2097 #endif                          /* CAN_USE_SYSCTL */
2098
2099 #if defined(HAVE_SYS_SYSCTL_H) && !defined(linux)
2100 /*
2101  * get_address()
2102  * 
2103  * Traverse the address structures after a routing socket message and
2104  * extract a specific one.
2105  * 
2106  * Some of this is peculiar to IRIX 6.2, which doesn't have sa_len in
2107  * the sockaddr structure yet.  With sa_len, skipping an address entry
2108  * would be much easier.
2109  */
2110 #include <sys/un.h>
2111
2112 /*
2113  * returns the length of a socket structure 
2114  */
2115
2116 size_t
2117 snmp_socket_length(int family)
2118 {
2119     size_t          length;
2120
2121     switch (family) {
2122 #ifndef cygwin
2123 #ifndef WIN32
2124 #ifdef AF_UNIX
2125     case AF_UNIX:
2126         length = sizeof(struct sockaddr_un);
2127         break;
2128 #endif                          /* AF_UNIX */
2129 #endif
2130 #endif
2131
2132 #ifndef aix3
2133 #ifdef AF_LINK
2134     case AF_LINK:
2135 #ifdef _MAX_SA_LEN
2136         length = _MAX_SA_LEN;
2137 #elif SOCK_MAXADDRLEN
2138         length = SOCK_MAXADDRLEN;
2139 #else
2140         length = sizeof(struct sockaddr_dl);
2141 #endif
2142         break;
2143 #endif                          /* AF_LINK */
2144 #endif
2145
2146     case AF_INET:
2147         length = sizeof(struct sockaddr_in);
2148         break;
2149     default:
2150         length = sizeof(struct sockaddr);
2151         break;
2152     }
2153
2154     return length;
2155 }
2156
2157 const struct sockaddr *
2158 get_address(const void *_ap, int addresses, int wanted)
2159 {
2160     const struct sockaddr *ap = (const struct sockaddr *) _ap;
2161     int             iindex;
2162     int             bitmask;
2163
2164     for (iindex = 0, bitmask = 1;
2165          iindex < RTAX_MAX; ++iindex, bitmask <<= 1) {
2166         if (bitmask == wanted) {
2167             if (bitmask & addresses) {
2168                 return ap;
2169             } else {
2170                 return 0;
2171             }
2172         } else if (bitmask & addresses) {
2173             unsigned        length =
2174                 (unsigned) snmp_socket_length(ap->sa_family);
2175             while (length % sizeof(long) != 0)
2176                 ++length;
2177             ap = (const struct sockaddr *) ((const char *) ap + length);
2178         }
2179     }
2180     return 0;
2181 }
2182
2183 /*
2184  * get_in_address()
2185  * 
2186  * Convenience function for the special case of get_address where an
2187  * AF_INET address is desired, and we're only interested in the in_addr
2188  * part.
2189  */
2190 const struct in_addr *
2191 get_in_address(const void *ap, int addresses, int wanted)
2192 {
2193     const struct sockaddr_in *a;
2194
2195     a = (const struct sockaddr_in *) get_address(ap, addresses, wanted);
2196     if (a == NULL)
2197         return NULL;
2198
2199     if (a->sin_family != AF_INET) {
2200         DEBUGMSGTL(("snmpd",
2201                     "unknown socket family %d [AF_INET expected] in var_ipRouteEntry.\n",
2202                     a->sin_family));
2203     }
2204     return &a->sin_addr;
2205 }
2206 #endif                          /* HAVE_SYS_SYSCTL_H */