1

I'm trying to send a message from kernel to user space using generic netlink and libnl, the part of my code which does this is implemented as follow:

int struct my_callback(struct sk_buff *skb, struct genl_info *info)
{
    struct sk_buff *obuff;
    void *msg_head;

    if ((obuff = genlmsg_new(0, GFP_KERNEL)) == NULL) { // I've tried to change the len to NLMSG_GOODSIZE but not worked
        pr_err("Failed allocating message to an reply\n");
        return 0;
    }

    if ((msg_head = genlmsg_put_reply(obuff, info, &lunatik_family, 0, LIST_STATES)) == NULL) {
        pr_err("Failed to put generic netlink header\n");
        return 0;
    }

    //I've tried to put a genlmsg_end(obuff, msg_head); but didn't work as well

    if (genlmsg_reply(obuff, info) < 0) {
        pr_err("Failed to send message to user space\n");
        return 0;
    }
    pr_info("Message sent to user-space\n");
    return 0;
}

P.s: LIST_STATES is a member of enum and have the value of 3

And my user space code is basically:

static int req_handler(struct nl_msg *msg, void *arg)
{
    struct nlmsghdr *nlhdr;
    struct genlmsghdr *genlhdr;
    
    nlhdr = nlmsg_hdr(msg);
    genlhdr = genlmsg_hdr(nlhdr);

    printf("Received a message from kernel: %d\n", genlhdr->cmd);

    return NL_OK;
}


int socket_init(struct nl_sock *sock)
{
    int err = -1;

    if ((sock = nl_socket_alloc()) == NULL)
        return err;

    if ((err = genl_connect(sock)))
        return err;

    if ((err = genl_ctrl_resolve(sock, LUNATIK_FAMILY)) < 0)
        return err;

    // I've tried to use NL_CB_VALID, but when I use it I receive no message at all
    nl_socket_modify_cb(sock, NL_CB_MSG_IN, NL_CB_CUSTOM, req_handler, NULL);
    return 0;
}

My output on dmesg is:

Message sent to user-space

And my output on user space is:

Received a message from kernel: 0

I should receive 3 instead of 0, I noticed that I'm receiving only the ACK message, but not the message that I'm sending, I would like to know why this is happening and what I'm doing wrong.

Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
Matheus
  • 195
  • 1
  • 1
  • 11
  • Kernel version? Did you have a look at this: http://www.infradead.org/~tgr/libnl/doc/core.html#core_send_recv? – lnksz Jul 11 '20 at 21:08
  • My Kernel version is 5.3.0, and I've already read this page – Matheus Jul 11 '20 at 21:10
  • What is the type of the message? `nlhdr->nlmsg_type` – lnksz Jul 11 '20 at 21:12
  • It's `NLMSG_ERROR`, but my `error` field from `struct nlmsgerr` is 0 which means that the message that I'm receiving is just a ACK message.. – Matheus Jul 11 '20 at 21:26
  • Based on [this example](https://cpp.hotexamples.com/examples/-/-/nlmsg_hdr/cpp-nlmsg_hdr-function-examples.html#0x3a095aec7e475ccb1fb119aa474236372f052da9309fd24fb8a9bb9e35a3f504-117,,148,) if you get back `NLMSG_ERROR`, you shouldn't continue with `genl` – lnksz Jul 11 '20 at 21:35
  • Just something else: `socket_init` doesn't return an `int` at the end. – lnksz Jul 11 '20 at 21:37
  • This is not the actual code that I'm using, it's just the important part which handle to the socket and the libnl, but I'll fix it in my question – Matheus Jul 11 '20 at 21:39
  • 1
    https://stackoverflow.com/q/8478231/1216776 – stark Jul 11 '20 at 21:48
  • What triggers `my_callback()`? – Yd Ahhrk Jul 16 '20 at 17:17
  • @YdAhhrk the generic netlink family triggers `my_callback()` – Matheus Jul 17 '20 at 19:30

1 Answers1

0

The result of genl_ctrl_resolve() is twofold:

  • If < 0, it's an error code.
  • If >= 0, it's the family identication number.

You're throwing away your family identication number. Instead of

if ((err = genl_ctrl_resolve(sock, LUNATIK_FAMILY)) < 0)
    return err;

, do

if ((lunatik_family = genl_ctrl_resolve(sock, LUNATIK_FAMILY)) < 0)
    return lunatik_family;

Later, when you're setting up the Netlink Header, make sure to use it:

if (!genlmsg_put(..., ..., ..., lunatik_family, ..., ..., LIST_STATES, ...))
    /* handle error */

And one more thing: nl_socket_modify_cb() also returns an error code. Instead of

nl_socket_modify_cb(sock, NL_CB_MSG_IN, NL_CB_CUSTOM, req_handler, NULL);
return 0;

do

return nl_socket_modify_cb(sock, NL_CB_MSG_IN, NL_CB_CUSTOM, req_handler, NULL);
Yd Ahhrk
  • 1,088
  • 12
  • 24