views:

584

answers:

2

Hi, I'm writing a Linux driver using netlink to communicate between user space and kernel space. But I can't find some useful materials, because the netlink has changed from Linux kernel >=2.6.24. Who can give me some suggestions about how to create a netlink socket. Thanks in advance!

A: 

I have been away of kernel programming from some time now. So I can't give you a direct example on what changes have been introduced. I can tell you how I got to understand the netlink functions and how to use them, reading code. Especially code from NetworkManager or the wireless extensions (iwlib), since that was my area of focus 2 years ago. Those OSS projects always are on top on changes on the kernel and their code is not difficult to understand.

rsarro
+1  A: 

The code below demonstrates the basics of sending data from a user space application to a kernel module using netlink. This code works on Linux 2.6.28.9 with the git version (ef8ba32) of libnl. For more details, check out the libnl documentation and the code for iw which extensively uses netlink.

Kernel

#if defined(CONFIG_NET)
static struct sock *my_nl_sock;
#endif

DEFINE_MUTEX(my_mutex);

static int
my_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
    int type;
    char *data;

    type = nlh->nlmsg_type;
    if (type != MY_MSG_TYPE) {
        printk("%s: expect %#x got %#x\n", __func__, MY_MSG_TYPE, type);
        return -EINVAL;
    }

    data = NLMSG_DATA(nlh);
    printk("%s: %02x %02x %02x %02x %02x %02x %02x %02x\n", __func__,
            data[0], data[1], data[2], data[3],
      data[4], data[5], data[6], data[7]);
    return 0;
}

static void
my_nl_rcv_msg(struct sk_buff *skb)
{
    mutex_lock(&my_mutex);
    netlink_rcv_skb(skb, &my_rcv_msg);
    mutex_unlock(&my_mutex);
}

static struct notifier_block module_load_nb = {
    .notifier_call = my_load_notify,
};

static int
my_init(void)
{
    my_nl_sock = netlink_kernel_create(&init_net, NETLINK_USERSOCK, 0,
      my_nl_rcv_msg, NULL, THIS_MODULE);
    if (!my_nl_sock) {
     printk(KERN_ERR "%s: receive handler registration failed\n", __func__);
     return -ENOMEM;
    }

    return 0;
}

static void
my_exit(void)
{
    if (my_nl_sock) {
     netlink_kernel_release(my_nl_sock);
    }
}

module_init(my_init);
module_exit(my_exit);

User Space

#include <stdio.h>
#include <stdlib.h>

#include <netlink/netlink.h>

#define MY_MSG_TYPE (0x10 + 2)  // + 2 is arbitrary but is the same for kern + user
int
main(int argc, char *argv[])
{
    struct nl_sock *nls;
    char msg[] = { 0xde, 0xad, 0xbe, 0xef, 0x90, 0x0d, 0xbe, 0xef };
    int ret;

    nls = nl_socket_alloc();
    if (!nls) {
        printf("bad nl_socket_alloc\n");
        return EXIT_FAILURE;
    }

    ret = nl_connect(nls, NETLINK_USERSOCK);
    if (ret < 0) {
        nl_perror(ret, "nl_connect");
        nl_socket_free(nls);
        return EXIT_FAILURE;
    }

    ret = nl_send_simple(nls, MY_MSG_TYPE, 0, msg, sizeof(msg));
    if (ret < 0) {
        nl_perror(ret, "nl_send_simple");
        nl_close(nls);
        nl_socket_free(nls);
        return EXIT_FAILURE;
    } else {
        printf("sent %d bytes\n", ret);
    }

    nl_close(nls);
    nl_socket_free(nls);

    return EXIT_SUCCESS;
}
ctuffli