Linux kernel 用户空间netlink套接字从内核空间接收空消息
免责声明-我必须承认这是我第一次使用这个内核接口(套接字) 我目前正在设计一个基于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”从内核发送到套接字之前,我的整个路径都是正确的。 我不确定我在这里做错了什么&非常感谢你的帮助 谢谢你,莫蒂克 下面是我的代码示例: 用户空间代码: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
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);而不是: