3

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

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

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

我没有使用 Netpoll API,因为这个问题表明不可能从本地主机发送数据和向本地主机发送数据。“你不能发送给自己”

问题:从内核发送的数据和从我的 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
�&lt;����,<,�,�,�,,,,
                    ,=
-------------------------------------------------------
-------------------------------------------------------
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 * 指针之前。那里的数据已经损坏。

结构 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';

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

4

1 回答 1

2

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

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

由于消息不是立即发送的,因此您传递的 testmsg 地址在堆栈上。如果有后续的函数调用,那么它们将在发送消息之前覆盖消息的内容。然后您有时会看到正确的消息,有时则不会。视工作安排而定。

于 2013-08-21T08:18:14.343 回答