将小型UDP数据包从Linux内核发送到LOOPBACK

情况:我的代码基本上被黑客入侵了Linux内核的驱动程序。 我想在用户空间中通知一个关于值得注意的原始事件的应用程序,然后才能将它们发送到主系统。

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

由于这是中断上下文,我决定使用工作队列来发送数据包(我得到了BUG:在没有它的情况下进行primefaces调度)。 因此,我的发送代码基于kernelnewbies代码,该代码包含在主进程中使用INIT_WORK和schedule_work触发的工作队列结构中。 我没有宣布自己的工作队列。

我没有使用Netpoll API,因为此问题表明无法从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-> buf中登录,甚至在存储到iov的void *指针之前。 那里的数据已经被破坏了。

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

我现在做的是更改我的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'; 

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

因为它有时会起作用,有时候我不会建议问题是你正在查看已经免费的内存()d。 因此,内容有时是正确的,有时它们会被破坏。 由于本地缓冲区很好,因此必须在内核中将其复制到本地内存之前。

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

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