and added files
[bcm963xx.git] / userapps / opensource / net-snmp / agent / mibgroup / mibII / at.c
1 #ifdef BUILD_SNMP_AT_MIB
2 /*
3  *  Template MIB group implementation - at.c
4  *
5  */
6
7 #include <net-snmp/net-snmp-config.h>
8 #if HAVE_STRING_H
9 #include <string.h>
10 #else
11 #include <strings.h>
12 #endif
13 #if HAVE_STDLIB_H
14 #include <stdlib.h>
15 #endif
16 #if defined(IFNET_NEEDS_KERNEL) && !defined(_KERNEL)
17 #define _KERNEL 1
18 #define _I_DEFINED_KERNEL
19 #endif
20 #include <sys/types.h>
21 #if TIME_WITH_SYS_TIME
22 # ifdef WIN32
23 #  include <sys/timeb.h>
24 # else
25 # include <sys/time.h>
26 # endif
27 # include <time.h>
28 #else
29 # if HAVE_SYS_TIME_H
30 #  include <sys/time.h>
31 # else
32 #  include <time.h>
33 # endif
34 #endif
35 #if HAVE_SYS_SOCKET_H
36 #include <sys/socket.h>
37 #endif
38
39 #if HAVE_NETINET_IN_H
40 #include <netinet/in.h>
41 #endif
42 #if HAVE_NET_IF_H
43 #include <net/if.h>
44 #endif
45 #if HAVE_NET_IF_VAR_H
46 #include <net/if_var.h>
47 #endif
48 #ifdef _I_DEFINED_KERNEL
49 #undef _KERNEL
50 #endif
51
52 #if HAVE_NETINET_IF_ETHER_H
53 #include <netinet/if_ether.h>
54 #endif
55 #if HAVE_INET_MIB2_H
56 #include <inet/mib2.h>
57 #endif
58 #if HAVE_SYS_PARAM_H
59 #include <sys/param.h>
60 #endif
61 #if HAVE_SYS_SYSCTL_H
62 #include <sys/sysctl.h>
63 #endif
64 #if HAVE_NET_IF_DL_H
65 #ifndef dynix
66 #include <net/if_dl.h>
67 #else
68 #include <sys/net/if_dl.h>
69 #endif
70 #endif
71 #if HAVE_SYS_STREAM_H
72 #include <sys/stream.h>
73 #endif
74 #if HAVE_NET_ROUTE_H
75 #include <net/route.h>
76 #endif
77 #ifdef solaris2
78 #include "kernel_sunos5.h"
79 #endif
80 #if HAVE_WINSOCK_H
81 #include <winsock.h>
82 #endif
83 #if HAVE_DMALLOC_H
84 #include <dmalloc.h>
85 #endif
86
87 #ifdef hpux11
88 #include <sys/mib.h>
89 #include <netinet/mib_kern.h>
90 #endif                          /* hpux11 */
91
92 #include <net-snmp/net-snmp-includes.h>
93 #include <net-snmp/agent/net-snmp-agent-includes.h>
94 #include <net-snmp/agent/auto_nlist.h>
95
96 #include "at.h"
97 #include "interfaces.h"
98
99 #if defined(HAVE_SYS_SYSCTL_H) && !defined(CAN_USE_SYSCTL)
100 # if defined(RTF_LLINFO) && !defined(irix6)
101 #  define CAN_USE_SYSCTL 1
102 # endif
103 #endif
104
105 #ifdef cygwin
106 #define WIN32
107 #include <windows.h>
108 #endif
109
110         /*********************
111          *
112          *  Kernel & interface information,
113          *   and internal forward declarations
114          *
115          *********************/
116
117 #ifndef WIN32
118 #ifndef solaris2
119 static void     ARP_Scan_Init(void);
120 #ifdef ARP_SCAN_FOUR_ARGUMENTS
121 static int      ARP_Scan_Next(u_long *, char *, u_long *, u_short *);
122 #else
123 static int      ARP_Scan_Next(u_long *, char *, u_long *);
124 #endif
125 #endif
126 #endif
127
128         /*********************
129          *
130          *  Public interface functions
131          *
132          *********************/
133
134 /*
135  * define the structure we're going to ask the agent to register our
136  * information at 
137  */
138 struct variable1 at_variables[] = {
139     {ATIFINDEX, ASN_INTEGER, RONLY, var_atEntry, 1, {1}},
140     {ATPHYSADDRESS, ASN_OCTET_STR, RONLY, var_atEntry, 1, {2}},
141     {ATNETADDRESS, ASN_IPADDRESS, RONLY, var_atEntry, 1, {3}}
142 };
143
144 /*
145  * Define the OID pointer to the top of the mib tree that we're
146  * registering underneath 
147  */
148 oid             at_variables_oid[] = { SNMP_OID_MIB2, 3, 1, 1 };
149
150 void
151 init_at(void)
152 {
153     /*
154      * register ourselves with the agent to handle our mib tree 
155      */
156     REGISTER_MIB("mibII/at", at_variables, variable1, at_variables_oid);
157 #ifdef solaris2
158     init_kernel_sunos5();
159 #endif
160 }
161
162 #ifndef WIN32
163 #ifndef solaris2
164
165 /*
166  * var_atEntry(...
167  * Arguments:
168  * vp     IN      - pointer to variable entry that points here
169  * name    IN/OUT  - IN/name requested, OUT/name found
170  * length  IN/OUT  - length of IN/OUT oid's 
171  * exact   IN      - TRUE if an exact match was requested
172  * var_len OUT     - length of variable or 0 if function returned
173  * write_method
174  * 
175  */
176
177 u_char         *
178 var_atEntry(struct variable *vp,
179             oid * name,
180             size_t * length,
181             int exact, size_t * var_len, WriteMethod ** write_method)
182 {
183     /*
184      * Address Translation table object identifier is of form:
185      * 1.3.6.1.2.1.3.1.1.1.interface.1.A.B.C.D,  where A.B.C.D is IP address.
186      * Interface is at offset 10,
187      * IPADDR starts at offset 12.
188      *
189      * IP Net to Media table object identifier is of form:
190      * 1.3.6.1.2.1.4.22.1.1.1.interface.A.B.C.D,  where A.B.C.D is IP address.
191      * Interface is at offset 10,
192      * IPADDR starts at offset 11.
193      */
194     u_char         *cp;
195     oid            *op;
196     oid             lowest[16];
197     oid             current[16];
198     static char     PhysAddr[6], LowPhysAddr[6];
199     u_long          Addr, LowAddr, foundone;
200 #ifdef ARP_SCAN_FOUR_ARGUMENTS
201     u_short         ifIndex, lowIfIndex = 0;
202 #endif                          /* ARP_SCAN_FOUR_ARGUMENTS */
203     u_long          ifType, lowIfType = 0;
204
205     int             oid_length;
206
207     /*
208      * fill in object part of name for current (less sizeof instance part) 
209      */
210     memcpy((char *) current, (char *) vp->name,
211            (int) vp->namelen * sizeof(oid));
212
213     if (current[6] == 3) {      /* AT group oid */
214         oid_length = 16;
215     } else {                    /* IP NetToMedia group oid */
216         oid_length = 15;
217     }
218
219     LowAddr = 0;                /* Don't have one yet */
220     foundone = 0;
221     ARP_Scan_Init();
222     for (;;) {
223 #ifdef ARP_SCAN_FOUR_ARGUMENTS
224         if (ARP_Scan_Next(&Addr, PhysAddr, &ifType, &ifIndex) == 0)
225             break;
226         current[10] = ifIndex;
227
228         if (current[6] == 3) {  /* AT group oid */
229             current[11] = 1;
230             op = current + 12;
231         } else {                /* IP NetToMedia group oid */
232             op = current + 11;
233         }
234 #else                           /* ARP_SCAN_FOUR_ARGUMENTS */
235         if (ARP_Scan_Next(&Addr, PhysAddr, &ifType) == 0)
236             break;
237         current[10] = 1;
238
239         if (current[6] == 3) {  /* AT group oid */
240             current[11] = 1;
241             op = current + 12;
242         } else {                /* IP NetToMedia group oid */
243             op = current + 11;
244         }
245 #endif                          /* ARP_SCAN_FOUR_ARGUMENTS */
246         cp = (u_char *) & Addr;
247         *op++ = *cp++;
248         *op++ = *cp++;
249         *op++ = *cp++;
250         *op++ = *cp++;
251
252         if (exact) {
253             if (snmp_oid_compare(current, oid_length, name, *length) == 0) {
254                 memcpy((char *) lowest, (char *) current,
255                        oid_length * sizeof(oid));
256                 LowAddr = Addr;
257                 foundone = 1;
258 #ifdef ARP_SCAN_FOUR_ARGUMENTS
259                 lowIfIndex = ifIndex;
260 #endif                          /*  ARP_SCAN_FOUR_ARGUMENTS */
261                 memcpy(LowPhysAddr, PhysAddr, sizeof(PhysAddr));
262                 lowIfType = ifType;
263                 break;          /* no need to search further */
264             }
265         } else {
266             if ((snmp_oid_compare(current, oid_length, name, *length) > 0)
267                 && ((foundone == 0)
268                     ||
269                     (snmp_oid_compare
270                      (current, oid_length, lowest, oid_length) < 0))) {
271                 /*
272                  * if new one is greater than input and closer to input than
273                  * previous lowest, save this one as the "next" one.
274                  */
275                 memcpy((char *) lowest, (char *) current,
276                        oid_length * sizeof(oid));
277                 LowAddr = Addr;
278                 foundone = 1;
279 #ifdef ARP_SCAN_FOUR_ARGUMENTS
280                 lowIfIndex = ifIndex;
281 #endif                          /*  ARP_SCAN_FOUR_ARGUMENTS */
282                 memcpy(LowPhysAddr, PhysAddr, sizeof(PhysAddr));
283                 lowIfType = ifType;
284             }
285         }
286     }
287     if (foundone == 0)
288         return (NULL);
289
290     memcpy((char *) name, (char *) lowest, oid_length * sizeof(oid));
291     *length = oid_length;
292     *write_method = 0;
293     switch (vp->magic) {
294     case IPMEDIAIFINDEX:       /* also ATIFINDEX */
295         *var_len = sizeof long_return;
296 #ifdef ARP_SCAN_FOUR_ARGUMENTS
297         long_return = lowIfIndex;
298 #else                           /* ARP_SCAN_FOUR_ARGUMENTS */
299 #if NO_DUMMY_VALUES
300         return NULL;
301 #endif
302         long_return = 1;        /* XXX */
303 #endif                          /* ARP_SCAN_FOUR_ARGUMENTS */
304         return (u_char *) & long_return;
305     case IPMEDIAPHYSADDRESS:   /* also ATPHYSADDRESS */
306         *var_len = sizeof(LowPhysAddr);
307         return (u_char *) LowPhysAddr;
308     case IPMEDIANETADDRESS:    /* also ATNETADDRESS */
309         *var_len = sizeof long_return;
310         long_return = LowAddr;
311         return (u_char *) & long_return;
312     case IPMEDIATYPE:
313         *var_len = sizeof long_return;
314         long_return = lowIfType;
315         return (u_char *) & long_return;
316     default:
317         DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_atEntry\n",
318                     vp->magic));
319     }
320     return NULL;
321 }
322 #else                           /* solaris2 */
323
324 typedef struct if_ip {
325     int             ifIdx;
326     IpAddress       ipAddr;
327 } if_ip_t;
328
329 static int
330 AT_Cmp(void *addr, void *ep)
331 {
332     mib2_ipNetToMediaEntry_t *mp = (mib2_ipNetToMediaEntry_t *) ep;
333     int             ret = -1;
334     DEBUGMSGTL(("mibII/at", "......... AT_Cmp %lx<>%lx %d<>%d (%.5s)\n",
335                 mp->ipNetToMediaNetAddress, ((if_ip_t *) addr)->ipAddr,
336                 ((if_ip_t *) addr)->ifIdx,
337                 Interface_Index_By_Name(mp->ipNetToMediaIfIndex.o_bytes,
338                                         mp->ipNetToMediaIfIndex.o_length),
339                 mp->ipNetToMediaIfIndex.o_bytes));
340     if (mp->ipNetToMediaNetAddress != ((if_ip_t *) addr)->ipAddr)
341         ret = 1;
342     else if (((if_ip_t *) addr)->ifIdx !=
343              Interface_Index_By_Name(mp->ipNetToMediaIfIndex.o_bytes,
344                                      mp->ipNetToMediaIfIndex.o_length))
345         ret = 1;
346     else
347         ret = 0;
348     DEBUGMSGTL(("mibII/at", "......... AT_Cmp returns %d\n", ret));
349     return ret;
350 }
351
352 u_char         *
353 var_atEntry(struct variable * vp,
354             oid * name,
355             size_t * length,
356             int exact, size_t * var_len, WriteMethod ** write_method)
357 {
358     /*
359      * object identifier is of form:
360      * 1.3.6.1.2.1.3.1.1.1.interface.1.A.B.C.D,  where A.B.C.D is IP address.
361      * Interface is at offset 10,
362      * IPADDR starts at offset 12.
363      */
364 #define AT_MAX_NAME_LENGTH      16
365 #define AT_IFINDEX_OFF  10
366     u_char         *cp;
367     oid            *op;
368     oid             lowest[AT_MAX_NAME_LENGTH];
369     oid             current[AT_MAX_NAME_LENGTH];
370     if_ip_t         NextAddr;
371     mib2_ipNetToMediaEntry_t entry, Lowentry;
372     int             Found = 0;
373     req_e           req_type;
374     int             offset, olength;
375
376     /*
377      * fill in object part of name for current (less sizeof instance part) 
378      */
379
380     DEBUGMSGTL(("mibII/at", "var_atEntry: "));
381     DEBUGMSGOID(("mibII/at", vp->name, vp->namelen));
382     DEBUGMSG(("mibII/at", " %d\n", exact));
383
384     memset(&Lowentry, 0, sizeof(Lowentry));
385     memcpy((char *) current, (char *) vp->name, vp->namelen * sizeof(oid));
386     lowest[0] = 1024;
387     for (NextAddr.ipAddr = (u_long) - 1, NextAddr.ifIdx = 255, req_type =
388          GET_FIRST;;
389          NextAddr.ipAddr = entry.ipNetToMediaNetAddress, NextAddr.ifIdx =
390          current[AT_IFINDEX_OFF], req_type = GET_NEXT) {
391         if (getMibstat
392             (MIB_IP_NET, &entry, sizeof(mib2_ipNetToMediaEntry_t),
393              req_type, &AT_Cmp, &NextAddr) != 0)
394             break;
395         current[AT_IFINDEX_OFF] =
396             Interface_Index_By_Name(entry.ipNetToMediaIfIndex.o_bytes,
397                                     entry.ipNetToMediaIfIndex.o_length);
398         if (current[6] == 3) {  /* AT group oid */
399             current[AT_IFINDEX_OFF + 1] = 1;
400             offset = AT_IFINDEX_OFF + 2;
401             olength = AT_IFINDEX_OFF + 6;
402         } else {
403             offset = AT_IFINDEX_OFF + 1;
404             olength = AT_IFINDEX_OFF + 5;
405         }
406         COPY_IPADDR(cp, (u_char *) & entry.ipNetToMediaNetAddress, op,
407                     current + offset);
408         if (exact) {
409             if (snmp_oid_compare(current, olength, name, *length) == 0) {
410                 memcpy((char *) lowest, (char *) current,
411                        olength * sizeof(oid));
412                 Lowentry = entry;
413                 Found++;
414                 break;          /* no need to search further */
415             }
416         } else {
417             if (snmp_oid_compare(current, olength, name, *length) > 0
418                 && snmp_oid_compare(current, olength, lowest,
419                                     *length) < 0) {
420                 /*
421                  * if new one is greater than input and closer to input than
422                  * previous lowest, and is not equal to it, save this one as the "next" one.
423                  */
424                 memcpy((char *) lowest, (char *) current,
425                        olength * sizeof(oid));
426                 Lowentry = entry;
427                 Found++;
428             }
429         }
430     }
431     DEBUGMSGTL(("mibII/at", "... Found = %d\n", Found));
432     if (Found == 0)
433         return (NULL);
434     memcpy((char *) name, (char *) lowest, olength * sizeof(oid));
435     *length = olength;
436     *write_method = 0;
437     switch (vp->magic) {
438     case IPMEDIAIFINDEX:
439         *var_len = sizeof long_return;
440         long_return =
441             Interface_Index_By_Name(Lowentry.ipNetToMediaIfIndex.o_bytes,
442                                     Lowentry.ipNetToMediaIfIndex.o_length);
443         return (u_char *) & long_return;
444     case IPMEDIAPHYSADDRESS:
445         *var_len = Lowentry.ipNetToMediaPhysAddress.o_length;
446         (void) memcpy(return_buf, Lowentry.ipNetToMediaPhysAddress.o_bytes,
447                       *var_len);
448         return (u_char *) return_buf;
449     case IPMEDIANETADDRESS:
450         *var_len = sizeof long_return;
451         long_return = Lowentry.ipNetToMediaNetAddress;
452         return (u_char *) & long_return;
453     case IPMEDIATYPE:
454         *var_len = sizeof long_return;
455         long_return = Lowentry.ipNetToMediaType;
456         return (u_char *) & long_return;
457     default:
458         DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_atEntry\n",
459                     vp->magic));
460     }
461     return NULL;
462 }
463 #endif                          /* solaris2 */
464
465
466         /*********************
467          *
468          *  Internal implementation functions
469          *
470          *********************/
471
472 #ifndef solaris2
473
474 static int      arptab_size, arptab_current;
475 #if CAN_USE_SYSCTL
476 static char    *lim, *rtnext;
477 static char    *at = 0;
478 #else
479 #ifdef STRUCT_ARPHD_HAS_AT_NEXT
480 static struct arphd *at = 0;
481 static struct arptab *at_ptr, at_entry;
482 static struct arpcom at_com;
483 #elif defined(hpux11)
484 static mib_ipNetToMediaEnt *at = (mib_ipNetToMediaEnt *) 0;
485 #else
486
487 /*
488  * at used to be allocated every time we needed to look at the arp cache.
489  * This cause us to parse /proc/net/arp twice for each request and didn't
490  * allow us to filter things like we'd like to.  So now we use it 
491  * semi-statically.  We initialize it to size 0 and if we need more room
492  * we realloc room for ARP_CACHE_INCR more entries in the table.
493  * We never release what we've taken . . .
494  */
495 #define ARP_CACHE_INCR 1024
496 static struct arptab *at = NULL;
497 static int      arptab_curr_max_size = 0;
498
499 #endif
500 #endif                          /* CAN_USE_SYSCTL */
501
502 static void
503 ARP_Scan_Init(void)
504 {
505 #ifndef CAN_USE_SYSCTL
506 #ifndef linux
507 #ifdef hpux11
508
509     int             fd;
510     struct nmparms  p;
511     int             val;
512     unsigned int    ulen;
513     int             ret;
514
515     if (at)
516         free(at);
517     at = (mib_ipNetToMediaEnt *) 0;
518     arptab_size = 0;
519
520     if ((fd = open_mib("/dev/ip", O_RDONLY, 0, NM_ASYNC_OFF)) >= 0) {
521         p.objid = ID_ipNetToMediaTableNum;
522         p.buffer = (void *) &val;
523         ulen = sizeof(int);
524         p.len = &ulen;
525         if ((ret = get_mib_info(fd, &p)) == 0)
526             arptab_size = val;
527
528         if (arptab_size > 0) {
529             ulen = (unsigned) arptab_size *sizeof(mib_ipNetToMediaEnt);
530             at = (mib_ipNetToMediaEnt *) malloc(ulen);
531             p.objid = ID_ipNetToMediaTable;
532             p.buffer = (void *) at;
533             p.len = &ulen;
534             if ((ret = get_mib_info(fd, &p)) < 0)
535                 arptab_size = 0;
536         }
537
538         close_mib(fd);
539     }
540
541     arptab_current = 0;
542
543 #else                           /* hpux11 */
544
545     if (!at) {
546         auto_nlist(ARPTAB_SIZE_SYMBOL, (char *) &arptab_size,
547                    sizeof arptab_size);
548 #ifdef STRUCT_ARPHD_HAS_AT_NEXT
549         at = (struct arphd *) malloc(arptab_size * sizeof(struct arphd));
550 #else
551         at = (struct arptab *) malloc(arptab_size * sizeof(struct arptab));
552 #endif
553     }
554 #ifdef STRUCT_ARPHD_HAS_AT_NEXT
555     auto_nlist(ARPTAB_SYMBOL, (char *) at,
556                arptab_size * sizeof(struct arphd));
557     at_ptr = at[0].at_next;
558 #else
559     auto_nlist(ARPTAB_SYMBOL, (char *) at,
560                arptab_size * sizeof(struct arptab));
561 #endif
562     arptab_current = 0;
563
564 #endif                          /* hpux11 */
565 #else                           /* linux */
566
567     static time_t   tm = 0;     /* Time of last scan */
568     FILE           *in;
569     int             i;
570     char            line[128];
571     int             za, zb, zc, zd, ze, zf, zg, zh, zi, zj;
572     char            ifname[21];
573
574     arptab_current = 0;         /* Anytime this is called we need to reset 'current' */
575
576     if (time(NULL) < tm + 1) {  /*Our cool one second cache implementation :-) */
577         return;
578     }
579
580     in = fopen("/proc/net/arp", "r");
581     if (!in) {
582         snmp_log(LOG_ERR, "snmpd: Cannot open /proc/net/arp\n");
583         arptab_size = 0;
584         return;
585     }
586
587     /*
588      * Get rid of the header line 
589      */
590     fgets(line, sizeof(line), in);
591
592     i = 0;
593     while (fgets(line, sizeof(line), in)) {
594         u_long          tmp_a;
595         int             tmp_flags;
596         if (i >= arptab_curr_max_size) {
597             struct arptab  *newtab = (struct arptab *)
598                 realloc(at, (sizeof(struct arptab) *
599                              (arptab_curr_max_size + ARP_CACHE_INCR)));
600             if (newtab == at) {
601                 snmp_log(LOG_ERR,
602                          "Error allocating more space for arpcache.  "
603                          "Cache will continue to be limited to %d entries",
604                          arptab_curr_max_size);
605                 break;
606             } else {
607                 arptab_curr_max_size += ARP_CACHE_INCR;
608                 at = newtab;
609             }
610         }
611         if (12 !=
612             sscanf(line,
613                    "%d.%d.%d.%d 0x%*x 0x%x %x:%x:%x:%x:%x:%x %*[^ ] %20s\n",
614                    &za, &zb, &zc, &zd, &tmp_flags, &ze, &zf, &zg, &zh, &zi,
615                    &zj, ifname)) {
616             snmp_log(LOG_ERR, "Bad line in /proc/net/arp: %s", line);
617             continue;
618         }
619         /*
620          * Invalidated entries have their flag set to 0.
621          * * We want to ignore them 
622          */
623         if (tmp_flags == 0) {
624             continue;
625         }
626         at[i].at_flags = tmp_flags;
627         at[i].at_enaddr[0] = ze;
628         at[i].at_enaddr[1] = zf;
629         at[i].at_enaddr[2] = zg;
630         at[i].at_enaddr[3] = zh;
631         at[i].at_enaddr[4] = zi;
632         at[i].at_enaddr[5] = zj;
633         tmp_a = ((u_long) za << 24) |
634             ((u_long) zb << 16) | ((u_long) zc << 8) | ((u_long) zd);
635         at[i].at_iaddr.s_addr = htonl(tmp_a);
636         at[i].if_index = Interface_Index_By_Name(ifname, strlen(ifname));
637         i++;
638     }
639     arptab_size = i;
640
641     fclose(in);
642     time(&tm);
643 #endif                          /* linux */
644 #else                           /* CAN_USE_SYSCTL */
645
646     int             mib[6];
647     size_t          needed;
648
649     mib[0] = CTL_NET;
650     mib[1] = PF_ROUTE;
651     mib[2] = 0;
652     mib[3] = AF_INET;
653     mib[4] = NET_RT_FLAGS;
654     mib[5] = RTF_LLINFO;
655
656     if (at)
657         free(at);
658     rtnext = lim = at = 0;
659
660     if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
661         snmp_log_perror("route-sysctl-estimate");
662     else {
663         if ((at = malloc(needed ? needed : 1)) == NULL)
664             snmp_log_perror("malloc");
665         else {
666             if (sysctl(mib, 6, at, &needed, NULL, 0) < 0)
667                 snmp_log_perror("actual retrieval of routing table");
668             else {
669                 lim = at + needed;
670                 rtnext = at;
671             }
672         }
673     }
674
675 #endif                          /* CAN_USE_SYSCTL */
676 }
677
678 #ifdef ARP_SCAN_FOUR_ARGUMENTS
679 static int
680 ARP_Scan_Next(u_long * IPAddr, char *PhysAddr, u_long * ifType,
681               u_short * ifIndex)
682 #else
683 static int
684 ARP_Scan_Next(u_long * IPAddr, char *PhysAddr, u_long * ifType)
685 #endif
686 {
687 #ifndef CAN_USE_SYSCTL
688 #ifdef linux
689     if (arptab_current < arptab_size) {
690         /*
691          * copy values 
692          */
693         *IPAddr = at[arptab_current].at_iaddr.s_addr;
694         *ifType =
695             (at[arptab_current].
696              at_flags & ATF_PERM) ? 4 /*static */ : 3 /*dynamic */ ;
697         *ifIndex = at[arptab_current].if_index;
698         memcpy(PhysAddr, &at[arptab_current].at_enaddr,
699                sizeof(at[arptab_current].at_enaddr));
700
701         /*
702          * increment to point next entry 
703          */
704         arptab_current++;
705         /*
706          * return success 
707          */
708         return (1);
709     }
710 #elif defined(hpux11)
711     if (arptab_current < arptab_size) {
712         /*
713          * copy values 
714          */
715         *IPAddr = at[arptab_current].NetAddr;
716         memcpy(PhysAddr, at[arptab_current].PhysAddr.o_bytes,
717                at[arptab_current].PhysAddr.o_length);
718         *ifType = at[arptab_current].Type;
719         *ifIndex = at[arptab_current].IfIndex;
720         /*
721          * increment to point next entry 
722          */
723         arptab_current++;
724         /*
725          * return success 
726          */
727         return (1);
728     }
729 #elif !defined(ARP_SCAN_FOUR_ARGUMENTS) || defined(hpux)
730     register struct arptab *atab;
731
732     while (arptab_current < arptab_size) {
733 #ifdef STRUCT_ARPHD_HAS_AT_NEXT
734         /*
735          * The arp table is an array of linked lists of arptab entries.
736          * Unused slots have pointers back to the array entry itself 
737          */
738
739         if (at_ptr == (auto_nlist_value(ARPTAB_SYMBOL) +
740                        arptab_current * sizeof(struct arphd))) {
741             /*
742              * Usused 
743              */
744             arptab_current++;
745             at_ptr = at[arptab_current].at_next;
746             continue;
747         }
748
749         klookup(at_ptr, (char *) &at_entry, sizeof(struct arptab));
750         klookup(at_entry.at_ac, (char *) &at_com, sizeof(struct arpcom));
751
752         at_ptr = at_entry.at_next;
753         atab = &at_entry;
754         *ifIndex = at_com.ac_if.if_index;       /* not strictly ARPHD */
755 #else                           /* STRUCT_ARPHD_HAS_AT_NEXT */
756         atab = &at[arptab_current++];
757 #endif                          /* STRUCT_ARPHD_HAS_AT_NEXT */
758         if (!(atab->at_flags & ATF_COM))
759             continue;
760         *ifType = (atab->at_flags & ATF_PERM) ? 4 : 3;
761         *IPAddr = atab->at_iaddr.s_addr;
762 #if defined (sunV3) || defined(sparc) || defined(hpux)
763         memcpy(PhysAddr, (char *) &atab->at_enaddr,
764                sizeof(atab->at_enaddr));
765 #endif
766 #if defined(mips) || defined(ibm032)
767         memcpy(PhysAddr, (char *) atab->at_enaddr,
768                sizeof(atab->at_enaddr));
769 #endif
770         return (1);
771     }
772 #endif                          /* linux || hpux11 || !ARP_SCAN_FOUR_ARGUMENTS || hpux */
773
774     return 0;                   /* we need someone with an irix box to fix this section */
775
776 #else                           /* !CAN_USE_SYSCTL */
777     struct rt_msghdr *rtm;
778     struct sockaddr_inarp *sin;
779     struct sockaddr_dl *sdl;
780
781     while (rtnext < lim) {
782         rtm = (struct rt_msghdr *) rtnext;
783         sin = (struct sockaddr_inarp *) (rtm + 1);
784         sdl = (struct sockaddr_dl *) (sin + 1);
785         rtnext += rtm->rtm_msglen;
786         if (sdl->sdl_alen) {
787             *IPAddr = sin->sin_addr.s_addr;
788             memcpy(PhysAddr, (char *) LLADDR(sdl), sdl->sdl_alen);
789             *ifIndex = sdl->sdl_index;
790             *ifType = 1;        /* XXX */
791             return (1);
792         }
793     }
794     return (0);                 /* "EOF" */
795 #endif                          /* !CAN_USE_SYSCTL */
796 }
797 #endif                          /* solaris2 */
798
799 #else                           /* WIN32 */
800 #include <iphlpapi.h>
801
802 extern WriteMethod write_arp;
803 MIB_IPNETROW   *arp_row = NULL;
804 int             create_flag = 0;
805
806 u_char         *
807 var_atEntry(struct variable *vp,
808             oid * name,
809             size_t * length,
810             int exact, size_t * var_len, WriteMethod ** write_method)
811 {
812     /*
813      * Address Translation table object identifier is of form:
814      * 1.3.6.1.2.1.3.1.?.interface.1.A.B.C.D,  where A.B.C.D is IP address.
815      * Interface is at offset 10,
816      * IPADDR starts at offset 12.
817      *
818      * IP Net to Media table object identifier is of form:
819      * 1.3.6.1.2.1.4.22.1.?.interface.A.B.C.D,  where A.B.C.D is IP address.
820      * Interface is at offset 10,
821      * IPADDR starts at offset 11.
822      */
823     u_char         *cp;
824     oid            *op;
825     oid             lowest[16];
826     oid             current[16];
827     int             oid_length;
828     int             lowState = -1;      /* Don't have one yet */
829     PMIB_IPNETTABLE pIpNetTable = NULL;
830     DWORD           status = NO_ERROR;
831     DWORD           dwActualSize = 0;
832     UINT            i;
833     u_char          dest_addr[4];
834
835     /*
836      * fill in object part of name for current (less sizeof instance part) 
837      */
838     memcpy((char *) current, (char *) vp->name,
839            (int) vp->namelen * sizeof(oid));
840
841     if (current[6] == 3) {      /* AT group oid */
842         oid_length = 16;
843     } else {                    /* IP NetToMedia group oid */
844         oid_length = 15;
845     }
846
847     status = GetIpNetTable(pIpNetTable, &dwActualSize, TRUE);
848     if (status == ERROR_INSUFFICIENT_BUFFER) {
849         pIpNetTable = (PMIB_IPNETTABLE) malloc(dwActualSize);
850         if (pIpNetTable != NULL) {
851             /*
852              * Get the sorted IpNet Table 
853              */
854             status = GetIpNetTable(pIpNetTable, &dwActualSize, TRUE);
855         }
856     }
857
858
859     if (status == NO_ERROR) {
860         for (i = 0; i < pIpNetTable->dwNumEntries; ++i) {
861             current[10] = pIpNetTable->table[i].dwIndex;
862
863
864             if (current[6] == 3) {      /* AT group oid */
865                 current[11] = 1;
866                 op = current + 12;
867             } else {            /* IP NetToMedia group oid */
868                 op = current + 11;
869             }
870             cp = (u_char *) & pIpNetTable->table[i].dwAddr;
871             *op++ = *cp++;
872             *op++ = *cp++;
873             *op++ = *cp++;
874             *op++ = *cp++;
875
876             if (exact) {
877                 if (snmp_oid_compare(current, oid_length, name, *length) ==
878                     0) {
879                     memcpy((char *) lowest, (char *) current,
880                            oid_length * sizeof(oid));
881                     lowState = 0;
882                     break;      /* no need to search further */
883                 }
884             } else {
885                 if (snmp_oid_compare(current, oid_length, name, *length) >
886                     0) {
887                     memcpy((char *) lowest, (char *) current,
888                            oid_length * sizeof(oid));
889                     lowState = 0;
890                     break;      /* As the table is sorted, no need to search further */
891                 }
892             }
893         }
894     }
895     if (arp_row == NULL) {
896         /*
897          * Free allocated memory in case of SET request's FREE phase 
898          */
899         arp_row = (PMIB_IPNETROW) malloc(sizeof(MIB_IPNETROW));
900     }
901
902     if (lowState < 0 || status != NO_ERROR) {
903         /*
904          * for creation of new row, only ipNetToMediaTable case is considered 
905          */
906         if (*length == 15 || *length == 16) {
907             create_flag = 1;
908             *write_method = write_arp;
909             arp_row->dwIndex = name[10];
910
911             if (*length == 15) {        /* ipNetToMediaTable */
912                 i = 11;
913             } else {            /* at Table */
914
915                 i = 12;
916             }
917
918             dest_addr[0] = (u_char) name[i];
919             dest_addr[1] = (u_char) name[i + 1];
920             dest_addr[2] = (u_char) name[i + 2];
921             dest_addr[3] = (u_char) name[i + 3];
922             arp_row->dwAddr = *((DWORD *) dest_addr);
923
924             arp_row->dwType = 4;        /* Static */
925             arp_row->dwPhysAddrLen = 0;
926         }
927         free(pIpNetTable);
928         return (NULL);
929     }
930
931     create_flag = 0;
932     memcpy((char *) name, (char *) lowest, oid_length * sizeof(oid));
933     *length = oid_length;
934     *write_method = write_arp;
935     *arp_row = pIpNetTable->table[i];
936
937     switch (vp->magic) {
938     case IPMEDIAIFINDEX:       /* also ATIFINDEX */
939         *var_len = sizeof long_return;
940         long_return = pIpNetTable->table[i].dwIndex;
941         free(pIpNetTable);
942         return (u_char *) & long_return;
943     case IPMEDIAPHYSADDRESS:   /* also ATPHYSADDRESS */
944         *var_len = pIpNetTable->table[i].dwPhysAddrLen;
945         memcpy(return_buf, pIpNetTable->table[i].bPhysAddr, *var_len);
946         free(pIpNetTable);
947         return (u_char *) return_buf;
948     case IPMEDIANETADDRESS:    /* also ATNETADDRESS */
949         *var_len = sizeof long_return;
950         long_return = pIpNetTable->table[i].dwAddr;
951         free(pIpNetTable);
952         return (u_char *) & long_return;
953     case IPMEDIATYPE:
954         *var_len = sizeof long_return;
955         long_return = pIpNetTable->table[i].dwType;
956         free(pIpNetTable);
957         return (u_char *) & long_return;
958     default:
959         DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_atEntry\n",
960                     vp->magic));
961     }
962     return NULL;
963 }
964
965 int
966 write_arp(int action,
967           u_char * var_val,
968           u_char var_val_type,
969           size_t var_val_len, u_char * statP, oid * name, size_t length)
970 {
971     int             var, retval = SNMP_ERR_NOERROR;
972     static PMIB_IPNETROW oldarp_row = NULL;
973     MIB_IPNETROW    temp_row;
974     DWORD           status = NO_ERROR;
975
976     /*
977      * IP Net to Media table object identifier is of form:
978      * 1.3.6.1.2.1.4.22.1.?.interface.A.B.C.D,  where A.B.C.D is IP address.
979      * Interface is at offset 10,
980      * IPADDR starts at offset 11.
981      */
982
983     if (name[6] == 3) {         /* AT group oid */
984         if (length != 16) {
985             snmp_log(LOG_ERR, "length error\n");
986             return SNMP_ERR_NOCREATION;
987         }
988     } else {                    /* IP NetToMedia group oid */
989         if (length != 15) {
990             snmp_log(LOG_ERR, "length error\n");
991             return SNMP_ERR_NOCREATION;
992         }
993     }
994
995
996     /*
997      * #define for ipNetToMediaTable entries are 1 less than corresponding sub-id in MIB
998      * * i.e. IPMEDIAIFINDEX defined as 0, but ipNetToMediaIfIndex registered as 1
999      */
1000     var = name[9] - 1;
1001     switch (action) {
1002     case RESERVE1:
1003         switch (var) {
1004         case IPMEDIAIFINDEX:
1005             if (var_val_type != ASN_INTEGER) {
1006                 snmp_log(LOG_ERR, "not integer\n");
1007                 return SNMP_ERR_WRONGTYPE;
1008             }
1009             if ((*((int *) var_val)) < 0) {
1010                 snmp_log(LOG_ERR, "invalid media ifIndex");
1011                 return SNMP_ERR_WRONGVALUE;
1012             }
1013             if (var_val_len > sizeof(int)) {
1014                 snmp_log(LOG_ERR, "bad length\n");
1015                 return SNMP_ERR_WRONGLENGTH;
1016             }
1017             break;
1018         case IPMEDIANETADDRESS:
1019             if (var_val_type != ASN_IPADDRESS) {
1020                 snmp_log(LOG_ERR, "not IP Address\n");
1021                 return SNMP_ERR_WRONGTYPE;
1022             }
1023             if ((*((int *) var_val)) < 0) {
1024                 snmp_log(LOG_ERR, "invalid media net address");
1025                 return SNMP_ERR_WRONGVALUE;
1026             }
1027             if (var_val_len > sizeof(DWORD)) {
1028                 snmp_log(LOG_ERR, "bad length\n");
1029                 return SNMP_ERR_WRONGLENGTH;
1030             }
1031             break;
1032         case IPMEDIATYPE:
1033             if (var_val_type != ASN_INTEGER) {
1034                 snmp_log(LOG_ERR, "not integer\n");
1035                 return SNMP_ERR_WRONGTYPE;
1036             }
1037             if ((*((int *) var_val)) < 1 || (*((int *) var_val)) > 4) {
1038                 snmp_log(LOG_ERR, "invalid media type");
1039                 return SNMP_ERR_WRONGVALUE;
1040             }
1041             if (var_val_len > sizeof(int)) {
1042                 snmp_log(LOG_ERR, "bad length\n");
1043                 return SNMP_ERR_WRONGLENGTH;
1044             }
1045             break;
1046         case IPMEDIAPHYSADDRESS:
1047             if (var_val_type != ASN_OCTET_STR) {
1048                 snmp_log(LOG_ERR, "not octet str");
1049                 return SNMP_ERR_WRONGTYPE;
1050             }
1051             if (var_val_len != 6) {
1052                 snmp_log(LOG_ERR, "not correct ipAddress length: %d",
1053                          var_val_len);
1054                 return SNMP_ERR_WRONGLENGTH;
1055             }
1056             break;
1057         default:
1058             DEBUGMSGTL(("snmpd", "unknown sub-id %d in write_rte\n",
1059                         var + 1));
1060             return SNMP_ERR_NOTWRITABLE;
1061         }
1062         break;
1063     case RESERVE2:
1064         /*
1065          * Save the old value, in case of UNDO 
1066          */
1067         if (oldarp_row == NULL) {
1068             oldarp_row = (PMIB_IPNETROW) malloc(sizeof(MIB_IPNETROW));
1069             *oldarp_row = *arp_row;
1070         }
1071         break;
1072     case ACTION:               /* Perform the SET action (if reversible) */
1073         switch (var) {
1074
1075         case IPMEDIAIFINDEX:
1076             temp_row = *arp_row;
1077             arp_row->dwIndex = *((int *) var_val);
1078             /*
1079              * In case of new entry, physical address is mandatory.
1080              * * SetIpNetEntry will be done in COMMIT case 
1081              */
1082             if (!create_flag) {
1083                 if (SetIpNetEntry(arp_row) != NO_ERROR) {
1084                     arp_row->dwIndex = temp_row.dwIndex;
1085                     retval = SNMP_ERR_COMMITFAILED;
1086                 }
1087                 /*
1088                  * Don't know yet, whether change in ifIndex creates new row or not 
1089                  */
1090                 /*
1091                  * else{ 
1092                  */
1093                 /*
1094                  * temp_row.dwType = 2; 
1095                  */
1096                 /*
1097                  * if(SetIpNetEntry(&temp_row) != NO_ERROR) 
1098                  */
1099                 /*
1100                  * retval = SNMP_ERR_COMMITFAILED; 
1101                  */
1102                 /*
1103                  * } 
1104                  */
1105             }
1106             break;
1107         case IPMEDIANETADDRESS:
1108             temp_row = *arp_row;
1109             arp_row->dwAddr = *((int *) var_val);
1110             if (!create_flag) {
1111                 if (SetIpNetEntry(arp_row) != NO_ERROR) {
1112                     arp_row->dwAddr = oldarp_row->dwAddr;
1113                     retval = SNMP_ERR_COMMITFAILED;
1114                 } else {
1115                     temp_row.dwType = 2;
1116                     if (SetIpNetEntry(&temp_row) != NO_ERROR) {
1117                         snmp_log(LOG_ERR,
1118                                  "Failed in ACTION, while deleting old row \n");
1119                         retval = SNMP_ERR_COMMITFAILED;
1120                     }
1121                 }
1122             }
1123             break;
1124         case IPMEDIATYPE:
1125             arp_row->dwType = *((int *) var_val);
1126             if (!create_flag) {
1127                 if (SetIpNetEntry(arp_row) != NO_ERROR)
1128                     retval = SNMP_ERR_COMMITFAILED;
1129             }
1130             break;
1131         case IPMEDIAPHYSADDRESS:
1132             memcpy(arp_row->bPhysAddr, var_val, var_val_len);
1133             arp_row->dwPhysAddrLen = var_val_len;
1134             if (!create_flag) {
1135                 if (SetIpNetEntry(arp_row) != NO_ERROR)
1136                     retval = SNMP_ERR_COMMITFAILED;
1137             }
1138             break;
1139         default:
1140             DEBUGMSGTL(("snmpd", "unknown sub-id %d in write_arp\n",
1141                         var + 1));
1142             retval = SNMP_ERR_NOTWRITABLE;
1143         }
1144         return retval;
1145     case UNDO:
1146         /*
1147          * Reverse the SET action and free resources 
1148          */
1149         if (oldarp_row != NULL) {
1150             /*
1151              * UNDO the changes done for existing entry. 
1152              */
1153             if (!create_flag) {
1154                 if ((status = SetIpNetEntry(oldarp_row)) != NO_ERROR) {
1155                     snmp_log(LOG_ERR, "Error in case UNDO, status : %d\n",
1156                              status);
1157                     retval = SNMP_ERR_UNDOFAILED;
1158                 }
1159             }
1160
1161             if (oldarp_row->dwAddr != arp_row->dwAddr) {
1162                 arp_row->dwType = 2;    /*If row was added/created delete that row */
1163
1164                 if ((status = SetIpNetEntry(arp_row)) != NO_ERROR) {
1165                     snmp_log(LOG_ERR,
1166                              "Error while deleting added row, status : %d\n",
1167                              status);
1168                     retval = SNMP_ERR_UNDOFAILED;
1169                 }
1170             }
1171             free(oldarp_row);
1172             oldarp_row = NULL;
1173             free(arp_row);
1174             arp_row = NULL;
1175             return retval;
1176         }
1177         break;
1178     case COMMIT:
1179         /*
1180          * if new entry and physical address specified, create new entry 
1181          */
1182         if (create_flag) {
1183             if (arp_row->dwPhysAddrLen != 0) {
1184                 if ((status = CreateIpNetEntry(arp_row)) != NO_ERROR) {
1185                     snmp_log(LOG_ERR,
1186                              "Inside COMMIT: CreateIpNetEntry failed, status %d\n",
1187                              status);
1188                     retval = SNMP_ERR_COMMITFAILED;
1189                 }
1190             } else {
1191                 /*
1192                  * For new entry, physical address must be set. 
1193                  */
1194                 snmp_log(LOG_ERR,
1195                          "Can't create new entry without physical address\n");
1196                 retval = SNMP_ERR_WRONGVALUE;
1197             }
1198             /*
1199              * unset the create_flag, so that CreateIpNetEntry called only once 
1200              */
1201             create_flag = 0;
1202         }
1203
1204     case FREE:
1205         /*
1206          * Free any resources allocated 
1207          */
1208         free(oldarp_row);
1209         oldarp_row = NULL;
1210         free(arp_row);
1211         arp_row = NULL;
1212         break;
1213     }
1214     return retval;
1215 }
1216 #endif                          /* WIN32 */
1217
1218 #else
1219 void
1220 init_at(void)
1221 {
1222   return;
1223 }
1224 #endif /* BUILD_SNMP_AT_MIB */