title: Kernel Module to Ethernet Packet Echo
body: <p>I develop a linux kernel module to re-transmit some ethernet packet (do the echo). THe packet arrives, i check the ethernet destination address, and if it is for me, i re-transmit. If not i do nothing.</p>
  
  <p>I used dev_pack_eth to define my protocol handler to recieve all ethernet packet (EHT_P_ALL) and dev_queue_xmit to transmit the skb buff received.</p>
  
  <p>It works, the echo is functional but...</p>
  
  <p>Sometimes, very often. the kernel crashs and i don't know why.</p>
  
  <p>When i re-transmit the packet, i return NET_RX_Sucess.</p>
  
  <p>When i don't re-transmit i use kfree_skb to free the skb buff received and return NET_RX_DROP.</p>
  
  <p>I think the problem my be on this issues. Can you help me?</p>
  
  <p>If needed i could post the kernel module code.</p>
  
  <p>Best Regards!</p>
  
  <p>------------Edit:Code added--------</p>
  
  <pre><code>#include &lt;linux/module.h&gt;   /* Needed by all modules */
  #include &lt;linux/kernel.h&gt;   /* Needed for KERN_INFO */
  #include &lt;linux/init.h&gt;     /* Needed for the macros */
  #include &lt;linux/skbuff.h&gt;
  #include &lt;linux/if_ether.h&gt;
  #include &lt;linux/netdevice.h&gt;
  #include &lt;linux/netfilter.h&gt;
  #include &lt;linux/netfilter_ipv4.h&gt;
  #include &lt;linux/netfilter_bridge.h&gt;
  #include &lt;asm-generic/types.h&gt;
  
  
  /*Buscar as interfaces de rede*/
  struct net_device *dev_eth0;
  struct net_device *dev_eth1;
  int contador;
  
  static struct packet_type hook; /* Initialisation routine */
  
  void handler_add_config (void);
  void handler_remove(void);
  void print_mac_hdr(struct ethhdr *eth);
  
  static int hook_func( struct sk_buff *skb)
  {
  
          struct ethhdr *eth;    
          struct ethhdr aux;
  
          eth= eth_hdr(skb)
          print_mac_hdr(eth);
  
  
         /*If destination isn't the same that dev_addr, the packet is not for me: do nothing*/
          if(memcmp(eth-&gt;h_dest,skb-&gt;dev-&gt;dev_addr,ETH_ALEN)!=0)
              {
              printk("NÃ£o sÃ£o iguais!!!\n");
              }
          else
              {
          /*Swap addr*/
              memcpy(&amp;(aux.h_dest),eth-&gt;h_dest,ETH_ALEN);
              memcpy(eth-&gt;h_dest,eth-&gt;h_source,ETH_ALEN);
              memcpy(eth-&gt;h_source,&amp;(aux.h_dest),ETH_ALEN);
       /*Re build ther hearders*/
              skb-&gt;data = (unsigned char *)skb-&gt;mac_header;
              skb-&gt;len += ETH_HLEN;
  
              skb-&gt;pkt_type = PACKET_OUTGOING;
  
                    /*Send*/
                  if(dev_queue_xmit(skb)!= NET_XMIT_SUCCESS)
                   {
                        printk("Erro na transmissÃ£o\n");
                   }
                  else
                   {
                        printk("Trama retransmitida com sucesso\n");
                        return NET_RX_SUCCESS;
                   }
  
              }
  
  
  
      kfree_skb(skb);
      return NET_RX_DROP;
  }
  
  /*Print eth  headers*/
  void print_mac_hdr(struct ethhdr *eth)
  {
      printk("Destino: %02x:%02x:%02x:%02x:%02x:%02x \n",eth-&gt;h_dest[0],eth-&gt;h_dest[1],eth-&gt;h_dest[2],eth-&gt;h_dest[3],eth-&gt;h_dest[4],eth-&gt;h_dest[5]);
      printk("Origem: %02x:%02x:%02x:%02x:%02x:%02x\n",eth-&gt;h_source[0],eth-&gt;h_source[1],eth-&gt;h_source[2],eth-&gt;h_source[3],eth-&gt;h_source[4],eth-&gt;h_source[5]);
      printk("Proto: 0x%04x\n",ntohs(eth-&gt;h_proto));
  
  }
  
  /*Configure Protocol Handler*/
  
  void handler_add_config (void)
  {
          hook.type = htons(ETH_P_ALL);
          hook.func = (void *)hook_func;
          hook.dev = NULL;
          dev_add_pack(&amp;hook);
          printk("Handler Protocol adicionado!!!!\n");
  
  }
  /*Unregist protocol handler*/
  void handler_remove(void)
  {
      dev_remove_pack(&amp;hook);
      printk("Handler Protocol removido!!!!\n");
      synchronize_net();/*Sincronizar a rede!*/
  }
  
  /*Init module and protocol handler*/
  static int __init hook_init(void)
  {
  
      printk("Hello:I'm the hook module!!!!\n");
      contador =0;
      dev_eth0=dev_get_by_name(&amp;init_net,"eth0");
      dev_eth1=dev_get_by_name(&amp;init_net,"eth1");
      handler_add_config();
      return 0;
  }
  
  
  /*Remove module and protocol handler*/
  static void __exit hook_exit(void)
  {
  
      printk("Hook module says Goodbye!!!!!\n");
      handler_remove();
  
  }
  
  module_init(hook_init);
  module_exit(hook_exit);
  MODULE_LICENSE("GPL");
  </code></pre>