gpt4 book ai didi

c - 从 Linux 内核向 LOOPBACK 发送小的 UDP 数据包

转载 作者:行者123 更新时间:2023-12-04 09:47:30 27 4
gpt4 key购买 nike

情况:我的代码基本上被黑进了 Linux 内核的驱动程序中。我想在用户空间中的应用程序将值得注意的原始事件发送到主系统之前通知它们。

解决步骤:我在这里找到了一个从内核空间发送 UDP 数据包的好例子:http://kernelnewbies.org/Simple_UDP_Server .他们使用 INADDR_LOOPBACK 作为目标地址,这正是我想要的。

因为这是中断上下文,所以我决定使用工作队列来发送数据包(我遇到了 BUG:在没有它的情况下进行原子调度)。所以我发送的代码是基于包裹在工作队列结构中的 kernelnewbies 代码,在主进程上用 INIT_WORK 和 schedule_work 触发。我没有声明自己的工作队列。

我没有将 Netpoll API 用作 this Question建议无法从本地主机发送数据或向本地主机发送数据。 “你不能发送给自己”

问题:从内核发送的数据和从我的 UDP 接收器接收的数据很少匹配。我不知道为什么会这样。

用于测试的虚拟数据代码,包括工作队列结构的定义:

static struct socket *sock_send;
static struct sockaddr_in addr_send;

static struct ksocket_workmessage {
unsigned char *buf;
int len;
struct work_struct workmessage;
} workmsg;


unsigned char testmsg[] = {'T', 'e', 's', 't', 'i', 'n', 'g', 'm', 's', 'g', '\0'};
workmsg.buf = testmsg;
workmsg.len = 11;
INIT_WORK(&workmsg.workmessage, handle_workmessage);
schedule_work(&workmsg.workmessage);

发送实际数据包就像 kernelnewbies 示例中的“int ksocket_send”。唯一的区别是我的 send_socket 是静态的,我必须从工作队列中使用 container_of 获取 buf 和 len。我在一个完全静态的环境中工作。我的 handle_workmessage 方法也是静态的:

static void handle_workmessage(struct work_struct *work)
{
struct msghdr msg;
struct iovec iov;
mm_segment_t oldfs;
int size = 0;

struct ksocket_workmessage *workmsg = container_of(work, struct ksocket_workmessage, workmessage);


if (sock_send->sk==NULL)
return;

iov.iov_base = workmsg->buf;
iov.iov_len = workmsg->len;

msg.msg_flags = 0;
msg.msg_name = &addr_send;
msg.msg_namelen = sizeof(struct sockaddr_in);
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;

oldfs = get_fs();
set_fs(KERNEL_DS);
size = sock_sendmsg(sock_send,&msg,workmsg->len);
set_fs(oldfs);
}

接收端是这样的:

int main(int argc, char**argv)
{
int sockfd,n;
struct sockaddr_in servaddr;
socklen_t len;
unsigned char mesg[1000];

sockfd=socket(AF_INET,SOCK_DGRAM,0);

bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(REC_PORT);
bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));

for (;;)
{
n = recv(sockfd,mesg,1000,0);
printf("-------------------------------------------------------\n");
mesg[n] = 0;
printf("Received the following: %d bytes\n", n);
printf("%s",mesg);
printf("%c",mesg[0]);
printf(",%c",mesg[1]);
printf(",%c",mesg[2]);
printf(",%c",mesg[3]);
printf(",%c",mesg[4]);
printf(",%c",mesg[5]);
printf(",%c",mesg[6]);
printf(",%c",mesg[7]);
printf(",%c",mesg[8]);
printf(",%c\n",mesg[9]);
//printf("%c\n",mesg[0]);
printf("-------------------------------------------------------\n");
memset(mesg, 0, sizeof(mesg));
}
}

输出看起来已损坏,尽管我总是出于测试目的发送完全相同的消息:

-------------------------------------------------------
Received the following: 11 bytes
�}|�ingmsg�,},|,�,i,n,g,m,s,g
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
����d����,�,�,�,d,�,�,�,,
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
�}|�ingmsg�,},|,�,i,n,g,m,s,g
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
,�,�,�,�,2,k,�,�,�
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
�<����,<,�,�,�,,,,
,=
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
�}|�ingmsg�,},|,�,i,n,g,m,s,g
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
�}|�ingmsg�,},|,�,i,n,g,m,s,g
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes


,,%,�,,,,,,
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
TestingmsgT,e,s,t,i,n,g,m,s,g
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
�}|�ingmsg�,},|,�,i,n,g,m,s,g
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
����Vk��1k ,�,�,�,�,V,k,�,�,1
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
TestingmsgT,e,s,t,i,n,g,m,s,g
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
,,,,,�,,�,,
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
,,
,�,,,,,�,<
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
�}|�ingmsg�,},|,�,i,n,g,m,s,g
-------------------------------------------------------

这可能是什么原因?由于它有时会与预期输出“TestingmsgT,e,s,t,i,n,g,m,s,g”一起工作,因此它不应该是技术限制。数据包碎片也不应该发生,因为我只发送 11 个字节。也没有丢包。每次我发送数据包时,它也会被接收。

更新:它有效..但我不知道为什么首先,感谢 alk 的评论,我忘记了显而易见的事情。在发送数据之前记录。我在调用 schedule_work 之前确实登录了。现在我直接登录我的发送方法 workmsg->buf,然后甚至存储到来自 iov 的 void * 指针。那里的数据已经损坏。

struct ksocket_workmessage 有一个 char *,我的数据是 char [] 并被分配给结构的指针。

我现在所做的是更改我的 struct ksocket_workmessage 中的数据类型:

struct ksocket_workmessage {
unsigned char buf[11];
int len;
struct work_struct workmessage;
} workmsg;

因为我没有指针了,所以我无法创建我的 unsigned char testmsg[],所以我直接给 buf 赋值:

workmsg.buf[0] = 'T';
workmsg.buf[1] = 'e';
workmsg.buf[2] = 's';
workmsg.buf[3] = 't';
workmsg.buf[4] = 'i';
workmsg.buf[5] = 'n';
workmsg.buf[6] = 'g';
workmsg.buf[7] = 'm';
workmsg.buf[8] = 's';
workmsg.buf[9] = 'g';
workmsg.buf[10] = '\0';

如果有人能告诉我我最初的方法在哪里失败,我会很乐意接受它作为正确答案。

最佳答案

因为它有时有效,有时无效,所以我认为问题在于您正在查看已释放 () 的内存。因此,内容有时是正确的,有时是错误的。由于您的本地缓冲区很好,因此在将其复制到本地内存之前,这必须在内核中发生。

unsigned char testmsg[] 确实声明为局部变量吗?

由于消息不会立即发送,因此您传递的 testmsg 地址位于堆栈中。如果有后续的功能调用,那么它们将在发送消息之前覆盖消息的内容。然后您有时会看到正确的消息,有时却看不到。取决于工作的安排。

关于c - 从 Linux 内核向 LOOPBACK 发送小的 UDP 数据包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18339174/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com