Sunday, August 1, 2010

How to use Netlink Sockets

 After reading kernel source I finally managed to make netlink sockets work for me. Below is an example of Netlink socket basics i.e opening a netlink socket, reading and writing to it and closing it.



Kernel Module

#include <linux/module.h>
#include <net/sock.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>

#define NETLINK_USER 31

struct sock *nl_sk = NULL;

static void hello_nl_recv_msg(struct sk_buff *skb)
{
    struct nlmsghdr *nlh;
    int pid;
    struct sk_buff *skb_out;
    int msg_size;
    char *msg="Hello from kernel";
    int res;

    printk(KERN_INFO "Entering: %s\n", __FUNCTION__);
    
    msg_size=strlen(msg);
    
    nlh=(struct nlmsghdr*)skb->data;
    printk(KERN_INFO "Netlink received msg payload: %s\n",(char*)nlmsg_data(nlh));
    pid = nlh->nlmsg_pid; /*pid of sending process */

    skb_out = nlmsg_new(msg_size,0);

    if(!skb_out)
    {
        printk(KERN_ERR "Failed to allocate new skb\n");
        return;
    } 
    nlh=nlmsg_put(skb_out,0,0,NLMSG_DONE,msg_size,0);

    NETLINK_CB(skb_out).dst_group = 0; /* not in mcast group */
    strncpy(nlmsg_data(nlh),msg,msg_size);
    
    res=nlmsg_unicast(nl_sk,skb_out,pid);
    
    if(res<0)
        printk(KERN_INFO "Error while sending bak to user\n");
}

static int __init hello_init(void)
{
    printk("Entering: %s\n",__FUNCTION__);
    nl_sk=netlink_kernel_create(&init_net, NETLINK_USER, 0, hello_nl_recv_msg, NULL, THIS_MODULE);
    if(!nl_sk)
    {
        printk(KERN_ALERT "Error creating socket.\n");
        return -10;
    }
    return 0;
}

static void __exit hello_exit(void){
    printk(KERN_INFO "exiting hello module\n");
    netlink_kernel_release(nl_sk);
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("GPL");


User Program

#include <sys/socket.h>
#include <linux/netlink.h>

#define NETLINK_USER 31

#define MAX_PAYLOAD 1024  /* maximum payload size*/
struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
int sock_fd;
struct msghdr msg;

void main() {
    sock_fd=socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);
    if(sock_fd<0)
return -1;

    memset(&src_addr, 0, sizeof(src_addr));
    src_addr.nl_family = AF_NETLINK;
    src_addr.nl_pid = getpid();  /* self pid */
    /* interested in group 1<<0 */
    bind(sock_fd, (struct sockaddr*)&src_addr,
        sizeof(src_addr));

    memset(&dest_addr, 0, sizeof(dest_addr));
    memset(&dest_addr, 0, sizeof(dest_addr));
    dest_addr.nl_family = AF_NETLINK;
    dest_addr.nl_pid = 0;   /* For Linux Kernel */
    dest_addr.nl_groups = 0; /* unicast */
    
    nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
    memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
    nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
    nlh->nlmsg_pid = getpid();
    nlh->nlmsg_flags = 0;
    strcpy(NLMSG_DATA(nlh), "Hello");
    iov.iov_base = (void *)nlh;
    iov.iov_len = nlh->nlmsg_len;
    msg.msg_name = (void *)&dest_addr;
    msg.msg_namelen = sizeof(dest_addr);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    printf("Sending message to kernel\n");
    sendmsg(sock_fd,&msg,0);
    printf("Waiting for message from kernel\n");

    /* Read message from kernel */
    recvmsg(sock_fd, &msg, 0);
    printf(" Received message payload: %s\n",
           NLMSG_DATA(nlh));
    close(sock_fd);
}

8 comments:

Unknown said...

Thanks for this example.

Little remark for newer kernel (eg 3.6) slight modifications at the kernel modul are necessary:

top lines add:
static struct netlink_kernel_cfg cfg = {0};

within the code replace:
nl_sk=netlink_kernel_create(&init_net, NETLINK_USER, 0, hello_nl_recv_msg, NULL, THIS_MODULE);

with:
cfg.input = hello_nl_recv_msg;
nl_sk=netlink_kernel_create(&init_net, NETLINK_USER, THIS_MODULE, &cfg );

Unknown said...
This comment has been removed by the author.
The Geeks said...

hi..Im college student, thanks for sharing :)

rishibagrawal said...

nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));

You are not freeing this memory - where should we free this, after the sendmsg() or the recvmsg().

Unknown said...

what if following fails?

nlh=nlmsg_put(skb_out,0,0,NLMSG_DONE,msg_size,0);

what all need to be freed?

Angel Claudia said...

We are the best online Academic Writing Assistance around, and you will not have to worry about submitting an assignment that has been written in the wrong context.

Ivymelda said...

Medicine Essay Writing are the most outstanding in the writing industry, enabling you to achieve the best Thesis Writing Services. Also the professional writers’ commitments to delivering the top Medicine Essay Writing Services.

Legitimate Custom Research Paper Services said...

The backbone of Term Paper Writing Services company is its writers and ours are the choicest in the industry to ensure that clients acquire the Best Term Paper Services and that will make you collect a high-quality Custom Term Paper Writing Help.