Welcome! Log In Create A New Profile


How to resolve the Mac address for an IP address under kernel module developing?

Posted by 915086731 
How to resolve the Mac address for an IP address under kernel module developing?
October 20, 2017 08:33AM
I want to build a tcp package in a kernel module and send it to another host by IP address using function dev_queue_xmit(skb). But I don't want to fill the Mac address manually by hand. The following is code for package producing. Some kernel functions call eth_rebuild_header(skb) to rebuild Mac header. However, in my case, it hangs my computer after being called. Google results answers that arp_find will crash the OS if the arp cache contains not entry for that IP address. But I'm sure the it exists in the arp cache as printed by shell command "arp -v".

static int build_and_xmit_tcp(char * eth, u_char * smac, u_char * dmac,
             u_long sip, u_long dip,
             u_short sport, u_short dport,
             u_char * pkt, int pkt_len,
             int syn, int ack, int fin,
             __be32 seq, __be32 seq_ack)
  struct sk_buff * skb = NULL;
  struct net_device * dev = NULL;
  struct ethhdr * ethdr = NULL;
  struct iphdr * iph = NULL;
  struct tcphdr * tcph = NULL;
  u_char * pdata = NULL;
  if(NULL == smac || NULL == dmac)
      goto out;

  if(NULL == (dev= dev_get_by_name(&init_net, eth)))
        goto out;
  skb = alloc_skb(pkt_len + sizeof(struct iphdr) + sizeof(struct tcphdr) + LL_RESERVED_SPACE(dev), GFP_ATOMIC);

  if(NULL == skb)
      goto out;
  skb_reserve(skb, LL_RESERVED_SPACE(dev));

  skb->dev = dev;
  skb->pkt_type = PACKET_OTHERHOST;
  skb->protocol = __constant_htons(ETH_P_IP);
  skb->ip_summed = CHECKSUM_NONE;
  skb->priority = 0;
    skb_set_network_header(skb, 0);
  skb_put(skb, sizeof(struct iphdr));
 skb_set_transport_header(skb, sizeof(struct iphdr));
  skb_put(skb, sizeof(struct tcphdr));

  pdata = skb_put(skb, pkt_len); 
     if(NULL != pkt)
        memcpy(pdata, pkt, pkt_len);

  tcph = tcp_hdr(skb);
  memset(tcph, 0, sizeof(struct tcphdr));
  tcph->source = sport;
  tcph->dest = dport;
  tcph->seq = htonl(seq);
  tcph-> ack_seq= htonl( seq_ack);
  tcph->psh = pkt_len>0? 1:0;
  tcph ->fin = fin;
  tcph->ack = ack;
  tcph->window=__constant_htons (65535);
  skb->csum = 0;
  tcph->check = 0;
  iph = ip_hdr(skb);
  iph->version = 4;
  iph->ihl = sizeof(struct iphdr)>>2;
  iph->frag_off = 0;
  iph->protocol = IPPROTO_TCP;
  iph->tos = 0;
  iph->daddr = dip;
  iph->saddr = sip;
  iph->ttl = 0x40;
  iph->tot_len = __constant_htons(skb->len);
  iph->check = 0;
  iph->check = ip_fast_csum((unsigned char *)iph,iph->ihl);

  skb->csum = skb_checksum(skb, iph->ihl*4, skb->len - iph->ihl * 4, 0);
  tcph->check = csum_tcpudp_magic(sip, dip, skb->len - iph->ihl * 4, IPPROTO_TCP, skb->csum);
  skb_push(skb, 14);
  skb_set_mac_header(skb, 0);
  ethdr = (struct ethhdr *)eth_hdr(skb);
//  memcpy(ethdr->h_dest, dmac, ETH_ALEN);
 // memcpy(ethdr->h_source, smac, ETH_ALEN);
  ethdr->h_proto = __constant_htons(ETH_P_IP);

//  arp_send(ARPOP_REQUEST, ETH_P_ARP, target, dev, saddr,
//       dst_ha, dev->dev_addr, NULL);
    eth_rebuild_header(skb);      // kernel hang....
  if(0 > dev_queue_xmit(skb)) {
        dev_put (dev);
        kfree_skb (skb);

        dev_put (dev);
        kfree_skb (skb);

static int __init myhook_init(void)
   printk("=========insert module......\n"winking smiley;
   build_and_xmit_tcp(ETH_O, GWMAC_O, DMAC, in_aton(GWIP_O), in_aton(DIP), htons(8888), htons(DPORT), 
                    "", 0,
                    1, 0, 0, 0, 0);

static void __exit myhook_fini(void)
   printk("=========rmmod ......\n"winking smiley;


Google gives me some other solution. They say arp_ioctl can resolve the Mac address. However, the fact is that, arp_ioctl is compiled statically into vmlinuz, which is not exported as a symbol to other modules.

int arp_get(char *ifname, char *ipStr)
    struct arpreq req;  
    struct sockaddr_in *sin;  
    int ret = 0;  
    int sock_fd = 0;
    struct net_device * dev = NULL;
    printk("arp  ----  \n"winking smiley;
    if(NULL == (dev= dev_get_by_name(&init_net, ifname))){
        dev_put (dev);
        printk("error dev get \n"winking smiley;
        return -1;
    struct net *net_arp = dev_net(dev);
    memset(&req, 0, sizeof(struct arpreq));  

    sin = (struct sockaddr_in *)&req.arp_pa;  
    sin->sin_family = AF_INET;  
    sin->sin_addr.s_addr = in_aton(ipStr);  

    strncpy(req.arp_dev, ifname, 15);
    ret = arp_ioctl(net_arp, SIOCGARP, &req);     // can't be called
    unsigned char *hw = (unsigned char *)req.arp_ha.sa_data;  
    printk("%#x-%#x-%#x-%#x-%#x-%#x\n", hw[0], hw[1], hw[2], hw[3], hw[4], hw[5]);
    return 0;

Maybe I need make a socket structure, and try some upper functions based on a socket. But how to do it...

kernel version : 2.6.32 os version: ubuntu 9.10 gcc version : 4.41

Edited 1 time(s). Last edit at 10/20/2017 08:34AM by 915086731.

Your Email:


Spam prevention:
Please, solve the mathematical question and enter the answer in the input field below. This is for blocking bots that try to post this form automatically.
Question: how much is 5 plus 21?