Linux kernel 用户空间netlink套接字从内核空间接收空消息

Linux kernel 用户空间netlink套接字从内核空间接收空消息,linux-kernel,linux-device-driver,netlink,Linux Kernel,Linux Device Driver,Netlink,免责声明-我必须承认这是我第一次使用这个内核接口(套接字) 我目前正在设计一个基于netlink套接字的内核模块 我正在使用Ubuntu14.04和linux内核4 作为初学者,我想确保我可以在两个方向上使用netlink套接字。 我编写了一个应用程序,它可以执行以下操作: 1) 用户通过netlink套接字向内核发送消息 2) 内核在收到消息时–将“ABCD”字符串消息发送到工作队列 3) 当工作队列接收到“ABCD”消息时,它调用一个函数(名为-my_wq_function),该函数通过ne

免责声明-我必须承认这是我第一次使用这个内核接口(套接字)

我目前正在设计一个基于netlink套接字的内核模块

我正在使用Ubuntu14.04和linux内核4

作为初学者,我想确保我可以在两个方向上使用netlink套接字。 我编写了一个应用程序,它可以执行以下操作:

1) 用户通过netlink套接字向内核发送消息

2) 内核在收到消息时–将“ABCD”字符串消息发送到工作队列

3) 当工作队列接收到“ABCD”消息时,它调用一个函数(名为-my_wq_function),该函数通过netlink套接字将消息发送回用户空间

4) 在用户空间中,我使用recvmsg函数(在收到消息之前阻塞),并显示“ABCD”消息

我的问题是recvmsg函数的返回值是20(而不是4),而数据本身(即NLMSG_数据)是空的。 在调试期间,我尝试将消息更改为“ABCD1234”,并获得24字节的返回值,但数据仍然为空

我还验证了在将“ABCD”从内核发送到套接字之前,我的整个路径都是正确的。 我不确定我在这里做错了什么&非常感谢你的帮助

谢谢你,莫蒂克

下面是我的代码示例:

用户空间代码:

printf("netlink receiver thread started...\n");

            nlh_rcv = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
            while(true) //endless loop on netlink socket
            {
            memset(nlh_rcv, 0, NLMSG_SPACE(MAX_PAYLOAD));
            iov_rcv.iov_base = (void *)nlh_rcv;

            iov_rcv.iov_len = nlh_rcv->nlmsg_len;

            msg_rcv.msg_name = (void *)&dest_addr;
            msg_rcv.msg_namelen = sizeof(dest_addr);
            msg_rcv.msg_iov = &iov;
            msg_rcv.msg_iovlen = 1;

            ret=recvmsg(sock_fd, &msg_rcv, 0);  

            printf("errno=%i bytes=%i message from kernel: %s\n",errno, ret, (char*)NLMSG_DATA(nlh_rcv));

            uint8_t mymsg[100];
            memcpy(mymsg, NLMSG_DATA(nlh_rcv), 100);
            printf("message from kernel: %s\n",mymsg);
    }
#include <linux/module.h>       /* Needed by all modules */
#include <linux/kernel.h>       /* Needed for KERN_INFO  */
#include <linux/init.h>         /* Needed for the macros */
#include <net/sock.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#include <linux/workqueue.h>

MODULE_LICENSE("GPL");


#include "rf_Kdriver_main.h"

//------ definitions ------------------------------------------------------------------------------------------------------------
#define NETLINK_USER 31
#define MAX_PAYLOAD 1024 /* maximum payload size*/

struct sock *nl_sk = NULL;

struct nlmsghdr *nlh;
struct nlmsghdr *nlh_out;

struct sk_buff *skb_out;

char buf_to_user[100];

int pid;


//------------------------------------------------------------------------------------------------------------------------------
struct workqueue_struct *my_wq;

typedef struct {
  struct work_struct my_work;
  uint8_t msg_to_pc[128];
  uint8_t msg_len;
} my_work_t;

my_work_t *work, *work2;

//-----------------------------------------------------------------------------------------------------------------------------
static void my_wq_function( struct work_struct *work)
{
            int res;
  my_work_t *my_work = (my_work_t *)work;

  skb_out = nlmsg_new(my_work->msg_len,0);
  if (!skb_out)
  {
            printk("Failed to allocate new skb\n");
            return;
  }
  nlh_out = nlmsg_put(skb_out, 0, 0, NLMSG_DONE,my_work->msg_len, 0);
  NETLINK_CB(skb_out).dst_group = 0;
  memcpy((char*)NLMSG_DATA(nlh_out), my_work->msg_to_pc , my_work->msg_len);

  printk( "dequeue message to pc=%s len=%i\n", (char*)NLMSG_DATA(nlh_out), (int)strlen((char*)NLMSG_DATA(nlh_out)));

  res = nlmsg_unicast(nl_sk, skb_out, pid);

  if (res<0)
            printk("Failed to send message from kernel to user\n");


  kfree( (void *)work );

  return;
}
//-----------------------------------------------------------------------------------------------------------------------------
int send_up_msg_to_workque(uint8_t msg_to_pc[], uint8_t msg_len)
{
  int ret=0;

  work = (my_work_t *)kmalloc(sizeof(my_work_t), GFP_KERNEL);
  if (work) {

    INIT_WORK( (struct work_struct *)work, my_wq_function );

    memcpy(work->msg_to_pc, msg_to_pc, msg_len);
    work->msg_len = msg_len;

    ret = queue_work( my_wq, /*(struct work_struct *)RR*/work );
    printk("kuku ret=%i msg=%s\n",ret,work->msg_to_pc);

  }
  return ret;
}
//------------------------------------------------------------------------------------------------------------------------------
static void netlink_recv_msg(struct sk_buff *skb)
{
    char *msg = "ABCD1234";

    printk(KERN_INFO "Entering: %s\n", __FUNCTION__);

    nlh=(struct nlmsghdr*)skb->data;
    printk(KERN_INFO "Netlink at kernel received msg payload: %s\n",(char*)NLMSG_DATA(nlh));
//rr
    pid = nlh->nlmsg_pid;

    send_up_msg_to_workque((uint8_t*) msg, strlen(msg));
}
//-------------------------------------------------------------------------------------------------------------------------------------

struct netlink_kernel_cfg cfg = {
    .input = netlink_recv_msg,
};

static int __init rf_driver_start(void)
{
            printk(KERN_INFO "Loading RF Driver module1...\n");

    my_wq = create_workqueue("my_queue");
            if (!my_wq)
            {
                        printk("Failed to create work queue\n");
            }

    printk("Entering: %s\n",__FUNCTION__);
    nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);
    if(!nl_sk)
    {
            printk(KERN_ALERT "Error creating socket.\n");
            return -10;
    }


            return 0;
}
//--------------------------------------------------------------------------------------------------------------
static void __exit rf_driver_end(void)
{
            netlink_kernel_release(nl_sk);
            flush_workqueue(my_wq);
            destroy_workqueue(my_wq);
            printk(KERN_INFO "RF Driver exit...\n");
}

module_init(rf_driver_start);
module_exit(rf_driver_end);
内核空间代码:

printf("netlink receiver thread started...\n");

            nlh_rcv = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
            while(true) //endless loop on netlink socket
            {
            memset(nlh_rcv, 0, NLMSG_SPACE(MAX_PAYLOAD));
            iov_rcv.iov_base = (void *)nlh_rcv;

            iov_rcv.iov_len = nlh_rcv->nlmsg_len;

            msg_rcv.msg_name = (void *)&dest_addr;
            msg_rcv.msg_namelen = sizeof(dest_addr);
            msg_rcv.msg_iov = &iov;
            msg_rcv.msg_iovlen = 1;

            ret=recvmsg(sock_fd, &msg_rcv, 0);  

            printf("errno=%i bytes=%i message from kernel: %s\n",errno, ret, (char*)NLMSG_DATA(nlh_rcv));

            uint8_t mymsg[100];
            memcpy(mymsg, NLMSG_DATA(nlh_rcv), 100);
            printf("message from kernel: %s\n",mymsg);
    }
#include <linux/module.h>       /* Needed by all modules */
#include <linux/kernel.h>       /* Needed for KERN_INFO  */
#include <linux/init.h>         /* Needed for the macros */
#include <net/sock.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#include <linux/workqueue.h>

MODULE_LICENSE("GPL");


#include "rf_Kdriver_main.h"

//------ definitions ------------------------------------------------------------------------------------------------------------
#define NETLINK_USER 31
#define MAX_PAYLOAD 1024 /* maximum payload size*/

struct sock *nl_sk = NULL;

struct nlmsghdr *nlh;
struct nlmsghdr *nlh_out;

struct sk_buff *skb_out;

char buf_to_user[100];

int pid;


//------------------------------------------------------------------------------------------------------------------------------
struct workqueue_struct *my_wq;

typedef struct {
  struct work_struct my_work;
  uint8_t msg_to_pc[128];
  uint8_t msg_len;
} my_work_t;

my_work_t *work, *work2;

//-----------------------------------------------------------------------------------------------------------------------------
static void my_wq_function( struct work_struct *work)
{
            int res;
  my_work_t *my_work = (my_work_t *)work;

  skb_out = nlmsg_new(my_work->msg_len,0);
  if (!skb_out)
  {
            printk("Failed to allocate new skb\n");
            return;
  }
  nlh_out = nlmsg_put(skb_out, 0, 0, NLMSG_DONE,my_work->msg_len, 0);
  NETLINK_CB(skb_out).dst_group = 0;
  memcpy((char*)NLMSG_DATA(nlh_out), my_work->msg_to_pc , my_work->msg_len);

  printk( "dequeue message to pc=%s len=%i\n", (char*)NLMSG_DATA(nlh_out), (int)strlen((char*)NLMSG_DATA(nlh_out)));

  res = nlmsg_unicast(nl_sk, skb_out, pid);

  if (res<0)
            printk("Failed to send message from kernel to user\n");


  kfree( (void *)work );

  return;
}
//-----------------------------------------------------------------------------------------------------------------------------
int send_up_msg_to_workque(uint8_t msg_to_pc[], uint8_t msg_len)
{
  int ret=0;

  work = (my_work_t *)kmalloc(sizeof(my_work_t), GFP_KERNEL);
  if (work) {

    INIT_WORK( (struct work_struct *)work, my_wq_function );

    memcpy(work->msg_to_pc, msg_to_pc, msg_len);
    work->msg_len = msg_len;

    ret = queue_work( my_wq, /*(struct work_struct *)RR*/work );
    printk("kuku ret=%i msg=%s\n",ret,work->msg_to_pc);

  }
  return ret;
}
//------------------------------------------------------------------------------------------------------------------------------
static void netlink_recv_msg(struct sk_buff *skb)
{
    char *msg = "ABCD1234";

    printk(KERN_INFO "Entering: %s\n", __FUNCTION__);

    nlh=(struct nlmsghdr*)skb->data;
    printk(KERN_INFO "Netlink at kernel received msg payload: %s\n",(char*)NLMSG_DATA(nlh));
//rr
    pid = nlh->nlmsg_pid;

    send_up_msg_to_workque((uint8_t*) msg, strlen(msg));
}
//-------------------------------------------------------------------------------------------------------------------------------------

struct netlink_kernel_cfg cfg = {
    .input = netlink_recv_msg,
};

static int __init rf_driver_start(void)
{
            printk(KERN_INFO "Loading RF Driver module1...\n");

    my_wq = create_workqueue("my_queue");
            if (!my_wq)
            {
                        printk("Failed to create work queue\n");
            }

    printk("Entering: %s\n",__FUNCTION__);
    nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);
    if(!nl_sk)
    {
            printk(KERN_ALERT "Error creating socket.\n");
            return -10;
    }


            return 0;
}
//--------------------------------------------------------------------------------------------------------------
static void __exit rf_driver_end(void)
{
            netlink_kernel_release(nl_sk);
            flush_workqueue(my_wq);
            destroy_workqueue(my_wq);
            printk(KERN_INFO "RF Driver exit...\n");
}

module_init(rf_driver_start);
module_exit(rf_driver_end);
#包括所有模块所需的/**/
#包含内核信息所需的/**/
#包含宏所需的/**/
#包括
#包括
#包括
#包括
#包括
#包括
#包括
模块许可证(“GPL”);
#包括“rf_kdu River_main.h”
//------定义------------------------------------------------------------------------------------------------------------
#定义NETLINK_用户31
#定义最大负载1024/*最大负载大小*/
结构sock*nl_sk=NULL;
结构nlmsghdr*nlh;
结构nlmsghdr*nlh_out;
结构sk_buff*skb_out;
char buf_to_user[100];
int-pid;
//------------------------------------------------------------------------------------------------------------------------------
struct workqueue_struct*my_wq;
类型定义结构{
构建工作构建我的工作;
uint8_t msg_to_pc[128];
uint8_t msg_len;
}我的工作;
我的工作,工作,工作2;
//-----------------------------------------------------------------------------------------------------------------------------
静态void my_wq_函数(结构工作\u结构*工作)
{
国际关系;
我的工作我的工作=(我的工作)工作;
skb_out=nlmsg_new(我的工作->msg_len,0);
如果(!skb_out)
{
printk(“未能分配新skb\n”);
返回;
}
nlh_out=nlmsg_put(skb_out,0,0,nlmsg_DONE,my_work->msg_len,0);
NETLINK_CB(skb_out).dst_group=0;
memcpy((char*)NLMSG_数据(nlh_out),我的工作->消息发送到pc,我的工作->消息发送;
printk(“将消息排到pc=%s len=%i\n”,(char*)NLMSG_数据(nlh_out),(int)strlen((char*)NLMSG_数据(nlh_out));
res=nlmsg_单播(nl_sk、skb_out、pid);
如果(从消息到消息,消息到消息,消息到消息);
工作->消息长度=消息长度;
ret=队列工作(my_wq,/*(struct work_struct*)RR*/work);
printk(“kuku ret=%i msg=%s\n”,ret,work->msg\u to\u pc);
}
返回ret;
}
//------------------------------------------------------------------------------------------------------------------------------
静态无效netlink_recv_msg(结构sk_buff*skb)
{
char*msg=“ABCD1234”;
printk(内核信息“输入:%s\n”,函数);
nlh=(结构nlmsghdr*)skb->数据;
printk(KERN_INFO“内核处的Netlink接收到消息负载:%s\n”,(char*)NLMSG_数据(nlh));
//rr
pid=nlh->nlmsg\U pid;
发送消息给工作组((uint8)消息,strlen(消息));
}
//-------------------------------------------------------------------------------------------------------------------------------------
结构netlink\u内核\u cfg={
.input=netlink\u recv\u msg,
};
静态整数初始化射频驱动程序启动(无效)
{
printk(KERN_INFO“加载射频驱动模块1…\n”);
my_wq=创建工作队列(“my_队列”);
如果(!my_wq)
{
printk(“创建工作队列失败\n”);
}
printk(“输入:%s\n”,函数);
nl_sk=netlink_kernel_create(&init_net,netlink_USER,&cfg);
如果(!nl_sk)
{
printk(KERN_警报“创建套接字时出错。\n”);
返回-10;
}
返回0;
}
//--------------------------------------------------------------------------------------------------------------
静态无效\uuu退出rf\u驱动器\u结束(无效)
{
netlink内核发布(nl sk);
刷新工作队列(my_wq);
销毁工作队列(my_wq);
printk(内核信息“RF驱动程序退出…\n”);
}
模块初始化(射频驱动器启动);
模块出口(射频驱动器端);
更新

我将用户空间功能更改为:

char buf[100];
ret=recv(sock_fd, buf, 100, 0);
而不是:

ret=recvmsg(sock_fd, &msg_rcv, 0);
而且它是有效的

有人知道这种奇怪的行为吗

谢谢。

更新

我将用户空间功能更改为:

char buf[100];
ret=recv(sock_fd, buf, 100, 0);
而不是:

ret=recvmsg(sock_fd, &msg_rcv, 0);
而且它是有效的

有人知道这种奇怪的行为吗


谢谢。

请粘贴完整的用户空间代码。 我猜
'len'
int这个代码就是问题所在:

    memset(nlh_rcv, 0, NLMSG_SPACE(MAX_PAYLOAD));

    iov_rcv.iov_len = nlh_rcv->nlmsg_len;   << check to what value is it getting initialized.
memset(nlh_rcv,0,NLMSG_空间(最大有效载荷));

iov_rcv.iov_len=nlh_rcv->nlmsg_len 你能粘贴完整的用户空间代码吗。 我猜
'len'
int这个代码就是问题所在:

    memset(nlh_rcv, 0, NLMSG_SPACE(MAX_PAYLOAD));

    iov_rcv.iov_len = nlh_rcv->nlmsg_len;   << check to what value is it getting initialized.
memset(nlh_rcv,0,NLMSG_空间(最大有效载荷));

iov_rcv.iov_len=nlh_rcv->nlmsg_len;我在用户空间使用了函数:char buf[100];ret=recv(sock_fd,buf,100,0);而不是:ret=recvmsg(sock\u fd和msg\u rcv,0);而且它是有效的。。。有人知道这种奇怪的行为吗?我在用户空间使用了函数:char buf[100];ret=recv(sock_fd,buf,100,0);而不是: