博客地址:http://home.cnblogs.com/u/zengjianrong/
在内核处理此流程,反而更加简单些,代码如下:
#include <net/arp.h>
#include <net/neighbour.h>
#include "linux/ctype.h" #define MAC_BCAST_ADDR (unsigned char *)"\xff\xff\xff\xff\xff\xff" /******************************************************************************
* nArpTblCtl - find mac from arp_tbl by ip
* DESCRIPTION: -
* Input:
* Output:
* Returns: -EAGAIN -- find nothing, but had send arp request.try again.
* -ENXIO -- find nothing, and create error.
* 0 -- find ok.
* modification history
* --------------------
* 2.00, 2014-12-18 , zengjianrong written
* --------------------
******************************************************************************/
static int nArpTblCtl(struct net_device *dev, const __be32 s_addr_remote, const __be32 s_addr_local, const unsigned char *pucMac)
{
struct arpreq arpreq;
struct sockaddr_in *sin = NULL;
struct neighbour *neigh = NULL;
unsigned char *hw_addr = NULL;
int err = -ENXIO; /* NO such device or address */ if (( == s_addr_remote)
|| (NULL == pucMac)
|| (NULL == dev))
{
err = -EINVAL;/* INVALID ARGUMENT */
return err;
} memset(&arpreq, , sizeof(struct arpreq));
sin = (struct sockaddr_in *) &(arpreq.arp_pa);
sin->sin_family = AF_INET;
memcpy(&(sin->sin_addr.s_addr), &s_addr_remote, sizeof(__be32));
strcpy(arpreq.arp_dev, dev->name); rtnl_lock();
if (neigh = neigh_lookup(&arp_tbl, &s_addr_remote, dev))
{
read_lock_bh(&neigh->lock);
memcpy(arpreq.arp_ha.sa_data, neigh->ha, dev->addr_len);
read_unlock_bh(&neigh->lock);
neigh_release(neigh); hw_addr = (unsigned char *) arpreq.arp_ha.sa_data;
memcpy(pucMac, hw_addr, );
if (!( == pucMac[] && == pucMac[] && == pucMac[]
&& == pucMac[] && == pucMac[] && == pucMac[]))
{
err = ;
}
}
else
{
if (neigh = neigh_create(&arp_tbl, &s_addr_remote, dev))
{
arp_send(ARPOP_REQUEST, ETH_P_ARP, s_addr_remote, netdev_eth1, s_addr_local,
MAC_BCAST_ADDR, netdev_eth1->dev_addr, NULL);
err = -EAGAIN; /* try again */
}
}
rtnl_unlock(); return err;
}
static int inet_aton(cp, addr)
const char *cp;
struct in_addr *addr;
{
u_long parts[];
uint32_t val;
const char *c;
char *endptr;
int gotend, n; c = (const char *)cp;
n = ;
/*
* Run through the string, grabbing numbers until
* the end of the string, or some error
*/
gotend = ;
while (!gotend)
{
unsigned long l; l = simple_strtoul(c, &endptr, ); if (l == ULONG_MAX || (l == && endptr == c))
return (); val = (uint32_t)l;
/*
* If the whole string is invalid, endptr will equal
* c.. this way we can make sure someone hasn't
* gone '.12' or something which would get past
* the next check.
*/
if (endptr == c)
return ();
parts[n] = val;
c = endptr; /* Check the next character past the previous number's end */
switch (*c)
{
case '.' :
/* Make sure we only do 3 dots .. */
if (n == ) /* Whoops. Quit. */
return ();
n++;
c++;
break; case '\0':
gotend = ;
break; default:
if (isspace((unsigned char)*c))
{
gotend = ;
break;
}
else
return (); /* Invalid character, so fail */
} } /*
* Concoct the address according to
* the number of parts specified.
*/ switch (n)
{
case : /* a -- 32 bits */
/*
* Nothing is necessary here. Overflow checking was
* already done in strtoul().
*/
break;
case : /* a.b -- 8.24 bits */
if (val > 0xffffff || parts[] > 0xff)
return ();
val |= parts[] << ;
break; case : /* a.b.c -- 8.8.16 bits */
if (val > 0xffff || parts[] > 0xff || parts[] > 0xff)
return ();
val |= (parts[] << ) | (parts[] << );
break; case : /* a.b.c.d -- 8.8.8.8 bits */
if (val > 0xff || parts[] > 0xff || parts[] > 0xff ||
parts[] > 0xff)
return ();
val |= (parts[] << ) | (parts[] << ) | (parts[] << );
break;
} if (addr != NULL)
addr->s_addr = htonl(val);
return ();
} int nArpTestByZjr(void)
{
struct in_addr sin_local_addr;
struct in_addr sin_remote_addr;
unsigned char aucMac[];
memset(aucMac, , );
memset(&sin_remote_addr, , sizeof(struct in_addr));
if ( == (inet_aton("200.31.96.225", &sin_remote_addr)))
{
printk("%s: IP address '200.31.96.225' not valid\n", __FUNCTION__);
return -;
}
memset(&sin_local_addr, , sizeof(struct in_addr));
if ( == (inet_aton("200.31.96.1", &sin_local_addr)))
{
printk("%s: IP address '200.31.96.1' not valid\n", __FUNCTION__);
return -;
} if ( > nArpTblCtl(netdev_eth1, sin_remote_addr.s_addr, sin_local_addr.s_addr, &aucMac))
{
printk("func:%s,line:%d, find nothing...\n", __FUNCTION__, __LINE__);
}
else
{
printk("200.31.96.225-->%02x:%02x:%02x:%02x:%02x:%02x\n",
aucMac[], aucMac[], aucMac[], aucMac[], aucMac[], aucMac[]);
}
}
EXPORT_SYMBOL(nArpTestByZjr);