博客地址: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 ((0 == s_addr_remote) || (NULL == pucMac) || (NULL == dev)) { err = -EINVAL;/* INVALID ARGUMENT */ return err; } memset(&arpreq, 0, 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, 6); if (!(0 == pucMac[0] && 0 == pucMac[1] && 0 == pucMac[2] && 0== pucMac[3] && 0 == pucMac[4] && 0 == pucMac[5])) { err = 0; } } 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[4]; uint32_t val; const char *c; char *endptr; int gotend, n; c = (const char *)cp; n = 0; /* * Run through the string, grabbing numbers until * the end of the string, or some error */ gotend = 0; while (!gotend) { unsigned long l; l = simple_strtoul(c, &endptr, 0); if (l == ULONG_MAX || (l == 0 && endptr == c)) return (0); 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 (0); 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 == 3) /* Whoops. Quit. */ return (0); n++; c++; break; case '\0': gotend = 1; break; default: if (isspace((unsigned char)*c)) { gotend = 1; break; } else return (0); /* Invalid character, so fail */ } } /* * Concoct the address according to * the number of parts specified. */ switch (n) { case 0: /* a -- 32 bits */ /* * Nothing is necessary here. Overflow checking was * already done in strtoul(). */ break; case 1: /* a.b -- 8.24 bits */ if (val > 0xffffff || parts[0] > 0xff) return (0); val |= parts[0] << 24; break; case 2: /* a.b.c -- 8.8.16 bits */ if (val > 0xffff || parts[0] > 0xff || parts[1] > 0xff) return (0); val |= (parts[0] << 24) | (parts[1] << 16); break; case 3: /* a.b.c.d -- 8.8.8.8 bits */ if (val > 0xff || parts[0] > 0xff || parts[1] > 0xff || parts[2] > 0xff) return (0); val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); break; } if (addr != NULL) addr->s_addr = htonl(val); return (1); } int nArpTestByZjr(void) { struct in_addr sin_local_addr; struct in_addr sin_remote_addr; unsigned char aucMac[6]; memset(aucMac, 0, 6); memset(&sin_remote_addr, 0, sizeof(struct in_addr)); if (0 == (inet_aton("200.31.96.225", &sin_remote_addr))) { printk("%s: IP address '200.31.96.225' not valid\n", __FUNCTION__); return -1; } memset(&sin_local_addr, 0, sizeof(struct in_addr)); if (0 == (inet_aton("200.31.96.1", &sin_local_addr))) { printk("%s: IP address '200.31.96.1' not valid\n", __FUNCTION__); return -1; } if (0 > 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[0], aucMac[1], aucMac[2], aucMac[3], aucMac[4], aucMac[5]); } } EXPORT_SYMBOL(nArpTestByZjr);