[ECOS] Patch for SNMP ipNetToMediaTable to return ARP entries

Tad ecos_removethispart@ds3switch.com
Tue Jun 19 19:24:00 GMT 2007


Here's the human readable proposal for a patch to var_ipNetToMediaTable 
so that it returns ARP entries rather than interface addresses which 
already exist in ipAddrTable and ifPhysAddress.  Not perfect, but should 
get the job done.  Currently only works for ethernet mac addresses and 
ipv4 and FreeBSD stack.  Disabled var_ip... for non FreeBSD because it 
appears to be completely wrong anyhow.

Basically, replace var_ipNet... and add a global to if_ether.c so we can 
access the ARP table.  Wasn't sure the proper way to lock the bsd stack, 
so just used a fairly fast cyg_scheduler_lock.  Also, if_ether.c has the 
ARP table as a static.  It probably should be moved to a header file, 
but I'm not going to put that much effort in at the moment.

The maching-readable patches will be submitted to ecos-patches

+++ if_ether.c    2007-06-19 11:19:00.000000000 -0800
static    LIST_HEAD(, llinfo_arp) llinfo_arp;
+struct llinfo_arp **llinfo_arp_headp = &llinfo_arp.lh_first; // for 
ipNetToMediaTable access to ARP entries

+++mibII/ip.c

// from if_ether.c
struct llinfo_arp {
        LIST_ENTRY(llinfo_arp) la_le;
        struct  rtentry *la_rt;
        struct  mbuf *la_hold;          /* last packet until 
resolved/timeout */
        long    la_asked;               /* last time we QUERIED for this 
addr */
#define la_timer la_rt->rt_rmx.rmx_expire /* deletion time in seconds */
};
#define SDL(s) ((struct sockaddr_dl *)(s))
#include <net/if_dl.h> // for LLADDR

// created for new var_ipNetToMediaTable
typedef struct nettomedia_entry {
  cyg_uint32  ipv4_addr;
  cyg_uint16  if_index;
  cyg_uint8   mac_addr[6];
  cyg_uint32  rt_flags;
} nettomedia_entry;

// returns the number of entries that could have been populated if len 
was long enough
// len is the number of pre-allocated entry positions in the array 
pointed to by e.

cyg_uint32
populate_nettomedia_list (nettomedia_entry *e, cyg_uint32 len)
{
  cyg_uint16        rv = 0;
#ifdef CYGPKG_NET_FREEBSD_STACK 
  extern struct llinfo_arp  **llinfo_arp_headp;
  struct llinfo_arp         *la = *llinfo_arp_headp;
  struct rtentry    *rt;
  cyg_uint16        entryid = 0;
  cyg_uint16        watchdog_ctr;

  cyg_scheduler_lock();

  for (watchdog_ctr = 3000; la && watchdog_ctr--;)
  {
    rt = la->la_rt;
    la = la->la_le.le_next;
   
    // Find one valid entry
    {
      struct sockaddr *dst, *gate;
      struct sockaddr_dl *sdl;

      dst = rt_key(rt);
      gate = rt->rt_gateway;

      if (gate)
      {
        sdl = SDL(gate);
        // XXX do we also need to check ifp->if_flags & IFF_STATICARP or 
ifp->if_type != IFT_CARP ?
        if (sdl &&
            dst->sa_family == AF_INET &&
            (rt->rt_flags & RTF_UP) &&
            !(rt->rt_flags & RTF_REJECT))
                                                 // Should we check 
b/mcast too?
          if (memcmp ((const void *) LLADDR(sdl), "\0\0\0\0\0\0", 
ETHER_ADDR_LEN) != 0) // somehow all 0 entries snuck into the table
          { // Valid entry
            ++rv;   // number of valid possible entries
            if (len)
            { // Populate one entry
              e[entryid].ipv4_addr = (cyg_uint32) ((struct sockaddr_in 
*)dst)->sin_addr.s_addr;
              memcpy ((void *) e[entryid].mac_addr, (const void *) 
LLADDR(sdl), sizeof (e[0].mac_addr));
              e[entryid].rt_flags = rt->rt_flags;
              e[entryid].if_index = rt->rt_ifp->if_index;
 
              ++entryid;
              --len;
            }
          }
      }
    }
  }

  cyg_scheduler_unlock();
#endif  // CYGPKG_NET_FREEBSD_STACK 
  return (cyg_uint32) rv;
}


/*
 * var_ipNetToMediaTable():
 */

unsigned char *
var_ipNetToMediaTable(struct variable *vp,
          oid     *name,
          size_t  *length,
          int     exact,
          size_t  *var_len,
          WriteMethod **write_method)
{
#define MAX_NETTOMEDIA_ENTRIES  40
    static nettomedia_entry   nettomedia_list [MAX_NETTOMEDIA_ENTRIES];
    static cyg_uint16         ntm_size = 0;
    static long               long_ret;
    static unsigned char      addr_ret [ETHER_ADDR_LEN];
    u_char      *cp;
    oid         *op;
    oid         lowest[16];
    oid         current[16];
    cyg_uint16  idx;
    cyg_int16   low_ia = -1; // notfound value
    cyg_tick_count_t        cur_time;
    static cyg_tick_count_t last_update_time = 0;


    /*
     * IP Net to Media table object identifier is of form:
     * 1.3.6.1.2.1.4.22.1.x.interface.A.B.C.D,  where A.B.C.D is IP address.
     * Interface is at offset 10,
     * IPADDR starts at offset 11.
     */

#define NETTOMEDIA_UPDATE_PERIOD  100   // 1 sec in csecs

    // would be silly to lock threads and populate the table every time.
    cur_time = cyg_current_time();
    if ((cur_time > last_update_time + NETTOMEDIA_UPDATE_PERIOD) ||
        (last_update_time > cur_time)) // in case someone reset clock
    { // ok, refresh our knowledge of arp
      last_update_time = cur_time;
      // retval is arp's count even if our list was too small. 
      // This way we recall with a bigger malloc down the road if we wanted.
      ntm_size = (cyg_uint16) populate_nettomedia_list (nettomedia_list, 
MAX_NETTOMEDIA_ENTRIES);
      if (ntm_size > MAX_NETTOMEDIA_ENTRIES)
        ntm_size = MAX_NETTOMEDIA_ENTRIES;
    }

    /* fill in object part of name for current (less sizeof instance 
part) */
    memcpy((char *)current, (char *)vp->name, (int)vp->namelen * 
sizeof(oid));

    for ( idx = 0; idx < ntm_size; ++idx)
    {
      // interface number
      current[10] = nettomedia_list[idx].if_index;
     
      // IP address
      cp = (u_char *)&(nettomedia_list[idx].ipv4_addr);
      op = current + 11;
      *op++ = *cp++;
      *op++ = *cp++;
      *op++ = *cp++;
      *op++ = *cp++;

      if (exact){
        if (snmp_oid_compare(current, 15, name, *length) == 0){
          memcpy( (char *)lowest,(char *)current, 15 * sizeof(oid));
          low_ia = idx;
          break;  /* no need to search further */
        }
      } else
      {
        if ((snmp_oid_compare(current, 15, name, *length) > 0) &&
                ((low_ia < 0) || (snmp_oid_compare(current, 15, lowest, 
15) < 0))) {
          /*
           * if new one is greater than input and closer to input than
           * previous lowest, save this one as the "next" one.
           */
          memcpy( (char *)lowest,(char *)current, 15 * sizeof(oid));
          low_ia = idx;
        }
      }
    }

    if ( low_ia < 0 )
      return(NULL);

    memcpy( (char *)name,(char *)lowest, 15 * sizeof(oid));
    *length = 15;
    *write_method = 0;
    *var_len = sizeof(long_return);

    /*
     * this is where we do the value assignments for the mib results.
     */
    switch(vp->magic) {
    case IPNETTOMEDIAIFINDEX:
        //NOTSUPPORTED: *write_method = write_ipNetToMediaIfIndex;
        long_ret = nettomedia_list[low_ia].if_index;
        return (unsigned char *) &long_ret;

    case IPNETTOMEDIAPHYSADDRESS: {
        memcpy (addr_ret, nettomedia_list[low_ia].mac_addr, ETHER_ADDR_LEN);
        *var_len = ETHER_ADDR_LEN;
        //NOTSUPPORTED: *write_method = write_ipNetToMediaPhysAddress;
        return (unsigned char *) addr_ret;
    }
    case IPNETTOMEDIANETADDRESS:
        //NOTSUPPORTED: *write_method = write_ipNetToMediaNetAddress;
        long_ret = /*ntohl*/ (nettomedia_list[low_ia].ipv4_addr);
        *var_len = 4;
        return (unsigned char *) &long_ret;

    case IPNETTOMEDIATYPE:
#ifndef IPNETTOMEDIATYPE_STATIC
#define IPNETTOMEDIATYPE_OTHER 1
#define IPNETTOMEDIATYPE_INVALID 2
#define IPNETTOMEDIATYPE_DYNAMIC 3
#define IPNETTOMEDIATYPE_STATIC 4
#endif
        long_ret = (nettomedia_list[low_ia].rt_flags | RTF_STATIC)? 
IPNETTOMEDIATYPE_STATIC:IPNETTOMEDIATYPE_DYNAMIC;
        //NOTSUPPORTED: *write_method = write_ipNetToMediaType;
        return (unsigned char *) &long_ret;

    default:
        ERROR_MSG("");
    }
    return NULL;
}



-- 
Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos
and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss



More information about the Ecos-discuss mailing list