LQ Newbie
Registered: Oct 2021
Distribution: Ubuntu
Posts: 1
Rep:
|
Netlink nlmsg_multicast() function returning -ESRCH even though the Netlink userspace application running.
I am writing a Linux kernel module and Linux userspace program and trying to establish a multicast netlink communication between them targeted from Linux kernel module to Linux userspace program.
Aim:
1)Linux userspace program will be added to a custom group and will be listening for incoming messages from Linux kernel module.
2)The Linux kernel module will send a multicast message which the user space program will receive and will just display the received payload.
The code for Netlink kernel module and Netlink userspace program is as follows.
/**********types**************/
typedef unsigned long _uint64_t;
typedef unsigned int _uint32_t;
typedef signed int _int32_t;
typedef short unsigned int _uint16_t;
typedef short signed int _int16_t;
typedef unsigned char _uint8_t;
typedef char _int8_t;
/***********************User space program***********************/
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<linux/netlink.h>
#include"types.h"
#define NETLINK_USER 31 //Custom netlink protocol number.
#define NOTIFICATION_GROUP (((_uint32_t)0x00000001)<<3)
_int32_t main(void)
{
_int32_t sock_fd;
struct msghdr msg;
_int8_t rcv_buffer[500] = {'\0'};
struct iovec iov[2];
struct nlmsghdr nlh;
sock_fd = socket(AF_NETLINK,SOCK_RAW,NETLINK_USER);
if(sock_fd & (0x00000001<<31))
{
perror("Failed to create a socket");
return -1;
}
printf("Successfully created a socket.\n");
struct sockaddr_nl src_addr,dst_addr;
memset(&src_addr,0,sizeof(src_addr));
memset(&dst_addr,0,sizeof(dst_addr));
memset(&nlh,0,sizeof(nlh));
memset(&msg,0,sizeof(msg));
src_addr.nl_family = AF_NETLINK; //socket family
src_addr.nl_groups = NOTIFICATION_GROUP;
src_addr.nl_pid = getpid();
bind(sock_fd,(struct sockaddr *)&src_addr,sizeof(src_addr));
iov[0].iov_base = &nlh;
iov[0].iov_len = sizeof(nlh);
iov[1].iov_base = rcv_buffer;
iov[1].iov_len = sizeof(rcv_buffer);
msg.msg_name = &dst_addr;
msg.msg_namelen = sizeof(dst_addr);
msg.msg_iov = iov;
msg.msg_iovlen = sizeof(iov)/sizeof(iov[0]);
printf("Waiting to receive message from kernel......\n");
recvmsg(sock_fd,&msg,0);
//(nl_msg_hdr+1) will point to start of payload data
printf("Received payload message : 0x%X\n",*(_uint32_t *)NLMSG_DATA(&nlh));
close(sock_fd);
return 0;
}
/***********************Linux kernel module**************************/
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/netlink.h>
#include<net/sock.h>
#include<linux/delay.h>
#include"types.h"
#define DATA_TYPE_u8 0
#define DATA_TYPE_u16 1
#define DATA_TYPE_u32 2
#define DATA_TYPE_u64 3
#define DATA_TYPE_STR 4
#define KERNEL_PID 0
#define NETLINK_CUSTOM_PROTCOL 31
#define NOTIFICATION_GROUP (((_uint32_t)0x00000001)<<3)
static struct sock *nl_sk = NULL;
static void send_notification_to_usp(void *data_ptr,_uint8_t data_type);
static _int32_t __init __nl_init(void)
{
nl_sk = netlink_kernel_create(&init_net,NETLINK_CUSTOM_PROTCOL,NULL);
if(nl_sk)
{
pr_info("Netlink socket creation : success.\n");
mdelay(20000);
_uint32_t __data = 0x11223344;
send_notification_to_usp(&__data,DATA_TYPE_u32);
}
else
{
pr_info("Netlink socket creation : failed.\n");
}
pr_info("%s module inserted in kernel.\n",__FUNCTION__);
return SUCCESS;
}
static void __exit __nl_exit(void)
{
//nlmsg_free(skbuff_out);
netlink_kernel_release(nl_sk);
pr_info("%s module removed from kernel.\n",__FUNCTION__);
}
static void send_notification_to_usp(void *data_ptr,_uint8_t data_type)
{
if(data_ptr)
{
struct sk_buff *skbuff_out = NULL;
_uint8_t u8_data;
_uint16_t u16_data;
_uint32_t u32_data;
_uint64_t u64_data;
_uint8_t *str_data = NULL;
struct nlmsghdr *nlh = NULL;
if(data_type == DATA_TYPE_u8)
{
u8_data = *(_uint8_t *)data_ptr;
skbuff_out = nlmsg_new(NLMSG_ALIGN(sizeof(u8_data)),GFP_KERNEL);
if(skbuff_out)
{
nlh = nlmsg_put(skbuff_out,KERNEL_PID,0,NLMSG_DONE,NLMSG_ALIGN(sizeof(u8_data)),0);
*(_uint8_t *)NLMSG_DATA(nlh) = u8_data;
}
else
{
pr_info("Failed to alocate socket buffer-u8_data.\n");
}
}
else if(data_type == DATA_TYPE_u16)
{
u16_data = *(_uint16_t *)data_ptr;
skbuff_out = nlmsg_new(NLMSG_ALIGN(sizeof(u16_data)),GFP_KERNEL);
if(skbuff_out)
{
nlh = nlmsg_put(skbuff_out,KERNEL_PID,0,NLMSG_DONE,NLMSG_ALIGN(sizeof(u8_data)),0);
*(_uint16_t *)NLMSG_DATA(nlh) = u16_data;
}
else
{
pr_info("Failed to alocate socket buffer-u16_data.\n");
}
}
else if(data_type == DATA_TYPE_u32)
{
u32_data = *(_uint32_t *)data_ptr;
skbuff_out = nlmsg_new(NLMSG_ALIGN(sizeof(u32_data)),GFP_KERNEL);
if(skbuff_out)
{
nlh = nlmsg_put(skbuff_out,KERNEL_PID,0,NLMSG_DONE,NLMSG_ALIGN(sizeof(u32_data)),0);
*(_uint32_t *)NLMSG_DATA(nlh) = u32_data;
}
else
{
pr_info("Failed to alocate socket buffer-u32_data.\n");
}
}
else if(data_type == DATA_TYPE_u64)
{
u64_data = *(_uint64_t *)data_ptr;
skbuff_out = nlmsg_new(NLMSG_ALIGN(sizeof(u64_data)),GFP_KERNEL);
if(skbuff_out)
{
nlh = nlmsg_put(skbuff_out,KERNEL_PID,0,NLMSG_DONE,NLMSG_ALIGN(sizeof(u64_data)),0);
*(_uint64_t *)NLMSG_DATA(nlh) = u64_data;
}
else
{
pr_info("Failed to alocate socket buffer-u64_data.\n");
}
}
else if(data_type == DATA_TYPE_STR)
{
str_data = (_uint8_t *)data_ptr;
skbuff_out = nlmsg_new(NLMSG_ALIGN(strlen(str_data)),GFP_KERNEL);
if(skbuff_out)
{
nlh = nlmsg_put(skbuff_out,KERNEL_PID,0,NLMSG_DONE,NLMSG_ALIGN(strlen(str_data)),0);
strncpy((_int8_t *)NLMSG_DATA(nlh),str_data,strlen(str_data));
}
else
{
pr_info("Failed to alocate socket buffer-str_data.\n");
}
}
//The below function is already in nlmsg_multicast().
_int32_t res;
res = nlmsg_multicast(nl_sk,skbuff_out,KERNEL_PID,NOTIFICATION_GROUP,GFP_KERNEL);
if(res<0)
{
pr_info("Failed to send multicast message to USP.\n");
pr_info("res : %d.\n",res);
//perror("Error message");
}
else
{
pr_info("Success send multicast message to USP.\n");
}
}
}
module_init(__nl_init);
module_exit(__nl_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Author name");
MODULE_VERSION("0.1");
MODULE_DESCRIPTION("Netlink kernel module");
The code compiles fine without any errors. The issues which are coming while running the code are as follows.
1)If the user program is run first without the kernel module being inserted in kernel first. Then the user program fails to create a socket and gives error message "Protocol not supported". So is this normal behavior or the kernel module needs to be inserted first and then the user program needs to be run.
2)If the kernel module is inserted first and then the userspace program is run then the userspace program is able to create socket and proceed forward but no message is received by userspace program and the userspace program keeps waiting.The kernel dmesg logs indicates that the nlmsg_multicast() function returns -ESRCH which indicates "There are no listeners for this group".
Linux Kernel version : 5.11.0
Any inputs on how to solve the above two issues will be helpful.
|