内核到用户空间的应用程序通信 [英] Kernel to userspace application communication

查看:214
本文介绍了内核到用户空间的应用程序通信的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使内核(Android,内核4.9.59)与用户空间应用程序通信.我找到了使用Netlink套接字的解决方案: https://stackoverflow.com/a/25071310/4190159

I am trying to make Kernel (Android, kernel 4.9.59) communicate with userspace applications. I found a solution using Netlink sockets: https://stackoverflow.com/a/25071310/4190159

该解决方案的第一个问题是该解决方案中使用的struct netlink_skb_parms没有成员名为"pid"的成员,而是有一个名为"portid"的成员,我认为这与pid不同.无论如何,为了编译我的内核端代码/解决方案,我使用了结构netlink_skb_parms的'portid'成员来进行初始化.但是,现在我遇到了另一个错误.

The first issue with the solution is that struct netlink_skb_parms used in the solution does not have a member named 'pid', instead has a member named 'portid', which I believe is not the same as pid. Anyway, to compile my kernel side code/solution I used 'portid' member of struct netlink_skb_parms instead for initialization. However, now I am getting a different error.

我的内核端Netlink套接字代码如下:

My Kernel side Netlink socket code as follows:

#include <linux/sched.h>
//For netlink socket -->
#include <net/sock.h>
//#include <net/netlink.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#include <linux/string.h>

#define MY_GROUP    1 //For netlink socket
struct sock* socket; //For netlink socket
struct sk_buff* socket_buff; //For netlink socket

static void nl_receive_callback (struct sk_buff *skb)
{
    nlmsg_free(skb);
}

static void kernel_send_nl_msg(void)
{
    struct nlmsghdr *nlsk_mh;
    char* msg = "hello from kernel";

    socket = netlink_kernel_create(&init_net, NETLINK_USERSOCK, 1, nl_receive_callback, NULL, THIS_MODULE);

    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 is deprecated
    NETLINK_CB(socket_buff).portid = 0;
    NETLINK_CB(socket_buff).dst_group = MY_GROUP;
    strcpy(nlmsg_data(nlsk_mh), msg);

    nlmsg_multicast(socket, socket_buff, 0, MY_GROUP, GFP_KERNEL);
    pr_info("%s", msg);//Print out the message to kernel

    return;
}

我的用户空间应用程序端代码,用于拦截来自内核的消息,如下所示:

My userspace application side code to intercept the message from the kernel as follows:

#include <sys/socket.h>
#include <linux/netlink.h>

#define MY_GROUP    1

void user_recieve_nl_msg(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);

    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(256));
        memset(nl_msghdr, 0, NLMSG_SPACE(256));

        iov.iov_base = (void*) nl_msghdr;
        iov.iov_len = NLMSG_SPACE(256);

        msghdr.msg_name = (void*) &user_sockaddr;
        msghdr.msg_namelen = sizeof(user_sockaddr);
        msghdr.msg_iov = &iov;
        msghdr.msg_iovlen = 1;

        recvmsg(sock_fd, &msghdr, 0);

        kernel_msg = (char*)NLMSG_DATA(nl_msghdr);
        print("Kernel message: %s\n", kernel_msg); // print to android logs
    }

    close(sock_fd);
}

当我尝试构建android内核时,出现以下错误:

When I am trying to build the android kernel I am receiving the fllowing error:

kernel/sched/custom_code.h:34:65:错误:传递的参数3为 'netlink_kernel_create'使指针从整数开始而无需强制转换 [-Werror]

kernel/sched/custom_code.h:34:65: error: passing argument 3 of 'netlink_kernel_create' makes pointer from integer without a cast [-Werror]

kernel/sched/custom_code.h:34:14:错误:参数过多 函数'netlink_kernel_create'

kernel/sched/custom_code.h:34:14: error: too many arguments to function 'netlink_kernel_create'

注意,用于内核的代码写在custom_code.h中.

Note the code for the Kernel side is written in custom_code.h.

我的问题如下:

  1. 我已经检查了功能'netlink_kernel_create',并且正在发送正确数量的参数,那么为什么出现上述错误?如何解决该错误?

  1. I have checked the function 'netlink_kernel_create' and I am sending the right number of arguments then why is the aformentioned error coming up? How this error could be resolved?

我应该怎么做才能在内核和用户空间应用程序之间建立有效的通信,以便可以在它们之间来回传递消息?

What should I do to establish a valid communication between the kernel and the userspace application so that messages could be passed (to and fro) between them?

推荐答案

1. 让我们检查一下Linux内核中的netlink_kernel_create函数:

1. Let's check netlink_kernel_create function in linux kernel:

static inline struct sock *
netlink_kernel_create(struct net *net, int unit, struct netlink_kernel_cfg *cfg)
{
    return __netlink_kernel_create(net, unit, THIS_MODULE, cfg);
}

从此处 https://elixir .bootlin.com/linux/v4.9.59/source/include/linux/netlink.h#L60 请注意,该函数仅接受3个参数(而不是您的代码中的6个参数)

from here https://elixir.bootlin.com/linux/v4.9.59/source/include/linux/netlink.h#L60 Notice, that this function takes only 3 arguments ( instead of 6 in your code )

此功能已在内核3.6中更改(从6个参数更改为4个) https://elixir.bootlin.com/linux/v3.6/source/include/linux/netlink.h#L185

This function have been changed in kernel 3.6 ( from 6 parameters to 4 ) https://elixir.bootlin.com/linux/v3.6/source/include/linux/netlink.h#L185

然后在内核3.7中重命名为__netlink_kernel_create

And then renamed to __netlink_kernel_create in kernel 3.7

netlink_kernel_create函数接受3个参数 https://elixir.bootlin.com/linux/v3.7/source/include/linux/netlink.h#L48

netlink_kernel_create function from 3.7 accepts 3 arguments https://elixir.bootlin.com/linux/v3.7/source/include/linux/netlink.h#L48

尝试更改此内容

socket = netlink_kernel_create(&init_net, NETLINK_USERSOCK, 1, nl_receive_callback, NULL, THIS_MODULE);

对此

struct netlink_kernel_cfg cfg = {
    .input  = nl_receive_callback,
    .groups = 1,
};
socket = netlink_kernel_create(&init_net, NETLINK_USERSOCK, &cfg);

  1. 现在,您可以在内核=>应用程序"方向上发送数据.

启动应用程序时,它将与user_sockaddr.nl_groups = MY_GROUP; bind(sock_fd, (struct sockaddr*)&user_sockaddr, sizeof(user_sockaddr));绑定套接字.

When you start your application, it will bind socket with user_sockaddr.nl_groups = MY_GROUP; bind(sock_fd, (struct sockaddr*)&user_sockaddr, sizeof(user_sockaddr));.

此后,您可以使用NETLINK_CB(socket_buff).dst_group = MY_GROUP; nlmsg_multicast(socket, socket_buff, 0, MY_GROUP, GFP_KERNEL);从内核将数据发送到应用程序,并且使用recvmsg(sock_fd, &msghdr, 0);

After this you can send data from kernel to application with NETLINK_CB(socket_buff).dst_group = MY_GROUP; nlmsg_multicast(socket, socket_buff, 0, MY_GROUP, GFP_KERNEL); and it will be received by application with recvmsg(sock_fd, &msghdr, 0);

如何调用kernel_send_nl_msg()函数与用户空间进行实际通信?

How can I call kernel_send_nl_msg() function to actually communicate with the userspace?

您可以从内核模块中调用它,然后将其编写,编译并插入到内核中.或者,您可以直接从内核调用它,但是为此,您将需要重建整个内核.

You can call it from kernel module, which you write, compile and insmod into kernel. Or you can call it directly from kernel, but for this you will need to rebuild whole kernel.

如果要向应用程序=>内核"方向发送数据,则需要做相反的事情:将新套接字与内核中的另一个MY_GROUP2绑定,并使用nlmsg_multicast

If you want to send data in direction "application = > kernel", then you need to do things in reverse: bind new socket with another MY_GROUP2 in kernel and send data from application with nlmsg_multicast

这篇关于内核到用户空间的应用程序通信的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆