-
-
Save arunk-s/c897bb9d75a6c98733d6 to your computer and use it in GitHub Desktop.
1. Execute make first. This will result in a netlinkKernel.ko output among many others. | |
2. Execute $ gcc netlinkUser.c -o netlinkUser | |
3. Insert kernel module by :$ sudo insmod netlinkKernel.ko | |
4. Run ./netlinkUser to see message and run dmesg to see debug messages | |
5. Remove module by : $ sudo rmmod netlinkKernel | |
6. Finally make clean to remove output files. |
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); | |
} |
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.
👍 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
Working on ubuntu, thank you.
@akinsWin ran can you?
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));
}
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.
I want to create user space to user space communication using my own protocol. Please provide any sample program with kernel module
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 ?
Why r u not freeing skb_out ?
What a beautiful code format!
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)
can you ran?