netlink multicast from kernel to user space error in linux kernel 3.10 in c
I had a similar problem and I think I may have been working of the same or similar example. There is not a huge amount I can tell you without seeing all of your code. I have can pass on a couple of things I did to make multicast work though.
- Define your group as 1 in both the kernel and userspace code.
- Remove setsockopt() altogether.
Without seeing the rest of your code, I cannot provide more instruction.
Good luck
Here is the code I used. It should help you along the way. However, my Kernel module does not have an exit function for security reasons.
Kernel Code
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netlink.h>
#include <net/netlink.h>
#include <net/sock.h>
#include <net/net_namespace.h>
#include <linux/skbuff.h>
#define MY_GROUP 1
struct sock* socket;
struct sk_buff* socket_buff;
char *log;
void nl_data_ready(struct sock *sk, int len)
{
nlmsg_free(socket_buff);
}
static void send_to_user(char *message)
{
struct nlmsghdr *nlsk_mh;
char* msg = message;
int res;
socket_buff = nlmsg_new(256, GFP_KERNEL);
nlsk_mh = nlmsg_put(socket_buff, 0, 0, NLMSG_DONE, strlen(msg), 0);
NETLINK_CB(socket_buff).pid = 0; // kernel pid
NETLINK_CB(socket_buff).dst_group = MY_GROUP;
strcpy(nlmsg_data(nlsk_mh), msg);
res = nlmsg_multicast(socket, socket_buff, 0, MY_GROUP, GFP_KERNEL);
if(res < 0)
{
printk("Multicast not sent: res < 0\n");
return 0;
}
else
{
printk("Multicast Sent\n");
}
}
void netlink_test(char *buf)
{
socket = netlink_kernel_create(&init_net, NETLINK_USERSOCK, MY_GROUP, nl_data_ready, NULL, THIS_MODULE);
if (!socket) {
printk("Error creating socket.\n");
return -10;
}
else
{
printk("\n\nSOCKET WAS CREATED SUCCESSFULLY\n\n");
}
printk("The message to be sent to the user is: %s", buf);
send_to_user(buf);
netlink_kernel_release(socket);
return 0;
}
UserSpace Code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <unistd.h>
#include <errno.h>
#include <unistd.h>
#define MAX_PAYLOAD 1024 /* maximum payload size*/
#define MY_GROUP 1
int main(void)
{
int sock_fd;
struct sockaddr_nl user_sockaddr;
struct nlmsghdr *nl_msghdr;
struct msghdr msghdr;
struct iovec iov;
char* kernel_msg;
sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USERSOCK);
if(sock_fd<0)
{
printf("Error creating socket because: %s\n", strerror(errno));
return -1;
}
memset(&user_sockaddr, 0, sizeof(user_sockaddr));
user_sockaddr.nl_family = AF_NETLINK;
user_sockaddr.nl_pid = getpid();
user_sockaddr.nl_groups = MY_GROUP;
bind(sock_fd, (struct sockaddr*)&user_sockaddr, sizeof(user_sockaddr));
while (1) {
nl_msghdr = (struct nlmsghdr*) malloc(NLMSG_SPACE(1024));
memset(nl_msghdr, 0, NLMSG_SPACE(1024));
iov.iov_base = (void*) nl_msghdr;
iov.iov_len = NLMSG_SPACE(1024);
msghdr.msg_name = (void*) &user_sockaddr;
msghdr.msg_namelen = sizeof(user_sockaddr);
msghdr.msg_iov = &iov;
msghdr.msg_iovlen = 1;
printf("Waiting to receive message\n");
recvmsg(sock_fd, &msghdr, 0);
kernel_msg = (char*)NLMSG_DATA(nl_msghdr);
printf("Kernel message: %s\n", kernel_msg); // print to android logs
}
close(sock_fd);
}
Also, I believe that the netlink_kernel_create()
function has different implementations in different Kernel versions. So some functions I have in here might be different for your Kernel version (depending on what it is).
Also, I think the Kernel code requires a callback function. I did not notice this in your code. The code should work but the article I linked to is much more useful for figuring out exactly what is going on.
Cheers
Can kernel module take initiative to send message to user space with netlink?
This looks like bad design (because upper layers should depend on lower layers, not the other way around). But if you're convinced the kernel cannot sit idle or operate using default configuration until userspace can fetch info, then first install this tool (might want to read the core guide too), and then do something like this:
Kernel:
#include <linux/module.h>
#include <linux/kernel.h>
#include <net/netlink.h>
#include <net/net_namespace.h>
#define MYPROTO NETLINK_USERSOCK
#define MYGRP 22
static struct sock *nl_sk;
static struct timer_list timer;
void try_send(unsigned long data)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
char *msg = "Hello from kernel";
int msg_size = strlen(msg) + 1;
int res;
skb = nlmsg_new(NLMSG_ALIGN(msg_size + 1), GFP_ATOMIC);
if (!skb) {
pr_err("Allocation failure.\n");
return;
}
nlh = nlmsg_put(skb, 0, 1, NLMSG_DONE, msg_size + 1, 0);
strcpy(nlmsg_data(nlh), msg);
pr_info("Sending multicast.\n");
res = nlmsg_multicast(nl_sk, skb, 0, MYGRP, GFP_ATOMIC);
if (res < 0) {
pr_info("nlmsg_multicast() error: %d. Will try again later.\n", res);
/* Wait 1 second. */
mod_timer(&timer, jiffies + msecs_to_jiffies(1000));
} else {
pr_info("Success.\n");
}
}
static int handle_netlink_message(struct sk_buff *skb_in, struct nlmsghdr *nl_hdr)
{
char *hello;
hello = NLMSG_DATA(nl_hdr);
pr_info("Userspace says '%s.'\n", hello);
return 0;
}
static void receive_answer(struct sk_buff *skb)
{
netlink_rcv_skb(skb, &handle_netlink_message);
}
static int __init hello_init(void)
{
pr_info("Inserting module.\n");
nl_sk = netlink_kernel_create(&init_net, MYPROTO, 0, receive_answer, NULL, THIS_MODULE);
if (!nl_sk) {
pr_err("Error creating socket.\n");
return -10;
}
init_timer(&timer);
timer.function = try_send;
timer.expires = jiffies + 1000;
timer.data = 0;
add_timer(&timer);
return 0;
}
static void __exit hello_exit(void)
{
del_timer_sync(&timer);
netlink_kernel_release(nl_sk);
pr_info("Exiting module.\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
User (I'm compiling using gcc usr.c -I/usr/include/libnl3 -lnl-3 -Wall
, your mileage may vary):
#include <netlink/netlink.h>
#include <netlink/msg.h>
#define MYPROTO NETLINK_USERSOCK
#define MYMGRP 22
struct nl_sock *sk;
void respond_to_kernel(void)
{
char *response = "foo bar";
int error;
error = nl_send_simple(sk, 12345, NLMSG_DONE, response, strlen(response) + 1);
if (error < 0) {
printf("nl_send_simple() threw errcode %d.\n", error);
printf("libnl's message: %s", nl_geterror(error));
} else {
printf("Responded %d bytes.\n", error);
}
}
int receive_kernel_request(struct nl_msg *msg, void *arg)
{
char *hello;
hello = nlmsg_data(nlmsg_hdr(msg));
printf("Kernel says '%s'.\n", hello);
respond_to_kernel();
return 0;
}
int prepare_socket(void)
{
int error;
sk = nl_socket_alloc();
if (!sk) {
printf("nl_socket_alloc() returned NULL.\n");
return -1;
}
nl_socket_disable_seq_check(sk);
error = nl_socket_modify_cb(sk, NL_CB_FINISH, NL_CB_CUSTOM, receive_kernel_request, NULL);
if (error < 0) {
printf("Could not register callback function. Errcode: %d\n", error);
goto fail;
}
error = nl_connect(sk, MYPROTO);
if (error < 0) {
printf("Connection failed: %d\n", error);
goto fail;
}
error = nl_socket_add_memberships(sk, MYMGRP, 0);
if (error) {
printf("Could not register to the multicast group. %d\n", error);
goto fail;
}
return 0;
fail:
printf("libnl's message: %s\n", nl_geterror(error));
nl_socket_free(sk);
return error;
}
int wait_for_kernel_message(void)
{
int error;
printf("Waiting for kernel request...\n");
error = nl_recvmsgs_default(sk);
if (error < 0) {
printf("nl_send_simple() threw errcode %d.\n", error);
printf("libnl's message: %s\n", nl_geterror(error));
return error;
}
return 0;
}
void destroy_socket(void)
{
nl_socket_free(sk);
}
int main(int argc, char *argv[])
{
int error;
error = prepare_socket();
if (error)
return error;
error = wait_for_kernel_message();
destroy_socket();
return error;
}
Tested on kernel 3.2. (Sorry; that's the lowest I have right now.)
Python Netlink Multicast Communication in Kernels above 4
You forgot to bind the socket. :-)
I'm not very fluent with Python, so use this only as a starting point (between the socket
and the setsockopt
):
sock.bind((0, 0))
That prints me a bunch of garbage, among which I can see
Hello from kernel
By the way: When nlmsg_multicast()
throws ESRCH
, it's usually (or maybe always) because there were no clients listening.
First open the client, then try to send the message from the kernel.
Otherwise you can always ignore that error code it that makes sense for your use case.
Related Topics
How to Disable CPU Cache (L1/L2) on a Linux System
Netfilter-Like Kernel Module to Get Source and Destination Address
Is There a Command to List All Unix Group Names
Create a Dedicated Folder for Every Zip Files in a Directory and Extract Zip Files
How Is It Possible That Kill -9 for a Process on Linux Has No Effect
Create a Static Haskell Linux Executable
Is There Any Method to Run Perf Under Wsl
How to Grep a String After a Specified Line Number
How to Build an App for an Old Linux Distribution, and Avoid the Fatal: Kernel Too Old Error
Command Substitution Within Sed Expression
How to Remove Specific Rules from Iptables
How to Map a Hostname *And* a Port with /Etc/Hosts
Linux/Bash, Using Ps -O to Get Process by Specific Name
How to Prepend a Directory the Library Path When Loading a Core File in Gdb on Linux
Explanation of Convertor of Cidr to Netmask in Linux Shell Netmask2Cdir and Cdir2Netmask