通过IP获取MAC地址例子(内核层)

  博客地址:http://home.cnblogs.com/u/zengjianrong/

  在内核处理此流程,反而更加简单些,代码如下:

#include <net/arp.h>
#include <net/neighbour.h>
#include "linux/ctype.h"

#define MAC_BCAST_ADDR        (unsigned char *)"xffxffxffxffxffxff"

/******************************************************************************
 * 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 '': 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 ", __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 ", __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... ", __FUNCTION__, __LINE__); } else { printk("200.31.96.225-->%02x:%02x:%02x:%02x:%02x:%02x ", aucMac[0], aucMac[1], aucMac[2], aucMac[3], aucMac[4], aucMac[5]); } } EXPORT_SYMBOL(nArpTestByZjr);
原文地址:https://www.cnblogs.com/zengjianrong/p/4185454.html