Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save arunk-s/c897bb9d75a6c98733d6 to your computer and use it in GitHub Desktop.
Save arunk-s/c897bb9d75a6c98733d6 to your computer and use it in GitHub Desktop.
netlink example code in c
KDIR := /lib/modules/$(shell uname -r)/build
obj-m += netlinkKernel.o
all:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
rm -rf *.o *.ko *.mod.* *.cmd .module* modules* Module* .*.cmd .tmp*
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
//Taken from https://stackoverflow.com/questions/15215865/netlink-sockets-in-c-using-the-3-x-linux-kernel?lq=1
#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__);
//This is for 3.6 kernels and above.
struct netlink_kernel_cfg cfg = {
.input = hello_nl_recv_msg,
};
nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);
//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");
//Taken from https://stackoverflow.com/questions/15215865/netlink-sockets-in-c-using-the-3-x-linux-kernel?lq=1
#include <sys/socket.h>
#include <linux/netlink.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.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;
int 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 */
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", (char *)NLMSG_DATA(nlh));
close(sock_fd);
}
@akinsWin
Copy link

can you ran?

@IS-BrianLian
Copy link

I trying workable on Linux 64 4.4.0-83-generic #106~14.04.1-Ubuntu SMP Mon Jun 26 18:10:19 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux.

@bsdb0y
Copy link

bsdb0y commented Aug 24, 2017

👍 Also working in Linux Kernel : 4.13.0-rc5 #1 SMP Tue Aug 15 19:53:44 IST 2017 x86_64 x86_64 x86_64 GNU/Linux

@ngorugan
Copy link

Working on ubuntu, thank you.

@Johnstedt
Copy link

@akinsWin ran can you?

@rameshyaga
Copy link

Hi arun, I am trying to write userspace to userspace netlink communication but I am not able to receive any message. Please correct the below code and also please let me know how to set dest_addr.nl_pid in sender.c

sender.c

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

//total netlink message length
#define NLINK_MSG_LEN 1024

int main()
{
int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_GENERIC);

    struct sockaddr_nl src_addr;
    struct sockaddr_nl dest_addr;
    //allocate buffer for netlink message which
    //is message header + message payload
    struct nlmsghdr *nlh =(struct nlmsghdr *) malloc(NLMSG_SPACE(NLINK_MSG_LEN));
    //fill the iovec structure
    struct iovev iov;
    //define the message header for message
    //sending
    struct msghdr msg;

    //AF_NETLINK socket protocol
    src_addr.nl_family = AF_NETLINK;

    //application unique id
    src_addr.nl_pid = 1;

    //specify not a multicast communication
    src_addr.nl_groups = 0;

    //attach socket to unique id or address
    bind(fd, (struct sockaddr *)&src_addr, sizeof(src_addr));

    dest_addr.nl_family = AF_NETLINK;

    //destination process id
    dest_addr.nl_pid = 2;

    dest_addr.nl_groups = 0;

    //netlink message length
    nlh->nlmsg_len = NLMSG_SPACE(NLINK_MSG_LEN);

    //src application unique id
    nlh->nlmsg_pid = 1;

    nlh->nlmsg_flags = 0;

    //copy the payload to be sent
    strcpy(NLMSG_DATA(nlh), "Hello Process");

    //netlink message header base address
    iov.iov_base = (void *)nlh;

    //netlink message length
    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;
    //send the message
    sendmsg(fd, &msg, 0);

}

receiver.c

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

//total netlink message length
#define NLINK_MSG_LEN 1024

int main()
{
int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_GENERIC);

    struct sockaddr_nl src_addr;
    struct sockaddr_nl dest_addr;
    //allocate buffer for netlink message which
    //is message header + message payload
    struct nlmsghdr *nlh =(struct nlmsghdr *) malloc(NLMSG_SPACE(NLINK_MSG_LEN));
    //fill the iovec structure
    struct iovev iov;
    //define the message header for message
    //sending
    struct msghdr msg;

    //AF_NETLINK socket protocol
    src_addr.nl_family = AF_NETLINK;

    //application unique id
    src_addr.nl_pid = 2;

    //specify not a multicast communication
    src_addr.nl_groups = 0;

    //attach socket to unique id or address
    bind(fd, (struct sockaddr *)&src_addr, sizeof(src_addr));

    memset(nlh, 0, NLMSG_SPACE(NLINK_MSG_PAYLOAD));

    //netlink message header base address
    iov.iov_base = (void *)nlh;

    //netlink message length
    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;
    //receive the message
    recvmsg(fd, &msg, 0);

    printf("received message %s\n", NLMSG_DATA(nlh));

}

@argonlaser
Copy link

Please find the sample code for user-user unicast NL communication here. I try to write and maintain core features of linux in this repo.
You can have a look and help yourself. Cheers !

@rameshyaga
Copy link

rameshyaga commented Feb 16, 2018

Hi Thanks for the response. I verified this code in linux version 3.2.0-61-generic-pae. I am able to send message but not able to receive.
Is it required to install any netlink package in linux machine?
Can you please explain the difference between nlh->nlmsg_pid and src_addr.nl_pid val? Is it getpid() value or any number I can put.Above userspace to kernel netlink code is working for me. but userspace to userspace code is not working. Please help me.

@rameshyaga
Copy link

I want to create user space to user space communication using my own protocol. Please provide any sample program with kernel module

@dolenam317
Copy link

NETLINK_USER is not a defined in <linux/netlink.h> so how this example run ? I know it works because i tested it but I can't figure out the magic behind. Could you please explain to me ?

@sachinites
Copy link

Why r u not freeing skb_out ?

@xjtuwxg
Copy link

xjtuwxg commented Aug 10, 2020

What a beautiful code format!

@TekuConcept
Copy link

Function hello_nl_recv_msg in netlinkKernel.c is incomplete (missing })

Also, the following changes should be made:
See also Does “sendmsg” free memory of the buffer or msg?

*** netlinkUser.c
--- netlinkUser.c
*************** int main()
*** 50,55 ****
--- 50,56 ----
  
  	printf("Sending message to kernel\n");
  	sendmsg(sock_fd,&msg,0);
+ 	free(nlh);
  	printf("Waiting for message from kernel\n");
  
  	/* Read message from kernel */

@sachinites nlmsg_unicast() will automagically free skb_out under the hood for us.
See also kernel crash when trying to free the skb with nlmsg_free(skb_out)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment