1 /*
2  *  Interfaces MIB group implementation - interfaces.c
3  *
4  */
5 
6 /* Portions of this file are subject to the following copyright(s).  See
7  * the Net-SNMP's COPYING file for more details and other copyrights
8  * that may apply:
9  */
10 /*
11  * Portions of this file are copyrighted by:
12  * Copyright � 2003 Sun Microsystems, Inc. All rights reserved.
13  * Use is subject to license terms specified in the COPYING file
14  * distributed with the Net-SNMP package.
15  *
16  * Portions of this file are copyrighted by:
17  * Copyright (c) 2016 VMware, Inc. All rights reserved.
18  * Use is subject to license terms specified in the COPYING file
19  * distributed with the Net-SNMP package.
20  */
21 
22 #include <net-snmp/net-snmp-config.h>
23 #include <net-snmp/net-snmp-features.h>
24 
25 netsnmp_feature_provide(interface_legacy);
26 
27 #if defined(NETSNMP_IFNET_NEEDS_KERNEL) && !defined(_KERNEL) && !defined(NETSNMP_IFNET_NEEDS_KERNEL_LATE)
28 #define _KERNEL 1
29 #define _I_DEFINED_KERNEL
30 #endif
31 
32 #if HAVE_STRING_H
33 #include <string.h>
34 #else
35 #include <strings.h>
36 #endif
37 
38 #if HAVE_STDLIB_H
39 #include <stdlib.h>
40 #endif
41 #if HAVE_UNISTD_H
42 #include <unistd.h>
43 #endif
44 #if HAVE_SYS_PARAM_H
45 #include <sys/param.h>
46 #endif
47 #include <sys/types.h>
48 #if defined(NETSNMP_IFNET_NEEDS_KERNEL) && !defined(_KERNEL) && defined(NETSNMP_IFNET_NEEDS_KERNEL_LATE)
49 #define _KERNEL 1
50 #define _I_DEFINED_KERNEL
51 #endif
52 #if HAVE_SYS_SOCKET_H
53 #include <sys/socket.h>
54 #endif
55 #ifndef STREAM_NEEDS_KERNEL_ISLANDS
56 #if HAVE_SYS_STREAM_H
57 #include <sys/stream.h>
58 #endif
59 #endif
60 #if HAVE_SYS_SOCKETVAR_H
61 #include <sys/socketvar.h>
62 #endif
63 
64 #if TIME_WITH_SYS_TIME
65 # include <sys/time.h>
66 # include <time.h>
67 #else
68 # if HAVE_SYS_TIME_H
69 #  include <sys/time.h>
70 # else
71 #  include <time.h>
72 # endif
73 #endif
74 #if HAVE_SYS_SOCKIO_H
75 #include <sys/sockio.h>
76 #endif
77 #if HAVE_FCNTL_H
78 #include <fcntl.h>
79 #endif
80 #if HAVE_SYS_IOCTL_H
81 #include <sys/ioctl.h>
82 #endif
83 #if HAVE_NETINET_IN_H
84 #include <netinet/in.h>
85 #endif
86 #if HAVE_NET_IF_H
87 #include <net/if.h>
88 #endif
89 #if HAVE_NETINET_IN_VAR_H
90 #include <netinet/in_var.h>
91 #endif
92 #if HAVE_NET_IF_VAR_H
93 #include <net/if_var.h>
94 #endif
95 #ifdef _I_DEFINED_KERNEL
96 #undef _KERNEL
97 #endif
98 #ifdef STREAM_NEEDS_KERNEL_ISLANDS
99 #if HAVE_SYS_STREAM_H
100 #include <sys/stream.h>
101 #endif
102 #endif
103 #if HAVE_NET_ROUTE_H
104 #include <net/route.h>
105 #endif
106 #if HAVE_NETINET_IN_SYSTM_H
107 #include <netinet/in_systm.h>
108 #endif
109 #if HAVE_SYS_HASHING_H
110 #include <sys/hashing.h>
111 #endif
112 #if HAVE_NETINET_IN_VAR_H
113 #include <netinet/in_var.h>
114 #endif
115 #if HAVE_NETINET_IP_H
116 #include <netinet/ip.h>
117 #endif
118 #ifdef NETSNMP_ENABLE_IPV6
119 #if HAVE_NETINET_IP6_H
120 #include <netinet/ip6.h>
121 #endif
122 #endif
123 #if HAVE_SYS_QUEUE_H
124 #include <sys/queue.h>
125 #endif
126 #if HAVE_NETINET_IP_VAR_H
127 #include <netinet/ip_var.h>
128 #endif
129 #ifdef NETSNMP_ENABLE_IPV6
130 #if HAVE_NETNETSNMP_ENABLE_IPV6_IP6_VAR_H
131 #include <netinet6/ip6_var.h>
132 #endif
133 #endif
134 #if HAVE_NETINET_IN_PCB_H
135 #include <netinet/in_pcb.h>
136 #endif
137 #if HAVE_NETINET_IF_ETHER_H
138 #include <netinet/if_ether.h>
139 #endif
140 #if HAVE_NET_IF_TYPES_H
141 #include <net/if_types.h>
142 #endif
143 #if HAVE_NET_IF_DL_H
144 #ifndef dynix
145 #include <net/if_dl.h>
146 #else
147 #include <sys/net/if_dl.h>
148 #endif
149 #endif
150 #if HAVE_INET_MIB2_H
151 #include <inet/mib2.h>
152 #endif
153 #if HAVE_IOCTLS_H
154 #include <ioctls.h>
155 #endif
156 
157 #ifdef solaris2
158 # include <errno.h>
159 #include "kernel_sunos5.h"
160 #else
161 #include "kernel.h"
162 #endif
163 
164 #ifdef hpux
165 #include <sys/mib.h>
166 #include <netinet/mib_kern.h>
167 #endif                          /* hpux */
168 
169 #if defined(cygwin) || defined(mingw32)
170 #include <windows.h>
171 #endif
172 
173 #if HAVE_SYS_SYSCTL_H
174 #include <sys/sysctl.h>
175 
176 #if defined(freebsd3) || defined(freebsd4) || defined(freebsd5)
177 #    define USE_SYSCTL_IFLIST
178 #else
179 # if defined(CTL_NET) && !defined(freebsd2) && !defined(netbsd1)
180 #  ifdef PF_ROUTE
181 #   ifdef NET_RT_IFLIST
182 #    ifndef netbsd1
183 #     define USE_SYSCTL_IFLIST
184 #    endif
185 #   endif
186 #  endif
187 # endif
188 #endif                          /* defined(freebsd3) */
189 #endif                          /* HAVE_SYS_SYSCTL_H */
190 
191 #if HAVE_OSRELDATE_H
192 #include <osreldate.h>
193 #endif
194 #ifdef NETSNMP_CAN_USE_SYSCTL
195 #include <sys/sysctl.h>
196 #endif
197 
198 #include <net-snmp/net-snmp-includes.h>
199 #include <net-snmp/agent/net-snmp-agent-includes.h>
200 #include <net-snmp/agent/auto_nlist.h>
201 #include <net-snmp/agent/sysORTable.h>
202 #include <net-snmp/data_access/interface.h>
203 
204 #include "interfaces.h"
205 #include "struct.h"
206 #include "util_funcs.h"
207 #include "util_funcs/header_generic.h"
208 
209 /* if you want caching enabled for speed retrieval purposes, set this to 5?*/
210 #define MINLOADFREQ 0                     /* min reload frequency in seconds */
211 #ifdef linux
212 static unsigned long LastLoad = 0;        /* ET in secs at last table load */
213 #endif
214 
215 #define starttime (*(const struct timeval*)netsnmp_get_agent_starttime())
216 
217 struct variable3 interfaces_variables[] = {
218     {NETSNMP_IFNUMBER, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
219      var_interfaces, 1, {1}},
220     {NETSNMP_IFINDEX, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
221      var_ifEntry, 3, {2, 1, 1}},
222     {NETSNMP_IFDESCR, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY,
223      var_ifEntry, 3, {2, 1, 2}},
224     {NETSNMP_IFTYPE, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
225      var_ifEntry, 3, {2, 1, 3}},
226     {NETSNMP_IFMTU, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
227      var_ifEntry, 3, {2, 1, 4}},
228     {NETSNMP_IFSPEED, ASN_GAUGE, NETSNMP_OLDAPI_RONLY,
229      var_ifEntry, 3, {2, 1, 5}},
230     {NETSNMP_IFPHYSADDRESS, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY,
231      var_ifEntry, 3, {2, 1, 6}},
232 #ifndef NETSNMP_NO_WRITE_SUPPORT
233 #if defined (WIN32) || defined (cygwin)
234     {NETSNMP_IFADMINSTATUS, ASN_INTEGER, NETSNMP_OLDAPI_RWRITE,
235      var_ifEntry, 3, {2, 1, 7}},
236 #else
237     {NETSNMP_IFADMINSTATUS, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
238      var_ifEntry, 3, {2, 1, 7}},
239 #endif
240 #else  /* !NETSNMP_NO_WRITE_SUPPORT */
241     {NETSNMP_IFADMINSTATUS, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
242      var_ifEntry, 3, {2, 1, 7}},
243 #endif /* !NETSNMP_NO_WRITE_SUPPORT */
244     {NETSNMP_IFOPERSTATUS, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
245      var_ifEntry, 3, {2, 1, 8}},
246     {NETSNMP_IFLASTCHANGE, ASN_TIMETICKS, NETSNMP_OLDAPI_RONLY,
247      var_ifEntry, 3, {2, 1, 9}},
248     {NETSNMP_IFINOCTETS, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
249      var_ifEntry, 3, {2, 1, 10}},
250     {NETSNMP_IFINUCASTPKTS, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
251      var_ifEntry, 3, {2, 1, 11}},
252     {NETSNMP_IFINNUCASTPKTS, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
253      var_ifEntry, 3, {2, 1, 12}},
254     {NETSNMP_IFINDISCARDS, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
255      var_ifEntry, 3, {2, 1, 13}},
256     {NETSNMP_IFINERRORS, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
257      var_ifEntry, 3, {2, 1, 14}},
258     {NETSNMP_IFINUNKNOWNPROTOS, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
259      var_ifEntry, 3, {2, 1, 15}},
260     {NETSNMP_IFOUTOCTETS, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
261      var_ifEntry, 3, {2, 1, 16}},
262     {NETSNMP_IFOUTUCASTPKTS, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
263      var_ifEntry, 3, {2, 1, 17}},
264     {NETSNMP_IFOUTNUCASTPKTS, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
265      var_ifEntry, 3, {2, 1, 18}},
266     {NETSNMP_IFOUTDISCARDS, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
267      var_ifEntry, 3, {2, 1, 19}},
268     {NETSNMP_IFOUTERRORS, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
269      var_ifEntry, 3, {2, 1, 20}},
270     {NETSNMP_IFOUTQLEN, ASN_GAUGE, NETSNMP_OLDAPI_RONLY,
271      var_ifEntry, 3, {2, 1, 21}},
272     {NETSNMP_IFSPECIFIC, ASN_OBJECT_ID, NETSNMP_OLDAPI_RONLY,
273      var_ifEntry, 3, {2, 1, 22}}
274 };
275 
276 /*
277  * Define the OID pointer to the top of the mib tree that we're
278  * registering underneath, and the OID of the MIB module
279  */
280 oid             interfaces_variables_oid[] = { SNMP_OID_MIB2, 2 };
281 oid             interfaces_module_oid[] = { SNMP_OID_MIB2, 31 };
282 
283 void
init_interfaces(void)284 init_interfaces(void)
285 {
286     /*
287      * register ourselves with the agent to handle our mib tree
288      */
289     REGISTER_MIB("mibII/interfaces", interfaces_variables, variable3,
290                  interfaces_variables_oid);
291     REGISTER_SYSOR_ENTRY(interfaces_module_oid,
292                          "The MIB module to describe generic objects for network interface sub-layers");
293 
294 #ifndef USE_SYSCTL_IFLIST
295 #if HAVE_NET_IF_MIB_H
296     init_interfaces_setup();
297 #endif
298 #endif
299 #ifdef solaris2
300     init_kernel_sunos5();
301 #endif
302 }
303 
304 #ifdef linux
305 /*
306  * if_type_from_name
307  * Return interface type using the interface name as a clue.
308  * Returns 1 to imply "other" type if name not recognized.
309  */
310 static int
if_type_from_name(const char * pcch)311 if_type_from_name(const char *pcch)
312 {
313     typedef struct _match_if {
314         int             mi_type;
315         const char     *mi_name;
316     }              *pmatch_if, match_if;
317 
318     static match_if lmatch_if[] = {
319         {24, "lo"},
320         {6, "eth"},
321         {9, "tr"},
322         {23, "ppp"},
323         {28, "sl"},
324         {0, 0}                  /* end of list */
325     };
326 
327     int             len;
328     register pmatch_if pm;
329 
330     for (pm = lmatch_if; pm->mi_name; pm++) {
331         len = strlen(pm->mi_name);
332         if (0 == strncmp(pcch, pm->mi_name, len)) {
333             return (pm->mi_type);
334         }
335     }
336     return (1);                 /* in case search fails */
337 }
338 #endif
339 
340 
341 #ifdef linux
342 static struct ifnet *ifnetaddr_list;
343 #endif
344 
345 
346 /*
347  * header_ifEntry(...
348  * Arguments:
349  * vp     IN      - pointer to variable entry that points here
350  * name    IN/OUT  - IN/name requested, OUT/name found
351  * length  IN/OUT  - length of IN/OUT oid's
352  * exact   IN      - TRUE if an exact match was requested
353  * var_len OUT     - length of variable or 0 if function returned
354  * write_method
355  *
356  */
357 #if !defined (WIN32) && !defined (cygwin)
358 static int
header_ifEntry(struct variable * vp,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)359 header_ifEntry(struct variable *vp,
360                oid * name,
361                size_t * length,
362                int exact, size_t * var_len, WriteMethod ** write_method)
363 {
364 #define IFENTRY_NAME_LENGTH	10
365     oid             newname[MAX_OID_LEN];
366     register int    interface;
367     int             result, count;
368 
369     DEBUGMSGTL(("mibII/interfaces", "var_ifEntry: "));
370     DEBUGMSGOID(("mibII/interfaces", name, *length));
371     DEBUGMSG(("mibII/interfaces", " %d\n", exact));
372 
373     memcpy((char *) newname, (char *) vp->name,
374            (int) vp->namelen * sizeof(oid));
375     /*
376      * find "next" interface
377      */
378     count = Interface_Scan_Get_Count();
379     for (interface = 1; interface <= count; interface++) {
380         newname[IFENTRY_NAME_LENGTH] = (oid) interface;
381         result =
382             snmp_oid_compare(name, *length, newname,
383                              (int) vp->namelen + 1);
384         if ((exact && (result == 0)) || (!exact && (result < 0)))
385             break;
386     }
387     if (interface > count) {
388         DEBUGMSGTL(("mibII/interfaces", "... index out of range\n"));
389         return MATCH_FAILED;
390     }
391 
392 
393     memcpy((char *) name, (char *) newname,
394            ((int) vp->namelen + 1) * sizeof(oid));
395     *length = vp->namelen + 1;
396     *write_method = 0;
397     *var_len = sizeof(long);    /* default to 'long' results */
398 
399     DEBUGMSGTL(("mibII/interfaces", "... get I/F stats "));
400     DEBUGMSGOID(("mibII/interfaces", name, *length));
401     DEBUGMSG(("mibII/interfaces", "\n"));
402 
403     return interface;
404 }
405 
406 
407 
408 u_char         *
var_interfaces(struct variable * vp,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)409 var_interfaces(struct variable * vp,
410                oid * name,
411                size_t * length,
412                int exact, size_t * var_len, WriteMethod ** write_method)
413 {
414     if (header_generic(vp, name, length, exact, var_len, write_method) ==
415         MATCH_FAILED)
416         return NULL;
417 
418     switch (vp->magic) {
419     case NETSNMP_IFNUMBER:
420         long_return = Interface_Scan_Get_Count();
421         return (u_char *) & long_return;
422     default:
423         DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_interfaces\n",
424                     vp->magic));
425     }
426     return NULL;
427 }
428 
429 #ifdef USE_SYSCTL_IFLIST
430 
431 static u_char  *if_list = 0;
432 static const u_char *if_list_end;
433 static size_t   if_list_size = 0;
434 
435 struct small_ifaddr {
436     struct in_addr  sifa_addr;
437     struct in_addr  sifa_netmask;
438     struct in_addr  sifa_broadcast;
439 };
440 
441 static int      Interface_Scan_By_Index(int, struct if_msghdr *, char *,
442                                         struct small_ifaddr *);
443 static int      Interface_Get_Ether_By_Index(int, u_char *);
444 
445 static int
Interface_Scan_By_Index(int iindex,struct if_msghdr * if_msg,char * if_name,struct small_ifaddr * sifa)446 Interface_Scan_By_Index(int iindex,
447                         struct if_msghdr *if_msg,
448                         char *if_name, struct small_ifaddr *sifa)
449 {
450     u_char         *cp;
451     struct if_msghdr *ifp;
452     int             have_ifinfo = 0, have_addr = 0;
453 
454     if (NULL != sifa)
455         memset(sifa, 0, sizeof(*sifa));
456     for (cp = if_list; cp < if_list_end; cp += ifp->ifm_msglen) {
457         ifp = (struct if_msghdr *) cp;
458         DEBUGMSGTL(("mibII/interfaces", "ifm_type = %d, ifm_index = %d\n",
459                     ifp->ifm_type, ifp->ifm_index));
460 
461         switch (ifp->ifm_type) {
462         case RTM_IFINFO:
463             {
464                 const struct sockaddr *a;
465 
466                 if (ifp->ifm_index == iindex) {
467                     a = get_address(ifp + 1, ifp->ifm_addrs, RTA_IFP);
468                     if (a == NULL)
469                         return 0;
470                     sprintf(if_name, "%.*s", ((const u_char *) a)[5],
471                             ((const struct sockaddr_in *) a)->sin_zero);
472                     *if_msg = *ifp;
473                     ++have_ifinfo;
474                 }
475             }
476             break;
477         case RTM_NEWADDR:
478             {
479                 struct ifa_msghdr *ifap = (struct ifa_msghdr *) cp;
480 
481                 if ((NULL != sifa) && (ifap->ifam_index == iindex)) {
482                     const struct in_addr *ia;
483 
484                     /*
485                      * I don't know why the normal get_address() doesn't
486                      * work on IRIX 6.2.  Maybe this has to do with the
487                      * existence of struct sockaddr_new.  Hopefully, on
488                      * other systems we can simply use get_in_address
489                      * three times, with (ifap+1) as the starting
490                      * address.
491                      */
492 
493                     sifa->sifa_netmask =
494                         *((struct in_addr *) ((char *) (ifap + 1) + 4));
495                     ia = get_in_address((char *) (ifap + 1) + 8,
496                                         ifap->ifam_addrs &=
497                                         ~RTA_NETMASK, RTA_IFA);
498                     if (ia == NULL)
499                         return 0;
500 
501                     sifa->sifa_addr = *ia;
502                     ia = get_in_address((char *) (ifap + 1) + 8,
503                                         ifap->ifam_addrs &= ~RTA_NETMASK,
504                                         RTA_BRD);
505                     if (ia == NULL)
506                         return 0;
507 
508                     sifa->sifa_broadcast = *ia;
509                     ++have_addr;
510                 }
511             }
512             break;
513         default:
514             DEBUGMSGTL(("mibII/interfaces",
515                         "routing socket: unknown message type %d\n",
516                         ifp->ifm_type));
517         }
518     }
519     if (have_ifinfo && (NULL == sifa) || (have_addr)) {
520         return 0;
521     } else if (have_ifinfo && !(if_msg->ifm_flags & IFF_UP))
522         return 0;
523     else {
524         return -1;
525     }
526 }
527 
528 int
Interface_Scan_Get_Count(void)529 Interface_Scan_Get_Count(void)
530 {
531     u_char         *cp;
532     struct if_msghdr *ifp;
533     long            n = 0;
534 
535     Interface_Scan_Init();
536 
537     if (if_list_size) {
538         for (cp = if_list, n = 0; cp < if_list_end; cp += ifp->ifm_msglen) {
539             ifp = (struct if_msghdr *) cp;
540 
541             if (ifp->ifm_type == RTM_IFINFO) {
542                 ++n;
543             }
544         }
545     }
546     return n;
547 }
548 
549 void
Interface_Scan_Init(void)550 Interface_Scan_Init(void)
551 {
552     int             name[] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0 };
553     size_t          size;
554 
555     if (sysctl(name, sizeof(name) / sizeof(int), 0, &size, 0, 0) == -1) {
556         snmp_log(LOG_ERR, "sysctl size fail\n");
557     } else {
558         if (if_list == 0 || if_list_size < size) {
559             if (if_list != 0) {
560                 free(if_list);
561             }
562             if_list      = NULL;
563             if_list_size = 0;
564             if_list_end  = 0;
565             if ((if_list = malloc(size)) == NULL) {
566                 snmp_log(LOG_ERR,
567                          "out of memory allocating route table (size = %d)\n", size);
568                 return;
569             }
570             if_list_size = size;
571         } else {
572             size = if_list_size;
573         }
574         if (sysctl(name, sizeof(name) / sizeof(int),
575                    if_list, &size, 0, 0) == -1) {
576             snmp_log(LOG_ERR, "sysctl get fail\n");
577         }
578         if_list_end = if_list + size;
579     }
580 }
581 
582 u_char         *
var_ifEntry(struct variable * vp,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)583 var_ifEntry(struct variable *vp,
584             oid * name,
585             size_t * length,
586             int exact, size_t * var_len, WriteMethod ** write_method)
587 {
588     int             interface;
589     struct if_msghdr if_msg;
590     static char     if_name[100];
591     conf_if_list   *if_ptr;
592     char           *cp;
593 
594     interface =
595         header_ifEntry(vp, name, length, exact, var_len, write_method);
596     if (interface == MATCH_FAILED)
597         return NULL;
598 
599     if (Interface_Scan_By_Index(interface, &if_msg, if_name, NULL) != 0)
600         return NULL;
601     if_ptr = netsnmp_access_interface_entry_overrides_get(if_name);
602 
603     switch (vp->magic) {
604     case NETSNMP_IFINDEX:
605         long_return = interface;
606         return (u_char *) & long_return;
607     case NETSNMP_IFDESCR:
608         cp = if_name;
609         *var_len = strlen(if_name);
610         return (u_char *) cp;
611     case NETSNMP_IFTYPE:
612         if (if_ptr)
613             long_return = if_ptr->type;
614         else
615         long_return = (long) if_msg.ifm_data.ifi_type;
616         return (u_char *) & long_return;
617     case NETSNMP_IFMTU:
618         long_return = (long) if_msg.ifm_data.ifi_mtu;
619         return (u_char *) & long_return;
620     case NETSNMP_IFSPEED:
621         if (if_ptr)
622             long_return = if_ptr->speed;
623         else {
624 #if HAVE_STRUCT_IFNET_IF_BAUDRATE_IFS_VALUE
625         long_return = (u_long) if_msg.ifm_data.ifi_baudrate.ifs_value <<
626             if_msg.ifm_data.ifi_baudrate.ifs_log2;
627 #else
628         long_return = (u_long) if_msg.ifm_data.ifi_baudrate;
629 #endif
630         }
631         return (u_char *) & long_return;
632     case NETSNMP_IFPHYSADDRESS:
633         /*
634          * XXX
635          */
636         return NULL;
637     case NETSNMP_IFADMINSTATUS:
638         long_return = if_msg.ifm_flags & IFF_UP ? 1 : 2;
639         return (u_char *) & long_return;
640     case NETSNMP_IFOPERSTATUS:
641         long_return = if_msg.ifm_flags & IFF_RUNNING ? 1 : 2;
642         return (u_char *) & long_return;
643         /*
644          * ifLastChange
645          */
646     case NETSNMP_IFINOCTETS:
647         long_return = (u_long) if_msg.ifm_data.ifi_ibytes;
648         return (u_char *) & long_return;
649     case NETSNMP_IFINUCASTPKTS:
650         long_return =
651             (u_long) if_msg.ifm_data.ifi_ipackets -
652             if_msg.ifm_data.ifi_imcasts;
653         return (u_char *) & long_return;
654     case NETSNMP_IFINNUCASTPKTS:
655         long_return = (u_long) if_msg.ifm_data.ifi_imcasts;
656         return (u_char *) & long_return;
657     case NETSNMP_IFINDISCARDS:
658         long_return = (u_long) if_msg.ifm_data.ifi_iqdrops;
659         return (u_char *) & long_return;
660     case NETSNMP_IFINERRORS:
661         long_return = (u_long) if_msg.ifm_data.ifi_ierrors;
662         return (u_char *) & long_return;
663     case NETSNMP_IFINUNKNOWNPROTOS:
664         long_return = (u_long) if_msg.ifm_data.ifi_noproto;
665         return (u_char *) & long_return;
666     case NETSNMP_IFOUTOCTETS:
667         long_return = (u_long) if_msg.ifm_data.ifi_obytes;
668         return (u_char *) & long_return;
669     case NETSNMP_IFOUTUCASTPKTS:
670         long_return =
671             (u_long) if_msg.ifm_data.ifi_opackets -
672             if_msg.ifm_data.ifi_omcasts;
673         return (u_char *) & long_return;
674     case NETSNMP_IFOUTNUCASTPKTS:
675         long_return = (u_long) if_msg.ifm_data.ifi_omcasts;
676         return (u_char *) & long_return;
677     case NETSNMP_IFOUTDISCARDS:
678 #ifdef if_odrops
679         long_return = (u_long) if_msg.ifm_data.ifi_odrops;
680 #else
681 #if NETSNMP_NO_DUMMY_VALUES
682         return NULL;
683 #endif
684         long_return = 0;
685 #endif
686         return (u_char *) & long_return;
687     case NETSNMP_IFOUTERRORS:
688         long_return = (u_long) if_msg.ifm_data.ifi_oerrors;
689         return (u_char *) & long_return;
690     case NETSNMP_IFLASTCHANGE:
691 #ifdef irix6
692         long_return = 0;
693 #else
694         if (if_msg.ifm_data.ifi_lastchange.tv_sec == 0 &&
695 #if STRUCT_IFNET_HAS_IF_LASTCHANGE_TV_NSEC
696             if_msg.ifm_data.ifi_lastchange.tv_nsec == 0
697 #else
698             if_msg.ifm_data.ifi_lastchange.tv_usec == 0
699 #endif
700            )
701             long_return = 0;
702         else if (if_msg.ifm_data.ifi_lastchange.tv_sec < starttime.tv_sec)
703             long_return = 0;
704         else {
705             long_return = (u_long)
706                 ((if_msg.ifm_data.ifi_lastchange.tv_sec -
707                   starttime.tv_sec) * 100 +
708                  (
709 #if STRUCT_IFNET_HAS_IF_LASTCHANGE_TV_NSEC
710                   if_msg.ifm_data.ifi_lastchange.tv_nsec / 1000
711 #else
712                   if_msg.ifm_data.ifi_lastchange.tv_usec
713 #endif
714                   - starttime.tv_usec) / 10000);
715         }
716 #endif
717         return (u_char *) & long_return;
718     default:
719         return 0;
720     }
721 }
722 
723 int
Interface_Scan_Next(short * Index,char * Name,struct ifnet * Retifnet,struct in_ifaddr * Retin_ifaddr)724 Interface_Scan_Next(short *Index,
725                     char *Name,
726                     struct ifnet *Retifnet, struct in_ifaddr *Retin_ifaddr)
727 {
728     return 0;
729 }
730 
731 int
Interface_Scan_NextInt(int * Index,char * Name,struct ifnet * Retifnet,struct in_ifaddr * Retin_ifaddr)732 Interface_Scan_NextInt(int *Index,
733                     char *Name,
734                     struct ifnet *Retifnet, struct in_ifaddr *Retin_ifaddr)
735 {
736     return 0;
737 }
738 
739 #else                           /* not USE_SYSCTL_IFLIST */
740 
741         /*********************
742 	 *
743 	 *  Kernel & interface information,
744 	 *   and internal forward declarations
745 	 *
746 	 *********************/
747 
748 #ifndef HAVE_NET_IF_MIB_H
749 
750 #ifndef solaris2
751 #ifndef hpux11
752 static int      Interface_Scan_By_Index(int, char *, struct ifnet *,
753                                         struct in_ifaddr *);
754 static int      Interface_Get_Ether_By_Index(int, u_char *);
755 #else
756 static int      Interface_Scan_By_Index(int, char *, nmapi_phystat *);
757 #endif
758 #endif
759 
760 
761 
762         /*********************
763 	 *
764 	 *  System specific implementation functions
765 	 *
766 	 *********************/
767 
768 
769 #ifndef solaris2
770 #ifndef hpux
771 
772 u_char         *
var_ifEntry(struct variable * vp,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)773 var_ifEntry(struct variable *vp,
774             oid * name,
775             size_t * length,
776             int exact, size_t * var_len, WriteMethod ** write_method)
777 {
778     static struct ifnet ifnet;
779     int             interface;
780     static struct in_ifaddr in_ifaddr;
781     static char     Name[16];
782     char           *cp;
783     conf_if_list   *if_ptr;
784 
785     interface =
786         header_ifEntry(vp, name, length, exact, var_len, write_method);
787     if (interface == MATCH_FAILED)
788         return NULL;
789 
790     Interface_Scan_By_Index(interface, Name, &ifnet, &in_ifaddr);
791     if_ptr = netsnmp_access_interface_entry_overrides_get(Name);
792 
793     switch (vp->magic) {
794     case NETSNMP_IFINDEX:
795         long_return = interface;
796         return (u_char *) & long_return;
797     case NETSNMP_IFDESCR:
798         cp = Name;
799         *var_len = strlen(cp);
800         return (u_char *) cp;
801     case NETSNMP_IFTYPE:
802         if (if_ptr)
803             long_return = if_ptr->type;
804         else {
805 #if HAVE_STRUCT_IFNET_IF_TYPE
806             long_return = ifnet.if_type;
807 #else
808             long_return = 1;    /* OTHER */
809 #endif
810         }
811         return (u_char *) & long_return;
812     case NETSNMP_IFMTU:{
813             long_return = (long) ifnet.if_mtu;
814             return (u_char *) & long_return;
815         }
816     case NETSNMP_IFSPEED:
817         if (if_ptr)
818             long_return = if_ptr->speed;
819         else {
820 #if HAVE_STRUCT_IFNET_IF_BAUDRATE
821             long_return = ifnet.if_baudrate;
822 #elif HAVE_STRUCT_IFNET_IF_SPEED
823             long_return = ifnet.if_speed;
824 #elif HAVE_STRUCT_IFNET_IF_TYPE && defined(IFT_ETHER)
825             if (ifnet.if_type == IFT_ETHER)
826                 long_return = 10000000;
827             if (ifnet.if_type == IFT_P10)
828                 long_return = 10000000;
829             if (ifnet.if_type == IFT_P80)
830                 long_return = 80000000;
831             if (ifnet.if_type == IFT_ISDNBASIC)
832                 long_return = 64000;    /* EDSS1 only */
833             if (ifnet.if_type == IFT_ISDNPRIMARY)
834                 long_return = 64000 * 30;
835 #else
836 #if NETSNMP_NO_DUMMY_VALUES
837             return NULL;
838 #endif
839             long_return = (u_long) 10000000;
840 #endif
841         }
842         return (u_char *) & long_return;
843     case NETSNMP_IFPHYSADDRESS:
844         Interface_Get_Ether_By_Index(interface, return_buf);
845 #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
846 	*var_len = 0;
847 #else
848         if ((return_buf[0] == 0) && (return_buf[1] == 0) &&
849             (return_buf[2] == 0) && (return_buf[3] == 0) &&
850             (return_buf[4] == 0) && (return_buf[5] == 0))
851             *var_len = 0;
852         else
853             *var_len = 6;
854 #endif
855         return (u_char *) return_buf;
856     case NETSNMP_IFADMINSTATUS:
857         long_return = ifnet.if_flags & IFF_UP ? 1 : 2;
858         return (u_char *) & long_return;
859     case NETSNMP_IFOPERSTATUS:
860         long_return = ifnet.if_flags & IFF_RUNNING ? 1 : 2;
861         return (u_char *) & long_return;
862     case NETSNMP_IFLASTCHANGE:
863 #if defined(HAVE_STRUCT_IFNET_IF_LASTCHANGE_TV_SEC) && !(defined(freebsd2) && __FreeBSD_version < 199607)
864         /*
865          * XXX - SNMP's ifLastchange is time when op. status changed
866          * * FreeBSD's if_lastchange is time when packet was input or output
867          * * (at least in 2.1.0-RELEASE. Changed in later versions of the kernel?)
868          */
869         /*
870          * FreeBSD's if_lastchange before the 2.1.5 release is the time when
871          * * a packet was last input or output.  In the 2.1.5 and later releases,
872          * * this is fixed, thus the 199607 comparison.
873          */
874         if (ifnet.if_lastchange.tv_sec == 0 &&
875             ifnet.if_lastchange.tv_usec == 0)
876             long_return = 0;
877         else if (ifnet.if_lastchange.tv_sec < starttime.tv_sec)
878             long_return = 0;
879         else {
880             long_return = (u_long)
881                 ((ifnet.if_lastchange.tv_sec - starttime.tv_sec) * 100
882                  + (ifnet.if_lastchange.tv_usec -
883                     starttime.tv_usec) / 10000);
884         }
885 #else
886 #if NETSNMP_NO_DUMMY_VALUES
887         return NULL;
888 #endif
889         long_return = 0;        /* XXX */
890 #endif
891         return (u_char *) & long_return;
892     case NETSNMP_IFINOCTETS:
893 #ifdef HAVE_STRUCT_IFNET_IF_IBYTES
894 #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
895         long_return = (u_long) ifnet.if_ibytes & 0xffffffff;
896 #else
897         long_return = (u_long) ifnet.if_ibytes;
898 #endif
899 #else
900 #if NETSNMP_NO_DUMMY_VALUES
901         return NULL;
902 #endif
903         long_return = (u_long) ifnet.if_ipackets * 308; /* XXX */
904 #endif
905         return (u_char *) & long_return;
906     case NETSNMP_IFINUCASTPKTS:
907         {
908 #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
909             long_return = (u_long) ifnet.if_ipackets & 0xffffffff;
910 #else
911             long_return = (u_long) ifnet.if_ipackets;
912 #endif
913 #if HAVE_STRUCT_IFNET_IF_IMCASTS
914 #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
915             long_return -= (u_long) ifnet.if_imcasts & 0xffffffff;
916 #else
917             long_return -= (u_long) ifnet.if_imcasts;
918 #endif
919 #endif
920         }
921         return (u_char *) & long_return;
922     case NETSNMP_IFINNUCASTPKTS:
923 #if HAVE_STRUCT_IFNET_IF_IMCASTS
924 #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
925         long_return = (u_long) ifnet.if_imcasts & 0xffffffff;
926 #else
927         long_return = (u_long) ifnet.if_imcasts;
928 #endif
929 #else
930 #if NETSNMP_NO_DUMMY_VALUES
931         return NULL;
932 #endif
933         long_return = (u_long) 0;       /* XXX */
934 #endif
935         return (u_char *) & long_return;
936     case NETSNMP_IFINDISCARDS:
937 #if HAVE_STRUCT_IFNET_IF_IQDROPS
938 #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
939         long_return = (u_long) ifnet.if_iqdrops & 0xffffffff;
940 #else
941         long_return = (u_long) ifnet.if_iqdrops;
942 #endif
943 #else
944 #if NETSNMP_NO_DUMMY_VALUES
945         return NULL;
946 #endif
947         long_return = (u_long) 0;       /* XXX */
948 #endif
949         return (u_char *) & long_return;
950     case NETSNMP_IFINERRORS:
951 #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
952         long_return = (u_long) ifnet.if_ierrors & 0xffffffff;
953 #else
954         long_return = (u_long) ifnet.if_ierrors;
955 #endif
956         return (u_char *) & long_return;
957     case NETSNMP_IFINUNKNOWNPROTOS:
958 #if HAVE_STRUCT_IFNET_IF_NOPROTO
959 #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
960         long_return = (u_long) ifnet.if_noproto & 0xffffffff;
961 #else
962         long_return = (u_long) ifnet.if_noproto;
963 #endif
964 #else
965 #if NETSNMP_NO_DUMMY_VALUES
966         return NULL;
967 #endif
968         long_return = (u_long) 0;       /* XXX */
969 #endif
970         return (u_char *) & long_return;
971     case NETSNMP_IFOUTOCTETS:
972 #ifdef HAVE_STRUCT_IFNET_IF_OBYTES
973 #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
974         long_return = (u_long) ifnet.if_obytes & 0xffffffff;
975 #else
976         long_return = (u_long) ifnet.if_obytes;
977 #endif
978 #else
979 #if NETSNMP_NO_DUMMY_VALUES
980         return NULL;
981 #endif
982         long_return = (u_long) ifnet.if_opackets * 308; /* XXX */
983 #endif
984         return (u_char *) & long_return;
985     case NETSNMP_IFOUTUCASTPKTS:
986         {
987 #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
988             long_return = (u_long) ifnet.if_opackets & 0xffffffff;
989 #else
990             long_return = (u_long) ifnet.if_opackets;
991 #endif
992 #if HAVE_STRUCT_IFNET_IF_OMCASTS
993 #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
994             long_return -= (u_long) ifnet.if_omcasts & 0xffffffff;
995 #else
996             long_return -= (u_long) ifnet.if_omcasts;
997 #endif
998 #endif
999         }
1000         return (u_char *) & long_return;
1001     case NETSNMP_IFOUTNUCASTPKTS:
1002 #if HAVE_STRUCT_IFNET_IF_OMCASTS
1003 #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
1004         long_return = (u_long) ifnet.if_omcasts & 0xffffffff;
1005 #else
1006         long_return = (u_long) ifnet.if_omcasts;
1007 #endif
1008 #else
1009 #if NETSNMP_NO_DUMMY_VALUES
1010         return NULL;
1011 #endif
1012         long_return = (u_long) 0;       /* XXX */
1013 #endif
1014         return (u_char *) & long_return;
1015     case NETSNMP_IFOUTDISCARDS:
1016 #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
1017         long_return = ifnet.if_snd.ifq_drops & 0xffffffff;
1018 #else
1019         long_return = ifnet.if_snd.ifq_drops;
1020 #endif
1021         return (u_char *) & long_return;
1022     case NETSNMP_IFOUTERRORS:
1023 #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
1024         long_return = ifnet.if_oerrors & 0xffffffff;
1025 #else
1026         long_return = ifnet.if_oerrors;
1027 #endif
1028         return (u_char *) & long_return;
1029     case NETSNMP_IFOUTQLEN:
1030 #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
1031         long_return = ifnet.if_snd.ifq_len & 0xffffffff;
1032 #else
1033         long_return = ifnet.if_snd.ifq_len;
1034 #endif
1035         return (u_char *) & long_return;
1036     case NETSNMP_IFSPECIFIC:
1037         *var_len = nullOidLen;
1038         return (u_char *) nullOid;
1039     default:
1040         DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ifEntry\n",
1041                     vp->magic));
1042     }
1043     return NULL;
1044 }
1045 
1046 #else                           /* hpux */
1047 
1048 u_char         *
var_ifEntry(struct variable * vp,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)1049 var_ifEntry(struct variable *vp,
1050             oid * name,
1051             size_t * length,
1052             int exact, size_t * var_len, WriteMethod ** write_method)
1053 {
1054 #if defined(hpux11)
1055     static nmapi_phystat ifnet;
1056 #else
1057     static struct ifnet ifnet;
1058 #endif
1059     register int    interface;
1060 #if !defined(hpux11)
1061     static struct in_ifaddr in_ifaddrVar;
1062 #endif
1063 #if defined(hpux11)
1064     static char     Name[MAX_PHYSADDR_LEN];
1065 #else
1066     static char     Name[16];
1067 #endif
1068     register char  *cp;
1069 #if HAVE_STRUCT_IFNET_IF_LASTCHANGE_TV_SEC
1070     struct timeval  now;
1071 #endif
1072 #if !defined(hpux11)
1073     struct nmparms  hp_nmparms;
1074     static mib_ifEntry hp_ifEntry;
1075     int             hp_fd;
1076     int             hp_len = sizeof(hp_ifEntry);
1077 #endif
1078     conf_if_list   *if_ptr;
1079 
1080     interface =
1081         header_ifEntry(vp, name, length, exact, var_len, write_method);
1082     if (interface == MATCH_FAILED)
1083         return NULL;
1084 
1085 #if defined(hpux11)
1086     Interface_Scan_By_Index(interface, Name, &ifnet);
1087 #else
1088     Interface_Scan_By_Index(interface, Name, &ifnet, &in_ifaddrVar);
1089 #endif
1090 
1091 #if !defined(hpux11)
1092     /*
1093      * Additional information about the interfaces is available under
1094      * HP-UX through the network management interface '/dev/netman'
1095      */
1096     hp_ifEntry.ifIndex = interface;
1097     hp_nmparms.objid = ID_ifEntry;
1098     hp_nmparms.buffer = (char *) &hp_ifEntry;
1099     hp_nmparms.len = &hp_len;
1100     if ((hp_fd = open("/dev/netman", O_RDONLY)) != -1) {
1101         if (ioctl(hp_fd, NMIOGET, &hp_nmparms) != -1) {
1102             close(hp_fd);
1103         } else {
1104             close(hp_fd);
1105             hp_fd = -1;         /* failed */
1106         }
1107     }
1108 #endif
1109     if_ptr = netsnmp_access_interface_entry_overrides_get(Name);
1110 
1111     switch (vp->magic) {
1112     case NETSNMP_IFINDEX:
1113         long_return = interface;
1114         return (u_char *) & long_return;
1115     case NETSNMP_IFDESCR:
1116 #if defined(hpux11)
1117         cp = ifnet.if_entry.ifDescr;
1118 #else
1119         if (hp_fd != -1)
1120             cp = hp_ifEntry.ifDescr;
1121         else
1122             cp = Name;
1123 #endif
1124         *var_len = strlen(cp);
1125         return (u_char *) cp;
1126     case NETSNMP_IFTYPE:
1127         if (if_ptr)
1128             long_return = if_ptr->type;
1129         else {
1130 #if defined(hpux11)
1131         long_return = ifnet.if_entry.ifType;
1132 #else
1133         if (hp_fd != -1)
1134             long_return = hp_ifEntry.ifType;
1135         else
1136             long_return = 1;    /* OTHER */
1137 #endif
1138         }
1139         return (u_char *) & long_return;
1140     case NETSNMP_IFMTU:{
1141 #if defined(hpux11)
1142             long_return = (long) ifnet.if_entry.ifMtu;
1143 #else
1144             long_return = (long) ifnet.if_mtu;
1145 #endif
1146             return (u_char *) & long_return;
1147         }
1148     case NETSNMP_IFSPEED:
1149         if (if_ptr)
1150             long_return = if_ptr->speed;
1151         else {
1152 #if defined(hpux11)
1153         long_return = ifnet.if_entry.ifSpeed;
1154 #else
1155         if (hp_fd != -1)
1156             long_return = hp_ifEntry.ifSpeed;
1157         else
1158             long_return = (u_long) 1;   /* OTHER */
1159 #endif
1160         }
1161         return (u_char *) & long_return;
1162     case NETSNMP_IFPHYSADDRESS:
1163 #if defined(hpux11)
1164         *var_len = ifnet.if_entry.ifPhysAddress.o_length;
1165         return (u_char *) ifnet.if_entry.ifPhysAddress.o_bytes;
1166 #else
1167         Interface_Get_Ether_By_Index(interface, return_buf);
1168         if ((return_buf[0] == 0) && (return_buf[1] == 0) &&
1169             (return_buf[2] == 0) && (return_buf[3] == 0) &&
1170             (return_buf[4] == 0) && (return_buf[5] == 0))
1171             *var_len = 0;
1172         else
1173             *var_len = 6;
1174         return (u_char *) return_buf;
1175 #endif
1176     case NETSNMP_IFADMINSTATUS:
1177 #if defined(hpux11)
1178         long_return = ifnet.if_entry.ifAdmin;
1179 #else
1180         long_return = ifnet.if_flags & IFF_UP ? 1 : 2;
1181 #endif
1182         return (u_char *) & long_return;
1183     case NETSNMP_IFOPERSTATUS:
1184 #if defined(hpux11)
1185         long_return = ifnet.if_entry.ifOper;
1186 #else
1187         long_return = ifnet.if_flags & IFF_RUNNING ? 1 : 2;
1188 #endif
1189         return (u_char *) & long_return;
1190     case NETSNMP_IFLASTCHANGE:
1191 #if defined(hpux11)
1192         long_return = ifnet.if_entry.ifLastChange;
1193 #else
1194         if (hp_fd != -1)
1195             long_return = hp_ifEntry.ifLastChange;
1196         else
1197             long_return = 0;    /* XXX */
1198 #endif
1199         return (u_char *) & long_return;
1200     case NETSNMP_IFINOCTETS:
1201 #if defined(hpux11)
1202         long_return = ifnet.if_entry.ifInOctets;
1203 #else
1204         if (hp_fd != -1)
1205             long_return = hp_ifEntry.ifInOctets;
1206         else
1207             long_return = (u_long) ifnet.if_ipackets * 308;     /* XXX */
1208 #endif
1209         return (u_char *) & long_return;
1210     case NETSNMP_IFINUCASTPKTS:
1211 #if defined(hpux11)
1212         long_return = ifnet.if_entry.ifInUcastPkts;
1213 #else
1214         if (hp_fd != -1)
1215             long_return = hp_ifEntry.ifInUcastPkts;
1216         else
1217             long_return = (u_long) ifnet.if_ipackets;
1218 #endif
1219         return (u_char *) & long_return;
1220     case NETSNMP_IFINNUCASTPKTS:
1221 #if defined(hpux11)
1222         long_return = ifnet.if_entry.ifInNUcastPkts;
1223 #else
1224         if (hp_fd != -1)
1225             long_return = hp_ifEntry.ifInNUcastPkts;
1226         else
1227             long_return = (u_long) 0;   /* XXX */
1228 #endif
1229         return (u_char *) & long_return;
1230     case NETSNMP_IFINDISCARDS:
1231 #if defined(hpux11)
1232         long_return = ifnet.if_entry.ifInDiscards;
1233 #else
1234         if (hp_fd != -1)
1235             long_return = hp_ifEntry.ifInDiscards;
1236         else
1237             long_return = (u_long) 0;   /* XXX */
1238 #endif
1239         return (u_char *) & long_return;
1240     case NETSNMP_IFINERRORS:
1241 #if defined(hpux11)
1242         long_return = ifnet.if_entry.ifInErrors;
1243 #else
1244         long_return = ifnet.if_ierrors;
1245 #endif
1246         return (u_char *) & long_return;
1247     case NETSNMP_IFINUNKNOWNPROTOS:
1248 #if defined(hpux11)
1249         long_return = ifnet.if_entry.ifInUnknownProtos;
1250 #else
1251         if (hp_fd != -1)
1252             long_return = hp_ifEntry.ifInUnknownProtos;
1253         else
1254             long_return = (u_long) 0;   /* XXX */
1255 #endif
1256         return (u_char *) & long_return;
1257     case NETSNMP_IFOUTOCTETS:
1258 #if defined(hpux11)
1259         long_return = ifnet.if_entry.ifOutOctets;
1260 #else
1261         if (hp_fd != -1)
1262             long_return = hp_ifEntry.ifOutOctets;
1263         else
1264             long_return = (u_long) ifnet.if_opackets * 308;     /* XXX */
1265 #endif
1266         return (u_char *) & long_return;
1267     case NETSNMP_IFOUTUCASTPKTS:
1268 #if defined(hpux11)
1269         long_return = ifnet.if_entry.ifOutUcastPkts;
1270 #else
1271         if (hp_fd != -1)
1272             long_return = hp_ifEntry.ifOutUcastPkts;
1273         else
1274             long_return = (u_long) ifnet.if_opackets;
1275 #endif
1276         return (u_char *) & long_return;
1277     case NETSNMP_IFOUTNUCASTPKTS:
1278 #if defined(hpux11)
1279         long_return = ifnet.if_entry.ifOutNUcastPkts;
1280 #else
1281         if (hp_fd != -1)
1282             long_return = hp_ifEntry.ifOutNUcastPkts;
1283         else
1284             long_return = (u_long) 0;   /* XXX */
1285 #endif
1286         return (u_char *) & long_return;
1287     case NETSNMP_IFOUTDISCARDS:
1288 #if defined(hpux11)
1289         long_return = ifnet.if_entry.ifOutDiscards;
1290 #else
1291         long_return = ifnet.if_snd.ifq_drops;
1292 #endif
1293         return (u_char *) & long_return;
1294     case NETSNMP_IFOUTERRORS:
1295 #if defined(hpux11)
1296         long_return = ifnet.if_entry.ifOutErrors;
1297 #else
1298         long_return = ifnet.if_oerrors;
1299 #endif
1300         return (u_char *) & long_return;
1301     case NETSNMP_IFOUTQLEN:
1302 #if defined(hpux11)
1303         long_return = ifnet.if_entry.ifOutQlen;
1304 #else
1305         long_return = ifnet.if_snd.ifq_len;
1306 #endif
1307         return (u_char *) & long_return;
1308     case NETSNMP_IFSPECIFIC:
1309         *var_len = nullOidLen;
1310         return (u_char *) nullOid;
1311     default:
1312         DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ifEntry\n",
1313                     vp->magic));
1314     }
1315     return NULL;
1316 }
1317 
1318 #endif                          /* hpux */
1319 #else                           /* solaris2 */
1320 
1321 static int
IF_cmp(void * addr,void * ep)1322 IF_cmp(void *addr, void *ep)
1323 {
1324     DEBUGMSGTL(("mibII/interfaces", "... IF_cmp %d %d\n",
1325                 ((mib2_ifEntry_t *) ep)->ifIndex,
1326                 ((mib2_ifEntry_t *) addr)->ifIndex));
1327     if (((mib2_ifEntry_t *) ep)->ifIndex ==
1328         ((mib2_ifEntry_t *) addr)->ifIndex)
1329         return (0);
1330     else
1331         return (1);
1332 }
1333 
1334 u_char         *
var_ifEntry(struct variable * vp,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)1335 var_ifEntry(struct variable * vp,
1336             oid * name,
1337             size_t * length,
1338             int exact, size_t * var_len, WriteMethod ** write_method)
1339 {
1340     int             interface;
1341     mib2_ifEntry_t  ifstat;
1342     conf_if_list   *if_ptr = NULL;
1343 
1344     interface =
1345         header_ifEntry(vp, name, length, exact, var_len, write_method);
1346     if (interface == MATCH_FAILED)
1347         return NULL;
1348 
1349     if (getMibstat(MIB_INTERFACES, &ifstat, sizeof(mib2_ifEntry_t),
1350                    GET_EXACT, &IF_cmp, &interface) != 0) {
1351         DEBUGMSGTL(("mibII/interfaces", "... no mib stats\n"));
1352         return NULL;
1353     }
1354     /*
1355      * hmmm.. where to get the interface name to check overrides?
1356      *
1357      * if_ptr = netsnmp_access_interface_entry_overrides_get(Name);
1358      */
1359     switch (vp->magic) {
1360     case NETSNMP_IFINDEX:
1361         long_return = ifstat.ifIndex;
1362         return (u_char *) & long_return;
1363     case NETSNMP_IFDESCR:
1364         *var_len = ifstat.ifDescr.o_length;
1365         (void) memcpy(return_buf, ifstat.ifDescr.o_bytes, *var_len);
1366         return (u_char *) return_buf;
1367     case NETSNMP_IFTYPE:
1368         if (if_ptr)
1369             long_return = if_ptr->type;
1370         else
1371         long_return = (u_long) ifstat.ifType;
1372         return (u_char *) & long_return;
1373     case NETSNMP_IFMTU:
1374         long_return = (u_long) ifstat.ifMtu;
1375         return (u_char *) & long_return;
1376     case NETSNMP_IFSPEED:
1377         if (if_ptr)
1378             long_return = if_ptr->speed;
1379         else
1380         long_return = (u_long) ifstat.ifSpeed;
1381         return (u_char *) & long_return;
1382     case NETSNMP_IFPHYSADDRESS:
1383         *var_len = ifstat.ifPhysAddress.o_length;
1384         (void) memcpy(return_buf, ifstat.ifPhysAddress.o_bytes, *var_len);
1385         return (u_char *) return_buf;
1386     case NETSNMP_IFADMINSTATUS:
1387         long_return = (u_long) ifstat.ifAdminStatus;
1388         return (u_char *) & long_return;
1389     case NETSNMP_IFOPERSTATUS:
1390         long_return = (u_long) ifstat.ifOperStatus;
1391         return (u_char *) & long_return;
1392     case NETSNMP_IFLASTCHANGE:
1393         long_return = (u_long) ifstat.ifLastChange;
1394         return (u_char *) & long_return;
1395     case NETSNMP_IFINOCTETS:
1396         long_return = (u_long) ifstat.ifInOctets;
1397         return (u_char *) & long_return;
1398     case NETSNMP_IFINUCASTPKTS:
1399         long_return = (u_long) ifstat.ifInUcastPkts;
1400         return (u_char *) & long_return;
1401     case NETSNMP_IFINNUCASTPKTS:
1402         long_return = (u_long) ifstat.ifInNUcastPkts;
1403         return (u_char *) & long_return;
1404     case NETSNMP_IFINDISCARDS:
1405         long_return = (u_long) ifstat.ifInDiscards;
1406         return (u_char *) & long_return;
1407     case NETSNMP_IFINERRORS:
1408         long_return = (u_long) ifstat.ifInErrors;
1409         return (u_char *) & long_return;
1410     case NETSNMP_IFINUNKNOWNPROTOS:
1411         long_return = (u_long) ifstat.ifInUnknownProtos;
1412         return (u_char *) & long_return;
1413     case NETSNMP_IFOUTOCTETS:
1414         long_return = (u_long) ifstat.ifOutOctets;
1415         return (u_char *) & long_return;
1416     case NETSNMP_IFOUTUCASTPKTS:
1417         long_return = (u_long) ifstat.ifOutUcastPkts;
1418         return (u_char *) & long_return;
1419     case NETSNMP_IFOUTNUCASTPKTS:
1420         long_return = (u_long) ifstat.ifOutNUcastPkts;
1421         return (u_char *) & long_return;
1422     case NETSNMP_IFOUTDISCARDS:
1423         long_return = (u_long) ifstat.ifOutDiscards;
1424         return (u_char *) & long_return;
1425     case NETSNMP_IFOUTERRORS:
1426         long_return = (u_long) ifstat.ifOutErrors;
1427         return (u_char *) & long_return;
1428     case NETSNMP_IFOUTQLEN:
1429         long_return = (u_long) ifstat.ifOutQLen;
1430         return (u_char *) & long_return;
1431     case NETSNMP_IFSPECIFIC:
1432 	long_return = (u_long) ifstat.ifSpecific;
1433 	return (u_char *) & long_return;
1434     default:
1435         DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ifEntry\n",
1436                     vp->magic));
1437     }
1438     return NULL;
1439 }
1440 
1441 #endif                          /* solaris2 */
1442 
1443 
1444 
1445         /*********************
1446 	 *
1447 	 *  Internal implementation functions
1448 	 *
1449 	 *********************/
1450 
1451 
1452 #ifndef solaris2
1453 
1454 #if !defined(sunV3) && !defined(linux) && !defined(hpux11)
1455 static struct in_ifaddr savein_ifaddr;
1456 #endif
1457 #if !defined(hpux11)
1458 static struct ifnet *ifnetaddr, saveifnet, *saveifnetaddr;
1459 static char     saveName[16];
1460 #endif
1461 static int      saveIndex = 0;
1462 
1463 /**
1464 * Determines network interface speed. It is system specific. Only linux
1465 * realization is made.
1466 */
getIfSpeed(int fd,struct ifreq ifr,unsigned int defaultspeed)1467 unsigned int getIfSpeed(int fd, struct ifreq ifr, unsigned int defaultspeed)
1468 {
1469 #ifdef linux
1470     return netsnmp_linux_interface_get_if_speed(fd, ifr.ifr_name, defaultspeed);
1471 #else /*!linux*/
1472     return defaultspeed;
1473 #endif
1474 }
1475 
1476 void
Interface_Scan_Init(void)1477 Interface_Scan_Init(void)
1478 {
1479 #ifdef linux
1480     char            line[256], ifname_buf[64], *ifname, *ptr;
1481     struct ifreq    ifrq;
1482     struct ifnet  **ifnetaddr_ptr;
1483     FILE           *devin;
1484     int             i, fd;
1485     conf_if_list   *if_ptr;
1486     /*
1487      * scanline_2_2:
1488      *  [               IN                        ]
1489      *   byte pkts errs drop fifo frame cmprs mcst |
1490      *  [               OUT                               ]
1491      *   byte pkts errs drop fifo colls carrier compressed
1492      */
1493     uintmax_t       rec_pkt, rec_oct, rec_err, rec_drop;
1494     uintmax_t       snd_pkt, snd_oct, snd_err, snd_drop, coll;
1495     const char     *scan_line_2_2 =
1496         "%"   SCNuMAX " %"  SCNuMAX " %"  SCNuMAX " %"  SCNuMAX
1497         " %*" SCNuMAX " %*" SCNuMAX " %*" SCNuMAX " %*" SCNuMAX
1498         " %"  SCNuMAX " %"  SCNuMAX " %"  SCNuMAX " %"  SCNuMAX
1499         " %*" SCNuMAX " %"  SCNuMAX;
1500     const char     *scan_line_2_0 =
1501         "%"   SCNuMAX " %"  SCNuMAX " %*" SCNuMAX " %*" SCNuMAX
1502         " %*" SCNuMAX " %"  SCNuMAX " %"  SCNuMAX " %*" SCNuMAX
1503         " %*" SCNuMAX " %"  SCNuMAX;
1504     const char     *scan_line_to_use;
1505     struct timeval et;                              /* elapsed time */
1506 
1507 #endif
1508 
1509 #if !defined(hpux11) && defined(IFNET_SYMBOL)
1510     auto_nlist(IFNET_SYMBOL, (char *) &ifnetaddr, sizeof(ifnetaddr));
1511 #endif
1512     saveIndex = 0;
1513 
1514 
1515 #ifdef linux
1516     /*  disallow reloading of structures too often */
1517     netsnmp_get_monotonic_clock(&et);
1518     if ( et.tv_sec < LastLoad + MINLOADFREQ ) {     /*  only reload so often */
1519       ifnetaddr = ifnetaddr_list;                   /*  initialize pointer */
1520       return;
1521     }
1522     LastLoad = et.tv_sec;
1523 
1524     /*
1525      * free old list:
1526      */
1527     while (ifnetaddr_list) {
1528         struct ifnet   *old = ifnetaddr_list;
1529         ifnetaddr_list = ifnetaddr_list->if_next;
1530         free(old->if_name);
1531         free(old->if_unit);
1532         free(old);
1533     }
1534 
1535     ifnetaddr = 0;
1536     ifnetaddr_ptr = &ifnetaddr_list;
1537 
1538     if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1539         DEBUGMSGTL(("snmpd",
1540                     "socket open failure in Interface_Scan_Init\n"));
1541         return; /** exit (1); **/
1542     }
1543 
1544     /*
1545      * build up ifnetaddr list by hand:
1546      */
1547 
1548     /*
1549      * at least linux v1.3.53 says EMFILE without reason...
1550      */
1551     if (!(devin = fopen("/proc/net/dev", "r"))) {
1552         close(fd);
1553         NETSNMP_LOGONCE((LOG_ERR, "cannot open /proc/net/dev.\n"));
1554         return; /** exit (1); **/
1555     }
1556 
1557     i = 0;
1558 
1559     /*
1560      * read the second line (a header) and determine the fields we
1561      * should read from.  This should be done in a better way by
1562      * actually looking for the field names we want.  But thats too
1563      * much work for today.  -- Wes
1564      */
1565     fgets(line, sizeof(line), devin);
1566     fgets(line, sizeof(line), devin);
1567     if (strstr(line, "compressed")) {
1568         scan_line_to_use = scan_line_2_2;
1569         DEBUGMSGTL(("mibII/interfaces",
1570                     "using linux 2.2 kernel /proc/net/dev\n"));
1571     } else {
1572         scan_line_to_use = scan_line_2_0;
1573         DEBUGMSGTL(("mibII/interfaces",
1574                     "using linux 2.0 kernel /proc/net/dev\n"));
1575     }
1576 
1577 
1578     while (fgets(line, sizeof(line), devin)) {
1579         struct ifnet   *nnew;
1580         char           *stats, *ifstart = line;
1581 
1582         if (line[strlen(line) - 1] == '\n')
1583             line[strlen(line) - 1] = '\0';
1584 
1585         while (*ifstart && *ifstart == ' ')
1586             ifstart++;
1587 
1588         if (!*ifstart || ((stats = strrchr(ifstart, ':')) == NULL)) {
1589             snmp_log(LOG_ERR,
1590                      "/proc/net/dev data format error, line ==|%s|", line);
1591             continue;
1592         }
1593         if ((scan_line_to_use == scan_line_2_2) && ((stats - line) < 6)) {
1594             snmp_log(LOG_ERR,
1595                      "/proc/net/dev data format error, line ==|%s|", line);
1596         }
1597 
1598         *stats   = 0;
1599         strlcpy(ifname_buf, ifstart, sizeof(ifname_buf));
1600         *stats++ = ':';
1601         while (*stats == ' ')
1602             stats++;
1603 
1604         if ((scan_line_to_use == scan_line_2_2 &&
1605              sscanf(stats, scan_line_to_use, &rec_oct, &rec_pkt, &rec_err,
1606                     &rec_drop, &snd_oct, &snd_pkt, &snd_err, &snd_drop,
1607                     &coll) != 9) || (scan_line_to_use == scan_line_2_0
1608                                      && sscanf(stats, scan_line_to_use,
1609                                                &rec_pkt, &rec_err,
1610                                                &snd_pkt, &snd_err,
1611                                                &coll) != 5)) {
1612             if ((scan_line_to_use == scan_line_2_2)
1613                 && !strstr(line, "No statistics available"))
1614                 snmp_log(LOG_ERR,
1615                          "/proc/net/dev data format error, line ==|%s|",
1616                          line);
1617             continue;
1618         }
1619 
1620         nnew = (struct ifnet *) calloc(1, sizeof(struct ifnet));
1621         if (nnew == NULL)
1622             break;              /* alloc error */
1623 
1624         /*
1625          * chain in:
1626          */
1627         *ifnetaddr_ptr = nnew;
1628         ifnetaddr_ptr = &nnew->if_next;
1629         i++;
1630 
1631         /*
1632          * linux previous to 1.3.~13 may miss transmitted loopback pkts:
1633          */
1634         if (!strcmp(ifname_buf, "lo") && rec_pkt > 0 && !snd_pkt)
1635             snd_pkt = rec_pkt;
1636 
1637         nnew->if_ipackets = rec_pkt & 0xffffffff;
1638         nnew->if_ierrors = rec_err;
1639         nnew->if_opackets = snd_pkt & 0xffffffff;
1640         nnew->if_oerrors = snd_err;
1641         nnew->if_collisions = coll;
1642         if (scan_line_to_use == scan_line_2_2) {
1643             nnew->if_ibytes = rec_oct & 0xffffffff;
1644             nnew->if_obytes = snd_oct & 0xffffffff;
1645             nnew->if_iqdrops = rec_drop;
1646             nnew->if_snd.ifq_drops = snd_drop;
1647         } else {
1648             nnew->if_ibytes = (rec_pkt * 308) & 0xffffffff;
1649             nnew->if_obytes = (snd_pkt * 308) & 0xffffffff;
1650         }
1651 
1652         /*
1653          * ifnames are given as ``   eth0'': split in ``eth'' and ``0'':
1654          */
1655         for (ifname = ifname_buf; *ifname && *ifname == ' '; ifname++);
1656 
1657         /*
1658          * set name and interface# :
1659          */
1660         nnew->if_name = (char *) strdup(ifname);
1661         for (ptr = nnew->if_name; *ptr && (*ptr < '0' || *ptr > '9');
1662              ptr++);
1663         nnew->if_unit = strdup(*ptr ? ptr : "");
1664         *ptr = 0;
1665 
1666         strlcpy(ifrq.ifr_name, ifname, sizeof(ifrq.ifr_name));
1667         if (ioctl(fd, SIOCGIFADDR, &ifrq) < 0)
1668             memset((char *) &nnew->if_addr, 0, sizeof(nnew->if_addr));
1669         else
1670             nnew->if_addr = ifrq.ifr_addr;
1671 
1672         strlcpy(ifrq.ifr_name, ifname, sizeof(ifrq.ifr_name));
1673         if (ioctl(fd, SIOCGIFBRDADDR, &ifrq) < 0)
1674             memset((char *) &nnew->ifu_broadaddr, 0,
1675                    sizeof(nnew->ifu_broadaddr));
1676         else
1677             nnew->ifu_broadaddr = ifrq.ifr_broadaddr;
1678 
1679         strlcpy(ifrq.ifr_name, ifname, sizeof(ifrq.ifr_name));
1680         if (ioctl(fd, SIOCGIFNETMASK, &ifrq) < 0)
1681             memset((char *) &nnew->ia_subnetmask, 0,
1682                    sizeof(nnew->ia_subnetmask));
1683         else
1684             nnew->ia_subnetmask = ifrq.ifr_netmask;
1685 
1686         strlcpy(ifrq.ifr_name, ifname, sizeof(ifrq.ifr_name));
1687         nnew->if_flags = ioctl(fd, SIOCGIFFLAGS, &ifrq) < 0
1688             ? 0 : ifrq.ifr_flags;
1689 
1690         nnew->if_type = 0;
1691 
1692         /*
1693          * NOTE: this ioctl does not guarantee 6 bytes of a physaddr.
1694          * In particular, a 'sit0' interface only appears to get back
1695          * 4 bytes of sa_data.
1696          */
1697         memset(ifrq.ifr_hwaddr.sa_data, (0), IFHWADDRLEN);
1698         strlcpy(ifrq.ifr_name, ifname, sizeof(ifrq.ifr_name));
1699         if (ioctl(fd, SIOCGIFHWADDR, &ifrq) < 0)
1700             memset(nnew->if_hwaddr, (0), IFHWADDRLEN);
1701         else {
1702             memcpy(nnew->if_hwaddr, ifrq.ifr_hwaddr.sa_data, IFHWADDRLEN);
1703 
1704 #ifdef ARPHRD_LOOPBACK
1705             switch (ifrq.ifr_hwaddr.sa_family) {
1706             case ARPHRD_ETHER:
1707                 nnew->if_type = 6;
1708                 break;
1709             case ARPHRD_TUNNEL:
1710             case ARPHRD_TUNNEL6:
1711 #ifdef ARPHRD_IPGRE
1712             case ARPHRD_IPGRE:
1713 #endif
1714             case ARPHRD_SIT:
1715                 nnew->if_type = 131;
1716                 break;          /* tunnel */
1717             case ARPHRD_SLIP:
1718             case ARPHRD_CSLIP:
1719             case ARPHRD_SLIP6:
1720             case ARPHRD_CSLIP6:
1721                 nnew->if_type = 28;
1722                 break;          /* slip */
1723             case ARPHRD_PPP:
1724                 nnew->if_type = 23;
1725                 break;          /* ppp */
1726             case ARPHRD_LOOPBACK:
1727                 nnew->if_type = 24;
1728                 break;          /* softwareLoopback */
1729             case ARPHRD_FDDI:
1730                 nnew->if_type = 15;
1731                 break;
1732             case ARPHRD_ARCNET:
1733                 nnew->if_type = 35;
1734                 break;
1735             case ARPHRD_LOCALTLK:
1736                 nnew->if_type = 42;
1737                 break;
1738 #ifdef ARPHRD_HIPPI
1739             case ARPHRD_HIPPI:
1740                 nnew->if_type = 47;
1741                 break;
1742 #endif
1743 #ifdef ARPHRD_ATM
1744             case ARPHRD_ATM:
1745                 nnew->if_type = 37;
1746                 break;
1747 #endif
1748                 /*
1749                  * XXX: more if_arp.h:ARPHDR_xxx to IANAifType mappings...
1750                  */
1751             }
1752 #endif
1753         }
1754 
1755         strlcpy(ifrq.ifr_name, ifname, sizeof(ifrq.ifr_name));
1756         nnew->if_metric = ioctl(fd, SIOCGIFMETRIC, &ifrq) < 0
1757             ? 0 : ifrq.ifr_metric;
1758 
1759 #ifdef SIOCGIFMTU
1760         strlcpy(ifrq.ifr_name, ifname, sizeof(ifrq.ifr_name));
1761         nnew->if_mtu = (ioctl(fd, SIOCGIFMTU, &ifrq) < 0)
1762             ? 0 : ifrq.ifr_mtu;
1763 #else
1764         nnew->if_mtu = 0;
1765 #endif
1766 
1767         if_ptr = netsnmp_access_interface_entry_overrides_get(ifname);
1768         if (if_ptr) {
1769             nnew->if_type = if_ptr->type;
1770             nnew->if_speed = if_ptr->speed;
1771         } else {
1772             /*
1773              * do only guess if_type from name, if we could not read
1774              * * it before from SIOCGIFHWADDR
1775              */
1776             unsigned int defaultspeed = NOMINAL_LINK_SPEED;
1777                 if (!(nnew->if_flags & IFF_RUNNING)) {
1778                     /*
1779                      * use speed 0 if the if speed cannot be determined *and* the
1780                      * interface is down
1781                      */
1782                     defaultspeed = 0;
1783                 }
1784 
1785             if (!nnew->if_type)
1786                 nnew->if_type = if_type_from_name(nnew->if_name);
1787             switch(nnew->if_type) {
1788             case 6:
1789                 nnew->if_speed = getIfSpeed(fd, ifrq, defaultspeed);
1790                 break;
1791             case 24:
1792                 nnew->if_speed = 10000000;
1793                 break;
1794             case 9:
1795                 nnew->if_speed = 4000000;
1796                 break;
1797             default:
1798                 nnew->if_speed = 0;
1799             }
1800             /*Zero speed means link problem*/
1801             if(nnew->if_speed == 0 && nnew->if_flags & IFF_UP){
1802                 nnew->if_flags &= ~IFF_RUNNING;
1803             }
1804         }
1805 
1806     }                           /* while (fgets ... */
1807 
1808     ifnetaddr = ifnetaddr_list;
1809 
1810     if (snmp_get_do_debugging()) {
1811         {
1812             struct ifnet   *x = ifnetaddr;
1813             DEBUGMSGTL(("mibII/interfaces", "* see: known interfaces:"));
1814             while (x) {
1815                 DEBUGMSG(("mibII/interfaces", " %s", x->if_name));
1816                 x = x->if_next;
1817             }
1818             DEBUGMSG(("mibII/interfaces", "\n"));
1819         }                       /* XXX */
1820     }
1821 
1822     fclose(devin);
1823     close(fd);
1824 #endif                          /* linux */
1825 }
1826 
1827 
1828 
1829 #if defined(sunV3) || defined(linux)
1830 /*
1831  * **  4.2 BSD doesn't have ifaddr
1832  * **
1833  */
1834 int
Interface_Scan_Next(short * Index,char * Name,struct ifnet * Retifnet,struct in_ifaddr * dummy)1835 Interface_Scan_Next(short *Index,
1836                     char *Name,
1837                     struct ifnet *Retifnet, struct in_ifaddr *dummy)
1838 {
1839     int returnIndex = 0;
1840     int ret;
1841     if (Index)
1842         returnIndex = *Index;
1843 
1844     ret = Interface_Scan_NextInt( &returnIndex, Name, Retifnet, dummy );
1845     if (Index)
1846         *Index = (returnIndex & 0x8fff);
1847     return ret;
1848 }
1849 
1850 int
Interface_Scan_NextInt(int * Index,char * Name,struct ifnet * Retifnet,struct in_ifaddr * dummy)1851 Interface_Scan_NextInt(int *Index,
1852                     char *Name,
1853                     struct ifnet *Retifnet, struct in_ifaddr *dummy)
1854 {
1855     struct ifnet    ifnet;
1856 #if !defined(linux)
1857     register char  *cp;
1858 #endif
1859 
1860     while (ifnetaddr) {
1861         /*
1862          *      Get the "ifnet" structure and extract the device name
1863          */
1864 #ifndef linux
1865         if (!NETSNMP_KLOOKUP(ifnetaddr, (char *) &ifnet, sizeof ifnet)) {
1866             DEBUGMSGTL(("mibII/interfaces:Interface_Scan_Next", "klookup failed\n"));
1867             break;
1868         }
1869 
1870         if (!NETSNMP_KLOOKUP(ifnet.if_name, (char *) saveName, sizeof saveName)) {
1871             DEBUGMSGTL(("mibII/interfaces:Interface_Scan_Next", "klookup failed\n"));
1872             break;
1873         }
1874 
1875        /*
1876         * The purpose of this comparison is lost in the mists of time.
1877         * It's been around at least cmu-snmp 2.1.2 for SUNv3 systems and
1878         * was applied to linux systems during the cmu-snmp-linux project.
1879         * No-one now knows what it was intended for, and it breaks IPv6
1880         * tunnel interfaces, so it's been moved out of the Linux code block.
1881         */
1882         if (strcmp(saveName, "ip") == 0) {
1883             ifnetaddr = ifnet.if_next;
1884             continue;
1885         }
1886 #else
1887         ifnet = *ifnetaddr;
1888         strlcpy(saveName, ifnet.if_name, sizeof(saveName));
1889 #endif
1890 
1891         saveName[sizeof(saveName) - 1] = '\0';
1892 #ifdef linux
1893         strlcat(saveName, ifnet.if_unit, sizeof(saveName));
1894 #else
1895 #ifdef NETSNMP_FEATURE_CHECKIN
1896         /* this exists here just so we don't copy ifdef logic elsewhere */
1897         netsnmp_feature_require(string_append_int);
1898 #endif
1899         cp = (char *) strchr(saveName, '\0');
1900         string_append_int(cp, ifnet.if_unit);
1901 #endif
1902         if (1 || strcmp(saveName, "lo0") != 0) {        /* XXX */
1903 
1904             if (Index)
1905                 *Index = ++saveIndex;
1906             if (Retifnet)
1907                 *Retifnet = ifnet;
1908             if (Name)
1909                 strcpy(Name, saveName);
1910             saveifnet = ifnet;
1911             saveifnetaddr = ifnetaddr;
1912             ifnetaddr = ifnet.if_next;
1913 
1914             return (1);         /* DONE */
1915         }
1916         ifnetaddr = ifnet.if_next;
1917     }
1918     return (0);                 /* EOF */
1919 }
1920 
1921 #ifdef linux
1922 int
Interface_Index_By_Name(char * Name,int Len)1923 Interface_Index_By_Name(char *Name, int Len)
1924 {
1925     int             ifIndex = 0;
1926     char            ifName[20];
1927 
1928     Interface_Scan_Init();
1929     while (Interface_Scan_NextInt(&ifIndex, ifName, NULL, NULL)
1930            && strcmp(Name, ifName));
1931     return ifIndex;
1932 }
1933 #endif
1934 
1935 
1936 #else                           /* sunV3 || linux */
1937 
1938 #if defined(netbsd1) || defined(openbsd2)
1939 #define ia_next ia_list.tqe_next
1940 #define if_next if_list.tqe_next
1941 #endif
1942 
1943 #if defined(hpux11)
1944 int
Interface_Scan_Next(short * Index,char * Name,nmapi_phystat * Retifnet)1945 Interface_Scan_Next(short *Index, char *Name, nmapi_phystat * Retifnet)
1946 {
1947     int returnIndex = 0;
1948     int ret;
1949     if (Index)
1950         returnIndex = *Index;
1951 
1952     ret = Interface_Scan_NextInt( &returnIndex, Name, Retifnet );
1953     if (Index)
1954         *Index = (returnIndex & 0x8fff);
1955     return ret;
1956 }
1957 
1958 
1959 int
Interface_Scan_NextInt(int * Index,char * Name,nmapi_phystat * Retifnet)1960 Interface_Scan_NextInt(int *Index, char *Name, nmapi_phystat * Retifnet)
1961 {
1962     static nmapi_phystat *if_ptr = (nmapi_phystat *) 0;
1963     int             count = Interface_Scan_Get_Count();
1964     unsigned int    ulen;
1965     int             ret;
1966 
1967     if (!if_ptr) {
1968         if (count) {
1969             if_ptr =
1970                 (nmapi_phystat *) malloc(sizeof(nmapi_phystat) * count);
1971             if (if_ptr == NULL)
1972                 return (0);
1973 
1974         } else
1975             return (0);         /* EOF */
1976     }
1977 
1978     if (saveIndex >= count)
1979         return (0);             /* EOF */
1980 
1981     ulen = (unsigned int) count *sizeof(nmapi_phystat);
1982     if ((ret = get_physical_stat(if_ptr, &ulen)) < 0)
1983         return (0);             /* EOF */
1984 
1985     if (Retifnet)
1986         *Retifnet = if_ptr[saveIndex];
1987     if (Name)
1988         strcpy(Name, if_ptr[saveIndex].nm_device);
1989     saveIndex++;
1990     if (Index)
1991         *Index = saveIndex;
1992     return (1);                 /* DONE */
1993 }
1994 
1995 #else                           /* hpux11 */
1996 int
Interface_Scan_Next(short * Index,char * Name,struct ifnet * Retifnet,struct in_ifaddr * Retin_ifaddr)1997 Interface_Scan_Next(short *Index,
1998                     char *Name,
1999                     struct ifnet *Retifnet, struct in_ifaddr *Retin_ifaddr)
2000 {
2001     int returnIndex = 0;
2002     int ret;
2003     if (Index)
2004         returnIndex = *Index;
2005 
2006     ret = Interface_Scan_NextInt( &returnIndex, Name, Retifnet, Retin_ifaddr );
2007     if (Index)
2008         *Index = (returnIndex & 0x8fff);
2009     return ret;
2010 }
2011 
2012 
2013 int
Interface_Scan_NextInt(int * Index,char * Name,struct ifnet * Retifnet,struct in_ifaddr * Retin_ifaddr)2014 Interface_Scan_NextInt(int *Index,
2015                     char *Name,
2016                     struct ifnet *Retifnet, struct in_ifaddr *Retin_ifaddr)
2017 {
2018     struct ifnet    ifnet;
2019     struct in_ifaddr *ia, in_ifaddr;
2020     short           has_ipaddr = 0;
2021 #if !HAVE_STRUCT_IFNET_IF_XNAME
2022     register char  *cp;
2023 #endif
2024 
2025     while (ifnetaddr) {
2026         /*
2027          *      Get the "ifnet" structure and extract the device name
2028          */
2029         if (!NETSNMP_KLOOKUP(ifnetaddr, (char *) &ifnet, sizeof ifnet)) {
2030             DEBUGMSGTL(("mibII/interfaces:Interface_Scan_Next", "klookup failed\n"));
2031             break;
2032         }
2033 #if HAVE_STRUCT_IFNET_IF_XNAME
2034 #if defined(netbsd1) || defined(openbsd2)
2035         strlcpy(saveName, ifnet.if_xname, sizeof(saveName));
2036 #else
2037         if (!NETSNMP_KLOOKUP(ifnet.if_xname, (char *) saveName, sizeof saveName)) {
2038             DEBUGMSGTL(("mibII/interfaces:Interface_Scan_Next", "klookup failed\n"));
2039             break;
2040         }
2041 #endif
2042         saveName[sizeof(saveName) - 1] = '\0';
2043 #else
2044         if (!NETSNMP_KLOOKUP(ifnet.if_name, (char *) saveName, sizeof saveName)) {
2045             DEBUGMSGTL(("mibII/interfaces:Interface_Scan_Next", "klookup failed\n"));
2046             break;
2047         }
2048 
2049         saveName[sizeof(saveName) - 1] = '\0';
2050         cp = strchr(saveName, '\0');
2051 #ifdef NETSNMP_FEATURE_CHECKIN
2052         /* this exists here just so we don't copy ifdef logic elsewhere */
2053         netsnmp_feature_require(string_append_int);
2054 #endif
2055         string_append_int(cp, ifnet.if_unit);
2056 #endif
2057         if (1 || strcmp(saveName, "lo0") != 0) {        /* XXX */
2058             /*
2059              *  Try to find an address for this interface
2060              */
2061 
2062 #ifdef netbsd1
2063             ia = (struct in_ifaddr *) ifnet.if_addrlist.tqh_first;
2064 #elif defined(IFADDR_SYMBOL)
2065             auto_nlist(IFADDR_SYMBOL, (char *) &ia, sizeof(ia));
2066 #endif
2067             while (ia) {
2068                 if (!NETSNMP_KLOOKUP(ia, (char *) &in_ifaddr, sizeof(in_ifaddr))) {
2069                     DEBUGMSGTL(("mibII/interfaces:Interface_Scan_Next", "klookup failed\n"));
2070                     break;
2071                 }
2072                 {
2073 #ifdef netbsd1
2074 #define CP(x)	((char *)(x))
2075                     char           *cp;
2076                     struct sockaddr *sa;
2077                     cp = (CP(in_ifaddr.ia_ifa.ifa_addr) - CP(ia)) +
2078                         CP(&in_ifaddr);
2079                     sa = (struct sockaddr *) cp;
2080 
2081                     if (sa->sa_family == AF_INET)
2082 #endif
2083                         if (in_ifaddr.ia_ifp == ifnetaddr) {
2084                             has_ipaddr = 1;     /* this IF has IP-address */
2085                             break;
2086                         }
2087                 }
2088 #ifdef netbsd1
2089                 ia = (struct in_ifaddr *) in_ifaddr.ia_ifa.ifa_list.
2090                     tqe_next;
2091 #else
2092                 ia = in_ifaddr.ia_next;
2093 #endif
2094             }
2095 
2096 #if !defined(netbsd1) && !defined(freebsd2) && !defined(openbsd2) && !defined(HAVE_STRUCT_IFNET_IF_ADDRLIST)
2097             ifnet.if_addrlist = (struct ifaddr *) ia;   /* WRONG DATA TYPE; ONLY A FLAG */
2098 #endif
2099             /*
2100              * ifnet.if_addrlist = (struct ifaddr *)&ia->ia_ifa;
2101              *
2102              * WRONG DATA TYPE; ONLY A FLAG
2103              */
2104 
2105             if (Index)
2106                 *Index = ++saveIndex;
2107             if (Retifnet)
2108                 *Retifnet = ifnet;
2109             if (Retin_ifaddr && has_ipaddr)     /* assign the in_ifaddr only
2110                                                  * if the IF has IP-address */
2111                 *Retin_ifaddr = in_ifaddr;
2112             if (Name)
2113                 strcpy(Name, saveName);
2114             saveifnet = ifnet;
2115             saveifnetaddr = ifnetaddr;
2116             savein_ifaddr = in_ifaddr;
2117             ifnetaddr = ifnet.if_next;
2118 
2119             return (1);         /* DONE */
2120         }
2121         ifnetaddr = ifnet.if_next;
2122     }
2123     return (0);                 /* EOF */
2124 }
2125 
2126 #endif                          /* hpux11 */
2127 
2128 #endif                          /* sunV3 || linux */
2129 
2130 #if defined(hpux11)
2131 
2132 static int
Interface_Scan_By_Index(int Index,char * Name,nmapi_phystat * Retifnet)2133 Interface_Scan_By_Index(int Index, char *Name, nmapi_phystat * Retifnet)
2134 {
2135     int           i;
2136 
2137     Interface_Scan_Init();
2138     while (Interface_Scan_NextInt(&i, Name, Retifnet)) {
2139         if (i == Index)
2140             break;
2141     }
2142     if (i != Index)
2143         return (-1);            /* Error, doesn't exist */
2144     return (0);                 /* DONE */
2145 }
2146 
2147 #else                           /* hpux11 */
2148 
2149 static int
Interface_Scan_By_Index(int Index,char * Name,struct ifnet * Retifnet,struct in_ifaddr * Retin_ifaddr)2150 Interface_Scan_By_Index(int Index,
2151                         char *Name,
2152                         struct ifnet *Retifnet,
2153                         struct in_ifaddr *Retin_ifaddr)
2154 {
2155     int           i;
2156 
2157     Interface_Scan_Init();
2158     while (Interface_Scan_NextInt(&i, Name, Retifnet, Retin_ifaddr)) {
2159         if (i == Index)
2160             break;
2161     }
2162     if (i != Index)
2163         return (-1);            /* Error, doesn't exist */
2164     return (0);                 /* DONE */
2165 }
2166 
2167 #endif                          /* hpux11 */
2168 
2169 static int      Interface_Count = 0;
2170 
2171 #if defined(hpux11)
2172 
2173 int
Interface_Scan_Get_Count(void)2174 Interface_Scan_Get_Count(void)
2175 {
2176     if (!Interface_Count) {
2177         int             fd;
2178         struct nmparms  p;
2179         int             val;
2180         unsigned int    ulen;
2181         int             ret;
2182 
2183         if ((fd = open_mib("/dev/ip", O_RDONLY, 0, NM_ASYNC_OFF)) >= 0) {
2184             p.objid = ID_ifNumber;
2185             p.buffer = (void *) &val;
2186             ulen = sizeof(int);
2187             p.len = &ulen;
2188             if ((ret = get_mib_info(fd, &p)) == 0)
2189                 Interface_Count = val;
2190             close_mib(fd);
2191         }
2192     }
2193     return (Interface_Count);
2194 }
2195 
2196 #else                           /* hpux11 */
2197 
2198 int
Interface_Scan_Get_Count(void)2199 Interface_Scan_Get_Count(void)
2200 {
2201     static time_t   scan_time = 0;
2202     time_t          time_now = time(NULL);
2203 
2204     if (!Interface_Count || (time_now > scan_time + 60)) {
2205         scan_time = time_now;
2206         Interface_Scan_Init();
2207         Interface_Count = 0;
2208         while (Interface_Scan_NextInt(NULL, NULL, NULL, NULL) != 0) {
2209             Interface_Count++;
2210         }
2211     }
2212     return (Interface_Count);
2213 }
2214 
2215 
2216 static int
Interface_Get_Ether_By_Index(int Index,u_char * EtherAddr)2217 Interface_Get_Ether_By_Index(int Index, u_char * EtherAddr)
2218 {
2219     int             i;
2220 #if !(defined(linux) || defined(netbsd1) || defined(bsdi2) || defined(openbsd2))
2221     struct arpcom   arpcom;
2222 #else                           /* is linux or netbsd1 */
2223     struct arpcom {
2224         char            ac_enaddr[6];
2225     } arpcom;
2226 #if defined(netbsd1) || defined(bsdi2) || defined(openbsd2)
2227     struct sockaddr_dl sadl;
2228     struct ifaddr   ifaddr;
2229     u_long          ifaddraddr;
2230 #endif
2231 #endif
2232 
2233 #if defined(mips) || defined(hpux) || defined(osf4) || defined(osf3) || defined(osf5)
2234     memset(arpcom.ac_enaddr, 0, sizeof(arpcom.ac_enaddr));
2235 #else
2236     memset(&arpcom.ac_enaddr, 0, sizeof(arpcom.ac_enaddr));
2237 #endif
2238     memset(EtherAddr, 0, sizeof(arpcom.ac_enaddr));
2239 
2240     if (saveIndex != Index) {   /* Optimization! */
2241 
2242         Interface_Scan_Init();
2243 
2244         while (Interface_Scan_NextInt(&i, NULL, NULL, NULL) != 0) {
2245             if (i == Index)
2246                 break;
2247         }
2248         if (i != Index)
2249             return (-1);        /* Error, doesn't exist */
2250     }
2251 #ifdef freebsd2
2252     if (saveifnet.if_type != IFT_ETHER) {
2253         return (0);             /* Not an ethernet if */
2254     }
2255 #endif
2256     /*
2257      *  the arpcom structure is an extended ifnet structure which
2258      *  contains the ethernet address.
2259      */
2260 #ifndef linux
2261 #if !(defined(netbsd1) || defined(bsdi2) || defined(openbsd2))
2262     if (!NETSNMP_KLOOKUP(saveifnetaddr, (char *) &arpcom, sizeof arpcom)) {
2263         DEBUGMSGTL(("mibII/interfaces:Interface_Get_Ether_By_Index", "klookup failed\n"));
2264         return 0;
2265     }
2266 #else                           /* netbsd1 or bsdi2 or openbsd2 */
2267 
2268 #if defined(netbsd1) || defined(openbsd2)
2269 #define if_addrlist if_addrlist.tqh_first
2270 #define ifa_next    ifa_list.tqe_next
2271 #endif
2272 
2273     ifaddraddr = (unsigned long) saveifnet.if_addrlist;
2274     while (ifaddraddr) {
2275         if (!NETSNMP_KLOOKUP(ifaddraddr, (char *) &ifaddr, sizeof ifaddr)) {
2276             DEBUGMSGTL(("mibII/interfaces:Interface_Get_Ether_By_Index", "klookup failed\n"));
2277             break;
2278         }
2279         if (!NETSNMP_KLOOKUP(ifaddr.ifa_addr, (char *) &sadl, sizeof sadl)) {
2280             DEBUGMSGTL(("mibII/interfaces:Interface_Get_Ether_By_Index", "klookup failed\n"));
2281             break;
2282         }
2283         if (sadl.sdl_family == AF_LINK
2284             && (saveifnet.if_type == IFT_ETHER
2285                 || saveifnet.if_type == IFT_ISO88025
2286                 || saveifnet.if_type == IFT_FDDI)) {
2287             memcpy(arpcom.ac_enaddr, sadl.sdl_data + sadl.sdl_nlen,
2288                    sizeof(arpcom.ac_enaddr));
2289             break;
2290         }
2291         ifaddraddr = (unsigned long) ifaddr.ifa_next;
2292     }
2293 #endif                          /* netbsd1 or bsdi2 or openbsd2 */
2294 
2295 #else                           /* linux */
2296     memcpy(arpcom.ac_enaddr, saveifnetaddr->if_hwaddr, 6);
2297 #endif
2298     if (strncmp("lo", saveName, 2) == 0) {
2299         /*
2300          *  Loopback doesn't have a HW addr, so return 00:00:00:00:00:00
2301          */
2302         memset(EtherAddr, 0, sizeof(arpcom.ac_enaddr));
2303 
2304     } else {
2305 
2306 #if defined(mips) || defined(hpux) || defined(osf4) || defined(osf3)
2307         memcpy(EtherAddr, (char *) arpcom.ac_enaddr,
2308                sizeof(arpcom.ac_enaddr));
2309 #else
2310         memcpy(EtherAddr, (char *) &arpcom.ac_enaddr,
2311                sizeof(arpcom.ac_enaddr));
2312 #endif
2313 
2314 
2315     }
2316     return (0);                 /* DONE */
2317 }
2318 
2319 #endif                          /* hpux11 */
2320 
2321 #else                           /* solaris2 */
2322 
2323 int
Interface_Scan_Get_Count(void)2324 Interface_Scan_Get_Count(void)
2325 {
2326     int             i, sd;
2327 
2328     if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
2329         return (0);
2330     if (ioctl(sd, SIOCGIFNUM, &i) == -1) {
2331         close(sd);
2332         return (0);
2333     } else {
2334         close(sd);
2335         return (i);
2336     }
2337 }
2338 
2339 int
Interface_Index_By_Name(char * Name,int Len)2340 Interface_Index_By_Name(char *Name, int Len)
2341 {
2342     return (solaris2_if_nametoindex(Name, Len));
2343 }
2344 
2345 #endif                          /* solaris2 */
2346 
2347 #else                           /* HAVE_NET_IF_MIB_H */
2348 
2349 /*
2350  * This code attempts to do the right thing for FreeBSD.  Note that
2351  * the statistics could be gathered through use of of the
2352  * net.route.0.link.iflist.0 sysctl (which we already use to get the
2353  * hardware address of the interfaces), rather than using the ifmib
2354  * code, but eventually I will implement dot3Stats and we will have to
2355  * use the ifmib interface.  ifmib is also a much more natural way of
2356  * mapping the SNMP MIB onto sysctl(3).
2357  */
2358 
2359 #include <net/if.h>
2360 #include <net/if_dl.h>
2361 #include <net/if_mib.h>
2362 #include <net/route.h>
2363 
2364 static int      header_interfaces(struct variable *, oid *, size_t *, int,
2365                                   size_t *, WriteMethod ** write);
2366 static int      header_ifEntry(struct variable *, oid *, size_t *, int,
2367                                size_t *, WriteMethod ** write);
2368 
2369 static char    *physaddrbuf;
2370 static int      nphysaddrs;
2371 struct sockaddr_dl **physaddrs;
2372 
2373 void
init_interfaces_setup(void)2374 init_interfaces_setup(void)
2375 {
2376     int             naddrs, ilen, bit;
2377     static int      mib[6]
2378     = { CTL_NET, PF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
2379     char           *cp;
2380     size_t          len;
2381     struct rt_msghdr *rtm;
2382     struct if_msghdr *ifm;
2383     struct ifa_msghdr *ifam;
2384     struct sockaddr *sa;
2385 
2386     DEBUGMSGTL(("mibII:freebsd", "init_interfaces_setup\n"));
2387 
2388     naddrs = 0;
2389     if (physaddrs)
2390         free(physaddrs);
2391     if (physaddrbuf)
2392         free(physaddrbuf);
2393     physaddrbuf = 0;
2394     physaddrs = 0;
2395     nphysaddrs = 0;
2396     len = 0;
2397     if (sysctl(mib, 6, 0, &len, 0, 0) < 0) {
2398         DEBUGMSGTL(("mibII:freebsd", "sysctl 1 < 0\n"));
2399         return;
2400     }
2401 
2402     cp = physaddrbuf = malloc(len);
2403     if (physaddrbuf == 0)
2404         return;
2405     if (sysctl(mib, 6, physaddrbuf, &len, 0, 0) < 0) {
2406         free(physaddrbuf);
2407         physaddrbuf = 0;
2408         DEBUGMSGTL(("mibII:freebsd", "sysctl 2 < 0\n"));
2409         return;
2410     }
2411 
2412   loop:
2413     ilen = len;
2414     cp = physaddrbuf;
2415     while (ilen > 0) {
2416         rtm = (struct rt_msghdr *) cp;
2417         if (rtm->rtm_version != RTM_VERSION || rtm->rtm_type != RTM_IFINFO) {
2418             DEBUGMSGTL(("mibII:freebsd", "version:%d/%d type:%d/%d\n",
2419                         rtm->rtm_version, RTM_VERSION, rtm->rtm_type, RTM_IFINFO));
2420             free(physaddrs);
2421             physaddrs = 0;
2422             free(physaddrbuf);
2423             physaddrbuf = 0;
2424         }
2425         ifm = (struct if_msghdr *) rtm;
2426 #if defined(freebsd3) || defined(freebsd4) || defined(freebsd5)
2427         if (physaddrs != 0)
2428             physaddrs[naddrs] = (void *) (ifm + 1);
2429         naddrs++;
2430 #endif
2431         ilen -= ifm->ifm_msglen;
2432         cp += ifm->ifm_msglen;
2433         rtm = (struct rt_msghdr *) cp;
2434         while (ilen > 0 && rtm->rtm_type == RTM_NEWADDR) {
2435 #if defined(freebsd3) || defined(freebsd4) || defined(freebsd5)
2436             ilen -= rtm->rtm_msglen;
2437             cp += rtm->rtm_msglen;
2438 #else
2439             int             is_alias = 0;
2440             ifam = (struct ifa_msghdr *) rtm;
2441             ilen -= sizeof(*ifam);
2442             cp += sizeof(*ifam);
2443             sa = (struct sockaddr *) cp;
2444 #define ROUND(x) (((x) + sizeof(long) - 1) & ~sizeof(long))
2445             for (bit = 1; bit && ilen > 0; bit <<= 1) {
2446                 if (!(ifam->ifam_addrs & bit))
2447                     continue;
2448                 ilen -= ROUND(sa->sa_len);
2449                 cp += ROUND(sa->sa_len);
2450 
2451                 if (bit == RTA_IFA) {
2452                     if (physaddrs)
2453 #define satosdl(sa) ((struct sockaddr_dl *)(sa))
2454                         physaddrs[naddrs++]
2455                             = satosdl(sa);
2456                     else
2457                         naddrs++;
2458                 }
2459                 sa = (struct sockaddr *) cp;
2460             }
2461 #endif
2462             rtm = (struct rt_msghdr *) cp;
2463         }
2464     }
2465     DEBUGMSGTL(("mibII:freebsd", "found %d addrs\n", naddrs));
2466     if (physaddrs) {
2467         nphysaddrs = naddrs;
2468         return;
2469     }
2470     physaddrs = malloc(naddrs * sizeof(*physaddrs));
2471     if (physaddrs == 0)
2472         return;
2473     naddrs = 0;
2474     goto loop;
2475 
2476 }
2477 
2478 static int
get_phys_address(int iindex,char ** ap,int * len)2479 get_phys_address(int iindex, char **ap, int *len)
2480 {
2481     int             i;
2482     int             once = 1;
2483 
2484     do {
2485         for (i = 0; i < nphysaddrs; i++) {
2486             if (physaddrs[i]->sdl_index == iindex)
2487                 break;
2488         }
2489         if (i < nphysaddrs)
2490             break;
2491         init_interfaces_setup();
2492     } while (once--);
2493 
2494     DEBUGMSGTL(("mibII:freebsd", "get_phys_address %d/%d\n", i, nphysaddrs));
2495     if (i < nphysaddrs) {
2496         *ap = LLADDR(physaddrs[i]);
2497         *len = physaddrs[i]->sdl_alen;
2498         return 0;
2499     }
2500     return -1;
2501 }
2502 
2503 int
Interface_Scan_Get_Count(void)2504 Interface_Scan_Get_Count(void)
2505 {
2506     static int      count_oid[5] = { CTL_NET, PF_LINK, NETLINK_GENERIC,
2507         IFMIB_SYSTEM, IFMIB_IFCOUNT
2508     };
2509     size_t          len;
2510     int             count;
2511 
2512     len = sizeof count;
2513     if (sysctl(count_oid, 5, &count, &len, (void *) 0, (size_t) 0) < 0) {
2514         DEBUGMSGTL(("mibII:freebsd", "Interface_Scan_Get_Count err\n"));
2515         return -1;
2516     }
2517     DEBUGMSGTL(("mibII:freebsd", "Interface_Scan_Get_Count %d\n", count));
2518     return count;
2519 }
2520 
2521 
2522 u_char         *
var_ifEntry(struct variable * vp,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)2523 var_ifEntry(struct variable * vp,
2524             oid * name,
2525             size_t * length,
2526             int exact, size_t * var_len, WriteMethod ** write_method)
2527 {
2528     int             interface;
2529     static int      sname[6] = { CTL_NET, PF_LINK, NETLINK_GENERIC,
2530         IFMIB_IFDATA, 0, IFDATA_GENERAL
2531     };
2532     static struct ifmibdata ifmd;
2533     size_t          len;
2534     char           *cp;
2535     conf_if_list   *if_ptr = NULL;
2536 
2537     interface = header_ifEntry(vp, name, length, exact, var_len,
2538                                write_method);
2539     if (interface == MATCH_FAILED)
2540         return NULL;
2541 
2542     sname[4] = interface;
2543     len = sizeof ifmd;
2544     if (sysctl(sname, 6, &ifmd, &len, 0, 0) < 0) {
2545         DEBUGMSGTL(("mibII:freebsd", "var_ifEntry sysctl err\n"));
2546         return NULL;
2547     }
2548     /*
2549      * hmmm.. where to get the interface name to check overrides?
2550      *
2551      * if_ptr = netsnmp_access_interface_entry_overrides_get(Name);
2552      */
2553 
2554     switch (vp->magic) {
2555     case NETSNMP_IFINDEX:
2556         long_return = interface;
2557         return (u_char *) & long_return;
2558     case NETSNMP_IFDESCR:
2559         cp = ifmd.ifmd_name;
2560         *var_len = strlen(cp);
2561         return (u_char *) cp;
2562     case NETSNMP_IFTYPE:
2563         if (if_ptr)
2564             long_return = if_ptr->type;
2565         else
2566         long_return = ifmd.ifmd_data.ifi_type;
2567         return (u_char *) & long_return;
2568     case NETSNMP_IFMTU:
2569         long_return = (long) ifmd.ifmd_data.ifi_mtu;
2570         return (u_char *) & long_return;
2571     case NETSNMP_IFSPEED:
2572         if (if_ptr)
2573             long_return = if_ptr->speed;
2574         else
2575         long_return = ifmd.ifmd_data.ifi_baudrate;
2576         return (u_char *) & long_return;
2577     case NETSNMP_IFPHYSADDRESS:
2578         {
2579             char           *cp;
2580             if (get_phys_address(interface, &cp, var_len))
2581                 return NULL;
2582             else
2583                 return cp;
2584         }
2585     case NETSNMP_IFADMINSTATUS:
2586         long_return = ifmd.ifmd_flags & IFF_UP ? 1 : 2;
2587         return (u_char *) & long_return;
2588     case NETSNMP_IFOPERSTATUS:
2589         long_return = ifmd.ifmd_flags & IFF_RUNNING ? 1 : 2;
2590         return (u_char *) & long_return;
2591     case NETSNMP_IFLASTCHANGE:
2592         if (ifmd.ifmd_data.ifi_lastchange.tv_sec == 0 &&
2593             ifmd.ifmd_data.ifi_lastchange.tv_usec == 0) {
2594             long_return = 0;
2595         } else if (ifmd.ifmd_data.ifi_lastchange.tv_sec < starttime.tv_sec) {
2596             long_return = 0;
2597         } else {
2598             long_return = (u_long)
2599                 ((ifmd.ifmd_data.ifi_lastchange.tv_sec -
2600                   starttime.tv_sec) * 100 +
2601                  ((ifmd.ifmd_data.ifi_lastchange.tv_usec -
2602                    starttime.tv_usec) / 10000));
2603         }
2604         return (u_char *) & long_return;
2605     case NETSNMP_IFINOCTETS:
2606         long_return = (u_long) ifmd.ifmd_data.ifi_ibytes;
2607         return (u_char *) & long_return;
2608     case NETSNMP_IFINUCASTPKTS:
2609         long_return = (u_long) ifmd.ifmd_data.ifi_ipackets;
2610         long_return -= (u_long) ifmd.ifmd_data.ifi_imcasts;
2611         return (u_char *) & long_return;
2612     case NETSNMP_IFINNUCASTPKTS:
2613         long_return = (u_long) ifmd.ifmd_data.ifi_imcasts;
2614         return (u_char *) & long_return;
2615     case NETSNMP_IFINDISCARDS:
2616         long_return = (u_long) ifmd.ifmd_data.ifi_iqdrops;
2617         return (u_char *) & long_return;
2618     case NETSNMP_IFINERRORS:
2619         long_return = ifmd.ifmd_data.ifi_ierrors;
2620         return (u_char *) & long_return;
2621     case NETSNMP_IFINUNKNOWNPROTOS:
2622         long_return = (u_long) ifmd.ifmd_data.ifi_noproto;
2623         return (u_char *) & long_return;
2624     case NETSNMP_IFOUTOCTETS:
2625         long_return = (u_long) ifmd.ifmd_data.ifi_obytes;
2626         return (u_char *) & long_return;
2627     case NETSNMP_IFOUTUCASTPKTS:
2628         long_return = (u_long) ifmd.ifmd_data.ifi_opackets;
2629         long_return -= (u_long) ifmd.ifmd_data.ifi_omcasts;
2630         return (u_char *) & long_return;
2631     case NETSNMP_IFOUTNUCASTPKTS:
2632         long_return = (u_long) ifmd.ifmd_data.ifi_omcasts;
2633         return (u_char *) & long_return;
2634     case NETSNMP_IFOUTDISCARDS:
2635         long_return = ifmd.ifmd_snd_drops;
2636         return (u_char *) & long_return;
2637     case NETSNMP_IFOUTERRORS:
2638         long_return = ifmd.ifmd_data.ifi_oerrors;
2639         return (u_char *) & long_return;
2640     case NETSNMP_IFOUTQLEN:
2641         long_return = ifmd.ifmd_snd_len;
2642         return (u_char *) & long_return;
2643     case NETSNMP_IFSPECIFIC:
2644         *var_len = nullOidLen;
2645         return (u_char *) nullOid;
2646     default:
2647         DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ifEntry\n",
2648                     vp->magic));
2649     }
2650     return NULL;
2651 }
2652 
2653 #endif                          /* HAVE_NET_IF_MIB_H */
2654 #endif                          /* !USE_SYSCTL_IFLIST */
2655 
2656 #elif defined(HAVE_IPHLPAPI_H)  /* WIN32 cygwin */
2657 #include <iphlpapi.h>
2658 
2659 #ifndef NETSNMP_NO_WRITE_SUPPORT
2660 WriteMethod     writeIfEntry;
2661 #endif /* !NETSNMP_NO_WRITE_SUPPORT */
2662 long            admin_status = 0;
2663 long            oldadmin_status = 0;
2664 
2665 void
Interface_Scan_Init(void)2666 Interface_Scan_Init(void)
2667 {
2668 }
2669 
2670 static int
header_ifEntry(struct variable * vp,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)2671 header_ifEntry(struct variable *vp,
2672                oid * name,
2673                size_t * length,
2674                int exact, size_t * var_len, WriteMethod ** write_method)
2675 {
2676 #define IFENTRY_NAME_LENGTH	10
2677     oid             newname[MAX_OID_LEN];
2678     register int    ifIndex;
2679     int             result, count;
2680     DWORD           status = NO_ERROR;
2681     DWORD           dwActualSize = 0;
2682     PMIB_IFTABLE    pIfTable = NULL;
2683 
2684     DEBUGMSGTL(("mibII/interfaces", "var_ifEntry: "));
2685     DEBUGMSGOID(("mibII/interfaces", name, *length));
2686     DEBUGMSG(("mibII/interfaces", " %d\n", exact));
2687 
2688     memcpy((char *) newname, (char *) vp->name,
2689            (int) vp->namelen * sizeof(oid));
2690     /*
2691      * find "next" ifIndex
2692      */
2693 
2694     status = GetIfTable(pIfTable, &dwActualSize, TRUE);
2695     if (status == ERROR_INSUFFICIENT_BUFFER) {
2696         pIfTable = malloc(dwActualSize);
2697         if (pIfTable)
2698             GetIfTable(pIfTable, &dwActualSize, TRUE);
2699     }
2700     count = pIfTable->dwNumEntries;
2701     for (ifIndex = 0; ifIndex < count; ifIndex++) {
2702         newname[IFENTRY_NAME_LENGTH] =
2703             (oid) pIfTable->table[ifIndex].dwIndex;
2704         result =
2705             snmp_oid_compare(name, *length, newname,
2706                              (int) vp->namelen + 1);
2707         if ((exact && (result == 0)) || (!exact && (result < 0)))
2708             break;
2709     }
2710     if (ifIndex >= count) {
2711         DEBUGMSGTL(("mibII/interfaces", "... index out of range\n"));
2712         count = MATCH_FAILED;
2713         goto out;
2714     }
2715 
2716     memcpy((char *) name, (char *) newname,
2717            ((int) vp->namelen + 1) * sizeof(oid));
2718     *length = vp->namelen + 1;
2719     *write_method = 0;
2720     *var_len = sizeof(long);    /* default to 'long' results */
2721 
2722     DEBUGMSGTL(("mibII/interfaces", "... get I/F stats "));
2723     DEBUGMSGOID(("mibII/interfaces", name, *length));
2724     DEBUGMSG(("mibII/interfaces", "\n"));
2725 
2726     count = pIfTable->table[ifIndex].dwIndex;
2727 out:
2728     free(pIfTable);
2729     return count;
2730 }
2731 
2732 
2733 
2734 u_char         *
var_interfaces(struct variable * vp,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)2735 var_interfaces(struct variable * vp,
2736                oid * name,
2737                size_t * length,
2738                int exact, size_t * var_len, WriteMethod ** write_method)
2739 {
2740     if (header_generic(vp, name, length, exact, var_len, write_method) ==
2741         MATCH_FAILED)
2742         return NULL;
2743 
2744     switch (vp->magic) {
2745     case NETSNMP_IFNUMBER:
2746         netsnmp_assert(sizeof(DWORD) == sizeof(long_return));
2747         GetNumberOfInterfaces((DWORD *) &long_return);
2748         return (u_char *) & long_return;
2749     default:
2750         DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_interfaces\n",
2751                     vp->magic));
2752     }
2753     return NULL;
2754 }
2755 
2756 u_char         *
var_ifEntry(struct variable * vp,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)2757 var_ifEntry(struct variable * vp,
2758             oid * name,
2759             size_t * length,
2760             int exact, size_t * var_len, WriteMethod ** write_method)
2761 {
2762     int             ifIndex;
2763     static MIB_IFROW ifRow;
2764     conf_if_list   *if_ptr = NULL;
2765 
2766     ifIndex =
2767         header_ifEntry(vp, name, length, exact, var_len, write_method);
2768     if (ifIndex == MATCH_FAILED)
2769         return NULL;
2770     /*
2771      * hmmm.. where to get the interface name to check overrides?
2772      *
2773      * if_ptr = netsnmp_access_interface_entry_overrides_get(Name);
2774      */
2775 
2776     /*
2777      * Get the If Table Row by passing index as argument
2778      */
2779     ifRow.dwIndex = ifIndex;
2780     if (GetIfEntry(&ifRow) != NO_ERROR)
2781         return NULL;
2782     switch (vp->magic) {
2783     case NETSNMP_IFINDEX:
2784         long_return = ifIndex;
2785         return (u_char *) & long_return;
2786     case NETSNMP_IFDESCR:
2787         *var_len = ifRow.dwDescrLen;
2788         return (u_char *) ifRow.bDescr;
2789     case NETSNMP_IFTYPE:
2790         if (if_ptr)
2791             long_return = if_ptr->type;
2792         else
2793         long_return = ifRow.dwType;
2794         return (u_char *) & long_return;
2795     case NETSNMP_IFMTU:
2796         long_return = (long) ifRow.dwMtu;
2797         return (u_char *) & long_return;
2798     case NETSNMP_IFSPEED:
2799         if (if_ptr)
2800             long_return = (long) if_ptr->speed;
2801         else
2802         long_return = (long) ifRow.dwSpeed;
2803         return (u_char *) & long_return;
2804     case NETSNMP_IFPHYSADDRESS:
2805         *var_len = ifRow.dwPhysAddrLen;
2806         memcpy(return_buf, ifRow.bPhysAddr, *var_len);
2807         return (u_char *) return_buf;
2808     case NETSNMP_IFADMINSTATUS:
2809         long_return = ifRow.dwAdminStatus;
2810         admin_status = long_return;
2811 #ifndef NETSNMP_NO_WRITE_SUPPORT
2812         *write_method = writeIfEntry;
2813 #endif /* !NETSNMP_NO_WRITE_SUPPORT */
2814         return (u_char *) & long_return;
2815     case NETSNMP_IFOPERSTATUS:
2816         long_return =
2817            (MIB_IF_OPER_STATUS_OPERATIONAL == ifRow.dwOperStatus) ? 1 : 2;
2818         return (u_char *) & long_return;
2819     case NETSNMP_IFLASTCHANGE:
2820         long_return = 0 /* XXX not a UNIX epochal time ifRow.dwLastChange */ ;
2821         return (u_char *) & long_return;
2822     case NETSNMP_IFINOCTETS:
2823         long_return = ifRow.dwInOctets;
2824         return (u_char *) & long_return;
2825     case NETSNMP_IFINUCASTPKTS:
2826         long_return = ifRow.dwInUcastPkts;
2827         return (u_char *) & long_return;
2828     case NETSNMP_IFINNUCASTPKTS:
2829         long_return = ifRow.dwInNUcastPkts;
2830         return (u_char *) & long_return;
2831     case NETSNMP_IFINDISCARDS:
2832         long_return = ifRow.dwInDiscards;
2833         return (u_char *) & long_return;
2834     case NETSNMP_IFINERRORS:
2835         long_return = ifRow.dwInErrors;
2836         return (u_char *) & long_return;
2837     case NETSNMP_IFINUNKNOWNPROTOS:
2838         long_return = ifRow.dwInUnknownProtos;
2839         return (u_char *) & long_return;
2840     case NETSNMP_IFOUTOCTETS:
2841         long_return = ifRow.dwOutOctets;
2842         return (u_char *) & long_return;
2843     case NETSNMP_IFOUTUCASTPKTS:
2844         long_return = ifRow.dwOutUcastPkts;
2845         return (u_char *) & long_return;
2846     case NETSNMP_IFOUTNUCASTPKTS:
2847         long_return = ifRow.dwOutNUcastPkts;
2848         return (u_char *) & long_return;
2849     case NETSNMP_IFOUTDISCARDS:
2850         long_return = ifRow.dwOutDiscards;
2851         return (u_char *) & long_return;
2852     case NETSNMP_IFOUTERRORS:
2853         long_return = ifRow.dwOutErrors;
2854         return (u_char *) & long_return;
2855     case NETSNMP_IFOUTQLEN:
2856         long_return = ifRow.dwOutQLen;
2857         return (u_char *) & long_return;
2858     case NETSNMP_IFSPECIFIC:
2859         *var_len = nullOidLen;
2860         return (u_char *) nullOid;
2861     default:
2862         DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ifEntry\n",
2863                     vp->magic));
2864     }
2865     return NULL;
2866 }
2867 
2868 
2869 #ifndef NETSNMP_NO_WRITE_SUPPORT
2870 int
writeIfEntry(int action,u_char * var_val,u_char var_val_type,size_t var_val_len,u_char * statP,oid * name,size_t name_len)2871 writeIfEntry(int action,
2872              u_char * var_val,
2873              u_char var_val_type,
2874              size_t var_val_len,
2875              u_char * statP, oid * name, size_t name_len)
2876 {
2877     MIB_IFROW       ifEntryRow;
2878     if ((char) name[9] != NETSNMP_IFADMINSTATUS) {
2879         return SNMP_ERR_NOTWRITABLE;
2880     }
2881 
2882     switch (action) {
2883     case RESERVE1:             /* Check values for acceptability */
2884         if (var_val_type != ASN_INTEGER) {
2885             snmp_log(LOG_ERR, "not integer\n");
2886             return SNMP_ERR_WRONGTYPE;
2887         }
2888         if (var_val_len > sizeof(int)) {
2889             snmp_log(LOG_ERR, "bad length\n");
2890             return SNMP_ERR_WRONGLENGTH;
2891         }
2892 
2893         /*
2894          * The dwAdminStatus member can be MIB_IF_ADMIN_STATUS_UP or MIB_IF_ADMIN_STATUS_DOWN
2895          */
2896         if (!(((int) (*var_val) == MIB_IF_ADMIN_STATUS_UP) ||
2897               ((int) (*var_val) == MIB_IF_ADMIN_STATUS_DOWN))) {
2898             snmp_log(LOG_ERR, "not supported admin state\n");
2899             return SNMP_ERR_WRONGVALUE;
2900         }
2901         break;
2902 
2903     case RESERVE2:             /* Allocate memory and similar resources */
2904         break;
2905 
2906     case ACTION:
2907         /*
2908          * Save the old value, in case of UNDO
2909          */
2910 
2911         oldadmin_status = admin_status;
2912         admin_status = (int) *var_val;
2913         break;
2914 
2915     case UNDO:                 /* Reverse the SET action and free resources */
2916         admin_status = oldadmin_status;
2917         break;
2918 
2919     case COMMIT:               /* Confirm the SET, performing any irreversible actions,
2920                                  * and free resources */
2921         ifEntryRow.dwIndex = (int) name[10];
2922         ifEntryRow.dwAdminStatus = admin_status;
2923         /*
2924          * Only UP and DOWN status are supported. Thats why done in COMMIT
2925          */
2926         if (SetIfEntry(&ifEntryRow) != NO_ERROR) {
2927             snmp_log(LOG_ERR,
2928                      "Error in writeIfEntry case COMMIT with index: %lu & adminStatus %lu\n",
2929                      ifEntryRow.dwIndex, ifEntryRow.dwAdminStatus);
2930             return SNMP_ERR_COMMITFAILED;
2931         }
2932 
2933     case FREE:                 /* Free any resources allocated */
2934         /*
2935          * No resources have been allocated
2936          */
2937         break;
2938     }
2939     return SNMP_ERR_NOERROR;
2940 }                               /* end of writeIfEntry */
2941 #endif /* !NETSNMP_NO_WRITE_SUPPORT */
2942 #endif                          /* WIN32 cygwin */
2943