简体   繁体   English

如何使用netlink套接字进行内核 - 用户空间通信Android

[英]How to use netlink sockets for kernel - userspace communication Android

I'm trying to write kernel module for android to communicate with userspace Service so my app can display some information about the kernel. 我正在尝试编写用于android的内核模块与用户空间服务进行通信,以便我的应用程序可以显示有关内核的一些信息。 So far I've tried several examples I found on the web and none of them works. 到目前为止,我已经尝试了几个我在网上找到的例子,但没有一个可行。 The idea is for kernel to send updates and service would then pick them up. 我们的想法是让内核发送更新,服务然后将它们接收。 ioctl is not a solution because the communication needs to be event driven, and initiated from kernel. ioctl不是解决方案,因为通信需要由事件驱动,并从内核启动。 C code for both jni and kernel module would be great if anyone knows how to do this. 如果有人知道如何执行此操作,jni和内核模块的C代码将会很棒。

Here's a code snippet that I've used (excluding error checking of return values for conciseness) where the netlink socket communication is driven by the kernel (ie the kernel is the sender, user program is the receiver). 这是我使用的代码片段(不包括对简洁性的返回值的错误检查),其中netlink套接字通信由内核驱动(即内核是发送方,用户程序是接收方)。

Kernel module 内核模块

#include <net/sock.h>
#include <net/netlink.h>
#include <linux/skbuff.h>
#include <string.h>

#define MY_GROUP    1

struct sock* socket;
struct sk_buff* socket_buff;

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

    nlmsg_multicast(socket, socket_buff, 0, MY_GROUP, GFP_KERNEL);                    

    return;                                                                                           
} 

You'd fire this up as a result of your kernel event, eg in response to an ioctl or within your interrupt handling. 你可以通过内核事件来解决这个问题,例如响应ioctl或你的中断处理。

User Program 用户程序

#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);
}

I use nlmsg_multicast() in the kernel rather than nlmsg_unicast() because to do a unicast, the kernel module would need to know the process id of your user process (so you'd need to add some extra implementation there). 我在内核中使用nlmsg_multicast()而不是nlmsg_unicast(),因为要进行单播,内核模块需要知道用户进程的进程ID(所以你需要在那里添加一些额外的实现)。

Hope that helps! 希望有所帮助!

I have successfully used netlink socket to communicate between kernel and user-space in Android. 我已成功使用netlink socket在Android中的内核和用户空间之间进行通信。 To use socket in non-blocking mode use the fcntl and select call. 要在非阻塞模式下使用套接字,请使用fcntl并选择call。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM