user1707718
user1707718

Reputation: 21

passing packets from IP layer to device driver

I am trying to pass a sk_buff packet from IP layer of the protocol stack to a device driver which I have created and registered. The code for the device driver is as follows :

    #include<linux/module.h>
    #include<linux/netdevice.h>
    #include<linux/kernel.h>
    #include<linux/skbuff.h>
    #include<linux/pci.h>
    #include<linux/interrupt.h>
    struct net_device *my_dev;
    static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
    {
           printk(KERN_INFO "I got a packet");    
           return NETDEV_TX_OK;
    }
    static int veth_open(struct net_device *dev)
    {

                  memcpy(dev->dev_addr, "\0ABCD0", ETH_ALEN);
                  netif_start_queue(dev);

                  return 0;
    }


    int veth_close(struct net_device *dev)
    {
           printk("releasing mydev\n");
           netif_stop_queue(dev);
           return 0;
    }

    int veth_dev_init(struct net_device *dev)
    {
           printk("initialising\n");
           return 0;
    }

    static struct net_device_ops veth_ops = {

     .ndo_init         = veth_dev_init,
     .ndo_open         = veth_open,
     .ndo_stop         = veth_close,
     .ndo_start_xmit   = veth_xmit,

       };
   int veth_init()
   {
   int ret,i;
   my_dev = alloc_netdev(sizeof(struct net_device), "my_dev", ether_setup);
   if (my_dev == NULL)
    return -ENOMEM; 
   my_dev->netdev_ops = &veth_ops;
       register_netdev(my_dev);
       return 0;
   }
   void veth_exit()
   {
    unregister_netdev(my_dev);
    free_netdev(my_dev);
   }

   module_init(veth_init);
   module_exit(veth_exit);

then after loading this module and using "ifconfig " to assign IP address to it, I have tried to pass a packet using dev_queue_xmit() function. the code is as fllows:

   struct sk_buff *skb;
   void generate_send()
   {
   skb=alloc_skb(skb,2);
   skb->data[0]='m';//just to check
       skb->dev="my_dev";
       dev_queue_xmit(skb);
   }
   static int testing_init(void)
   {
   //time=4;    
   generate_send();

   return 0;    
   }
   static void testing_exit(void)
   {
printk(KERN_INFO "Goodbye, world 2\n");
   }
   module_init(testing_init);
   module_exit(testing_exit);

but the packet is not getting passed and when I am trying to load this testing module the system shows fatal error and terminate the process. Can you suggest me a good approach to solve this?

Upvotes: 2

Views: 2910

Answers (1)

akp
akp

Reputation: 1823

As your code is showing that you are just allocating the skb as

   struct sk_buff *skb;
   void generate_send()
   {
   skb=alloc_skb(skb,2);
   skb->data[0]='m';//just to check
       skb->dev="my_dev";
       dev_queue_xmit(skb);
   }

so there is no checking that alloc_skb() allocate the storage successfully or not. And you are just setting the dev and data parameter of this(skb) structure. But if you see the source code of the function dev_queue_xmit() in the file /net/core/dev.c you will get the result why u are getting return value as positive but it doesn't mean the packet has been transmitted.

so first of all try to create the whole packet as its UDP/TCP header, IP Header,data as protocol suggest. and then set the fields of the skb to this whole new created packet. Now try to send it you will get result.

for reference try->

skb = alloc_skb(len, GFP_ATOMIC);
if (!skb)
        return;

skb_put(skb, len);

skb_push(skb, sizeof(*udph));
skb_reset_transport_header(skb);
udph = udp_hdr(skb);
udph->source = htons(....);
udph->dest = htons(...);
udph->len = htons(udp_len);
udph->check = 0;
udph->check = csum_tcpudp_magic(local_ip,
                                remote_ip,
                                udp_len, IPPROTO_UDP,
                                csum_partial(udph, udp_len, 0));

if (udph->check == 0)
        udph->check = CSUM_MANGLED_0;

skb_push(skb, sizeof(*iph));
skb_reset_network_header(skb);
iph = ip_hdr(skb);

/* iph->version = 4; iph->ihl = 5; */
put_unaligned(0x45, (unsigned char *)iph);
iph->tos      = 0;
put_unaligned(htons(ip_len), &(iph->tot_len));
iph->id       = htons(atomic_inc_return(&ip_ident));
iph->frag_off = 0;
iph->ttl      = 64;
iph->protocol = IPPROTO_UDP;
iph->check    = 0;
put_unaligned(local_ip, &(iph->saddr));
put_unaligned(remote_ip, &(iph->daddr));
iph->check    = ip_fast_csum((unsigned char *)iph, iph->ihl);

eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
skb_reset_mac_header(skb);
skb->protocol = eth->h_proto = htons(ETH_P_IP);
memcpy(eth->h_source, dev->dev_addr, ETH_ALEN);
memcpy(eth->h_dest, remote_mac, ETH_ALEN);

skb->dev = dev;


dev_queue_xmit(skb);

change the fields as required...

Upvotes: 1

Related Questions