Your core problem is that before using a Generic Netlink family, you first have to register it (this also applies to normal Netlink families). The kernel cannot handle families it doesn't know. Unless you're using an already existing family, this shapes the way you have to approach Netlink.
A Generic Netlink Family belongs to a kernel module. This means a userspace client cannot create a family. In turn, this means you can't just start the client, then have the module send the message right after it creates the family. This is because the family doesn't exist at the moment the client wanted to bind itself to it.
What you need to do is this:
- Create and register the family and the multicast group while you're inserting the module.
- Start the userspace client and have it bind itself to the family and multicast group.
- Have the kernel module send the message at some point (after the client's bind).
- The userspace client now receives the message.
- When the module is removed, it should unregister the family.
My version of your code follows. This is driver.c
, the kernel module. As you can see, I decided to send the message repeatedly on a timer that runs every two seconds. This gives you time to start the client:
#include <linux/kernel.h>
#include <linux/module.h>
#include <net/genetlink.h>
#include <linux/timer.h>
static struct timer_list timer;
static const int repeat_ms = 2000;
/**
* This callback runs whenever the socket receives messages.
* We don't use it now, but Linux complains if we don't define it.
*/
static int hello(struct sk_buff *skb, struct genl_info *info)
{
pr_info("Received a message in kernelspace.\n");
return 0;
}
/**
* Attributes are fields of data your messages will contain.
* Among other reasons, the designers of Netlink want you to use these instead
* of dumping raw data to the packet payload because it's designed to prevent
* alignment problems for you.
* (http://www.catb.org/esr/structure-packing/)
*/
enum attributes {
/*
* The first one has to be a throwaway empty attribute; I don't know
* why.
* If you remove it, ATTR_HELLO (the first one) stops working, because
* it then becomes the throwaway.
*/
ATTR_DUMMY,
ATTR_HELLO,
ATTR_FOO,
/* This must be last! */
__ATTR_MAX,
};
/**
* Here you can define some constraints for the attributes so Linux will
* validate them for you.
*/
static struct nla_policy policies[] = {
[ATTR_HELLO] = { .type = NLA_STRING, },
[ATTR_FOO] = { .type = NLA_U32, },
};
/**
* Message type codes. All you need is a hello sorta function, so that's what
* I'm defining.
*/
enum commands {
COMMAND_HELLO,
/* This must be last! */
__COMMAND_MAX,
};
/**
* Actual message type definition.
*/
struct genl_ops ops[] = {
{
.cmd = COMMAND_HELLO,
.flags = 0,
.doit = hello, /* The dummy function we defined above. */
.dumpit = NULL,
},
};
/**
* Your multicast group. Choose a likely unique name.
*/
struct genl_multicast_group groups[] = {
{ .name = "PotatoGroup" },
};
/**
* A Generic Netlink family is a group of listeners who can and want to speak
* your "language" (ie. your set of Attributes).
* Anyone who wants to hear your messages needs to register to the same family
* as you.
* (And because we're using multicast, they will have to register to the same
* multicast group as well.)
*/
struct genl_family family = {
.hdrsize = 0,
.name = "PotatoFamily",
.version = 1,
.maxattr = __ATTR_MAX,
.policy = policies,
.ops = ops,
.n_ops = ARRAY_SIZE(ops),
.mcgrps = groups,
.n_mcgrps = ARRAY_SIZE(groups),
};
void send_multicast(struct timer_list *t)
{
struct sk_buff *skb;
void *msg_head;
unsigned char *msg = "TEST";
int error;
pr_info("----- Running timer -----\n");
pr_info("Newing message.\n");
skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
if (!skb) {
pr_err("genlmsg_new() failed.\n");
goto end;
}
pr_info("Adding Generic Netlink header to the message.\n");
msg_head = genlmsg_put(skb, 0, 0, &family, 0, COMMAND_HELLO);
if (!msg_head) {
pr_err("genlmsg_put() failed.\n");
kfree_skb(skb);
goto end;
}
pr_info("Nla_putting 'hello' attribute.\n");
error = nla_put_string(skb, ATTR_HELLO, msg);
if (error) {
pr_err("nla_put_string() failed: %d\n", error);
kfree_skb(skb);
goto end;
}
pr_info("Nla_putting 'foo' attribute.\n");
error = nla_put_u32(skb, ATTR_FOO, 12345);
if (error) {
pr_err("nla_put_u32() failed: %d\n", error);
kfree_skb(skb);
goto end;
}
pr_info("Ending message.\n");
genlmsg_end(skb, msg_head);
pr_info("Multicasting message.\n");
/*
* The family has only one group, so the group ID is just the family's
* group offset.
* mcgrp_offset is supposed to be private, so use this value for debug
* purposes only.
*/
pr_info("The group ID is %u.\n", family.mcgrp_offset);
error = genlmsg_multicast_allns(&family, skb, 0, 0, GFP_KERNEL);
if (error) {
pr_err("genlmsg_multicast_allns() failed: %d\n", error);
pr_err("(This can happen if nobody is listening. "
"Because it's not that unexpected, "
"you might want to just ignore this error.)\n");
goto end;
}
pr_info("Success.\n");
end:
// Reschedule the timer to call this function again in repeat_ms
// milliseconds
mod_timer(t, jiffies + msecs_to_jiffies(repeat_ms));
}
static int init_socket(void)
{
int error;
pr_info("Registering family.\n");
error = genl_register_family(&family);
if (error)
pr_err("Family registration failed: %d\n", error);
return error;
}
static void initialize_timer(void)
{
pr_info("Starting timer.\n");
// Initialize the timer and assign the callback function
timer_setup(&timer, send_multicast, 0);
// Set the timer to expire in repeat_ms milliseconds from now
mod_timer(&timer, jiffies + msecs_to_jiffies(repeat_ms));
}
static int __init hello_init(void)
{
int error;
error = init_socket();
if (error)
return error;
initialize_timer();
pr_info("Hello module registered.\n");
return 0;
}
static void __exit hello_exit(void)
{
// Make sure to delete the timer when exiting your module
del_timer(&timer);
genl_unregister_family(&family);
pr_info("Hello removed.\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
And this is app.c
, the userspace client:
#include <netlink/netlink.h>
#include <netlink/socket.h>
#include <netlink/msg.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/ctrl.h>
static struct nl_sock *sk = NULL;
/**
* Attributes and commands have to be the same as in kernelspace, so you might
* want to move these enums to a .h and just #include that from both files.
*/
enum attributes {
ATTR_DUMMY,
ATTR_HELLO,
ATTR_FOO,
/* This must be last! */
__ATTR_MAX,
};
enum commands {
COMMAND_HELLO,
/* This must be last! */
__COMMAND_MAX,
};
static int fail(int error, char *func_name)
{
printf("%s() failed.\n", func_name);
return error;
}
static int nl_fail(int error, char *func_name)
{
printf("%s (%d)\n", nl_geterror(error), error);
return fail(error, func_name);
}
/*
* This function will be called for each valid netlink message received
* in nl_recvmsgs_default()
*/
static int cb(struct nl_msg *msg, void *arg)
{
struct nlmsghdr *nl_hdr;
struct genlmsghdr *genl_hdr;
struct nlattr *attrs[__ATTR_MAX];
int error;
printf("The kernel module sent a message.\n");
nl_hdr = nlmsg_hdr(msg);
genl_hdr = genlmsg_hdr(nl_hdr);
if (genl_hdr->cmd != COMMAND_HELLO) {
printf("Oops? The message type is not Hello; ignoring.\n");
return 0;
}
error = genlmsg_parse(nl_hdr, 0, attrs, __ATTR_MAX - 1, NULL);
if (error)
return nl_fail(error, "genlmsg_parse");
/* Remember: attrs[0] is a throwaway. */
if (attrs[1])
printf("ATTR_HELLO: len:%u type:%u data:%s\n",
attrs[1]->nla_len,
attrs[1]->nla_type,
(char *)nla_data(attrs[1]));
else
printf("ATTR_HELLO: null\n");
if (attrs[2])
printf("ATTR_FOO: len:%u type:%u data:%u\n",
attrs[2]->nla_len,
attrs[2]->nla_type,
*((__u32 *)nla_data(attrs[2])));
else
printf("ATTR_FOO: null\n");
return 0;
}
static int do_things(void)
{
struct genl_family *family;
int group;
int error;
/* Socket allocation yadda yadda. */
sk = nl_socket_alloc();
if (!sk)
return fail(-1, "nl_socket_alloc");
nl_socket_disable_seq_check(sk);
error = nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, cb, NULL);
if (error)
return nl_fail(error, "nl_socket_modify_cb");
error = genl_connect(sk);
if (error)
return nl_fail(error, "genl_connect");
/* Find the multicast group identifier and register ourselves to it. */
group = genl_ctrl_resolve_grp(sk, "PotatoFamily", "PotatoGroup");
if (group < 0)
return nl_fail(group, "genl_ctrl_resolve_grp");
printf("The group is %u.\n", group);
error = nl_socket_add_memberships(sk, group, 0);
if (error) {
printf("nl_socket_add_memberships() failed: %d\n", error);
return error;
}
/* Finally, receive the message. */
nl_recvmsgs_default(sk);
return 0;
}
int main(void)
{
int error;
error = do_things();
if (sk)
nl_socket_free(sk);
return error;
}
Here's also a sample Makefile (please verify your directories):
KERNEL_HEADERS := /lib/modules/$(shell uname -r)/build
LIBNL_INC := /usr/include/libnl3
LIBNL_LIB := /usr/lib/x86_64-linux-gnu
obj-m += driver.o
CC := gcc
CFLAGS := -I$(KERNEL_HEADERS)
APPFLAGS := -I$(LIBNL_INC)
LDFLAGS := -L$(LIBNL_LIB)
LDLIBS := -lnl-3 -lnl-genl-3
.PHONY: all driver app clean
all: driver app
driver:
$(MAKE) -C $(KERNEL_HEADERS) M=$(shell pwd) modules
app: app.c
$(CC) $(APPFLAGS) $(LDFLAGS) -o app app.c $(LDLIBS)
clean:
$(MAKE) -C $(KERNEL_HEADERS) M=$(shell pwd) clean
rm -f app