Linux. Sol_Netlink Not Defined

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.

  1. Define your group as 1 in both the kernel and userspace code.
  2. 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



Leave a reply



Submit