I'm trying to implement kernel-user communication using netlink sockets and the generic message type. So far I'm able to send Messages from user space to the kernel and then send a message back to user space. The Problem is that in my user space program I always get an error that an invalid/malformed message was received. In the user space program I'm using libnl for the netlink communication.
The relevant netlink kernel code Looks like the following:
enum nl_tdisk_attr {
NL_UNSPEC,
NL_MY_ATTR, //My argument
__NL_MAX
};
#define NL_MAX (__NL_MAX - 1)
enum nl_tdisk_msg_types {
NL_CMD_READ = 0,
NL_CMD_MY_CMD //My command
NL_CMD_MAX
};
//Family definition
static struct genl_family family = {
.id = GENL_ID_GENERATE,
.name = "my-family",
.hdrsize = 0,
.version = 0,
.maxattr = NL_MAX,
};
//Command definition
static struct genl_ops ops[] = {
{
.cmd = NL_CMD_MY_CMD,
.doit = genl_register,
}
};
//...
//When the module is loaded:
genl_register_family_with_ops(&family, ops);
//Now some data should be sent to user space:
struct sk_buff *msg= nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
void *hdr = genlmsg_put(msg, port/*note1*/, 0, &family, 0/*note2*/, NL_CMD_MY_CMD);
nla_put_u32(msg, NL_MY_ATTR, some_value);
genlmsg_end(msg, hdr);
genlmsg_unicast(&init_net, msg, port/*note1*/); //note3
Please note that I removed error checking to reduce the amount of code
Some notes:
- note1: The port of the user space program is stored internally in the kernel module - I'm 100% sure it is correct
- note2: In the flags I also tried to set NLM_F_REQUEST but without success
- note3: The function
genlmsg_unicast
always Returns 0 which means that the message was sent successfully. So I assume the kernel code should be fine.
And here the user space code:
#include <netlink/netlink.h>
#include <netlink/socket.h>
#include <netlink/types.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/ctrl.h>
#include <netlink/genl/mngt.h>
//...
struct nl_sock *socket = nl_socket_alloc();
//I explicitly set those callbacks to get some debug information
nl_socket_modify_cb(socket, NL_CB_MSG_IN, NL_CB_DEBUG, NULL, NULL);
nl_socket_modify_cb(socket, NL_CB_INVALID, NL_CB_DEBUG, NULL, NULL);
//I also tried to Play around with the buffer size:
nl_socket_set_buffer_size(socket, 65536, 65536);
genl_connect(socket);
familyId = genl_ctrl_resolve(socket, "my-family"); //This works and gives me the correct Family id
nl_recvmsgs_default(socket);
As soon as the kernel sends a message I see debug Information in the user space program but sadly it's just error Messages:
-- Debug: Received Message:
-------------------------- BEGIN NETLINK MESSAGE ---------------------------
[NETLINK HEADER] 16 octets
.nlmsg_len = 308
.type = 23 <0x17>
.flags = 0
.seq = 0
.port = -1765782228
[GENERIC NETLINK HEADER] 4 octets
.cmd = 1
.version = 1
.unused = 0
[PAYLOAD] 4 octets
08 00 02 00 ....
--------------------------- END NETLINK MESSAGE ---------------------------
-- Error: Invalid message: type=0x17 length=24 flags=0 sequence-nr=0 pid=2529185068
As you can see, after the line "END NETLINK MESSAGE" the is the message from the callback NL_CB_INVALID
which is telling me that in invalid message was received.
So actually the communication per se is working as it should it just receives an invalid message, don't know why. Does anybody know where I can look for more Information? WHY is the message malformed... Or even better: does anyone see an error in my code? Or does anyone know a really good Website which describes such a Scenario?