Search code examples
csocketslinux-kernelnetwork-programmingraw-sockets

Send a raw ethernet packet from inside a kernel module


I found out that I need to build a new sk_buff struct in the kernel module and pass it to my network device, but what I can't figure out is how to set the struct variables for a simple raw ethernet packet.

This has to be easy, but I would really appreciate it, if someone could give me a sample code of how to put the sk_buff together.


Solution

  • Take a look at the function packet_sendmsg_spkt in net/packet/af_packet.c for inspiration. The hard part is getting a struct sock if you don't have a socket...

    Edit: Added a basic code shell:

    int sendpacket(struct socket *sock, struct net_device *dev, __be16 proto, void *data, size_t len)
    {
        struct sock *sk = sock->sk;
        struct sk_buff *skb;
    
        if (!(dev->flags & IFF_UP))
            return -ENETDOWN;
    
        if (len > dev->mtu + dev->hard_header_len)
            return -EMSGSIZE;
    
        skb = sock_wmalloc(sk, len + LL_RESERVED_SPACE(dev), 0, GFP_KERNEL);
    
        if (skb == NULL)
            return -ENOBUFS;
    
        /* FIXME: Save some space for broken drivers that write a
         * hard header at transmission time by themselves. PPP is the
         * notable one here. This should really be fixed at the driver level.
         */
        skb_reserve(skb, LL_RESERVED_SPACE(dev));
        skb_reset_network_header(skb);
    
        /* Try to align data part correctly */
        if (dev->header_ops) {
            skb->data -= dev->hard_header_len;
            skb->tail -= dev->hard_header_len;
            if (len < dev->hard_header_len)
                skb_reset_network_header(skb);
        }
    
        memcpy(skb_put(skb, len), data, len);
        skb->protocol = proto;
        skb->dev = dev;
        skb->priority = sk->sk_priority;
    
        dev_queue_xmit(skb);
    
        return len;
    }