情况:我的代码基本上被黑客入侵了Linux内核的驱动程序。我想在用户空间中通知一个关于值得注意的原始事件的应用程序,然后才能将它们发送到主系统。
解决方案的步骤:我在这里找到了一个从内核空间发送UDP数据包的好例子:http://kernelnewbies.org/Simple_UDP_Server。他们使用INADDR_LOOPBACK作为目标地址,这正是我想要的。
由于这是中断上下文,我决定使用工作队列来发送数据包(我得到了BUG:在没有它的情况下进行原子调度)。因此,我的发送代码基于kernelnewbies代码,该代码包含在主进程中使用INIT_WORK和schedule_work触发的工作队列结构中。我没有宣布自己的工作队列。
我没有使用Netpoll API,因为this Question表示无法从localhost发送数据。 “你不能发给自己”
问题: 从内核发送并从我的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是静态的,我必须从工作队列中获取buf和len与container_of。我在一个完全静态的环境中工作。我的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之前做了日志。现在我直接在我的send方法workmsg-&gt; 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';
如果有人能告诉我我最初的方法失败了,我很乐意接受它作为正确答案。
答案 0 :(得分:2)
因为它有时会起作用,有时候我不会建议问题是你正在寻找已经免费的内存()d。因此,内容有时是正确的,有时它们会被破坏。由于本地缓冲区很好,因此必须在内核中将其复制到本地内存之前。
确实unsigned char testmsg[]
被声明为局部变量?
由于消息未立即发送,因此您传递的testmsg地址位于堆栈中。如果存在后续的功能调用,则它们将在发送之前重写消息的内容。然后,您有时会看到正确的信息,有时则看不到。取决于工作的安排。