This is the mail archive of the ecos-discuss@sourceware.org mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Patch for SNMP ipNetToMediaTable to return ARP entries


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]