2009-11-29 35 views
0

对于一个项目,我试图从Linux内核空间发送UDP数据包。我目前正在将我的代码“硬编码”到内核中(我不理解它是最好的/最新的方式),但我试图让一个简单的测试工作(发送“TEST”)。应该指出,我是内核黑客的新手 - 我不是那种在许多原理和技术上找到的东西!在Linux内核中发送UDP数据包

每当我的代码运行系统挂起,我必须重新启动 - 没有鼠标/键盘响应和滚动和大写锁定键灯闪烁在一起 - 我不知道这是什么意思,但我假设它是内核恐慌?

repeat_send代码对于此测试代码是不必要的,但是当它工作时,我想发送可能需要多个'send'的大消息 - 我不确定如果可能是我的问题的原因?

N.B.这段代码被插入到linux-source/net/core/origin的neighbour.c中,因此使用了NEIGH_PRINTK1,它只是一个宏包装printk。

我真的把我的头撞在这里的砖墙上,我找不到任何明显的东西,任何人都可以指向正确的方向(或者发现那个盲目的明显错误!)?

这是我到目前为止有:

void mymethod() 
{ 
    struct socket sock; 
    struct sockaddr_in addr_in; 
    int ret_val; 
    unsigned short port = htons(2048); 
    unsigned int host = in_aton("192.168.1.254"); 
    unsigned int length = 5; 
    char *buf = "TEST\0"; 
    struct msghdr msg; 
    struct iovec iov; 
    int len = 0, written = 0, left = length; 
    mm_segment_t oldmm; 

    NEIGH_PRINTK1("forwarding sk_buff at: %p.\n", skb); 

    if ((ret_val = sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock)) < 0) { 
     NEIGH_PRINTK1("Error during creation of socket; terminating. code: %d\n", ret_val); 
     return; 
    } 

    memset(&addr_in, 0, sizeof(struct sockaddr_in)); 
    addr_in.sin_family=AF_INET; 
    addr_in.sin_port = port; 
    addr_in.sin_addr.s_addr = host; 

    if((ret_val = sock.ops->bind(&sock, (struct sockaddr *)&addr_in, sizeof(struct sockaddr_in))) < 0) { 
    NEIGH_PRINTK1("Error trying to bind socket. code: %d\n", ret_val); 
    goto close; 
    } 

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

repeat_send: 
    msg.msg_iov->iov_len = left; 
    msg.msg_iov->iov_base = (char *)buf + written; 

    oldmm = get_fs(); 
    set_fs(KERNEL_DS); 
    len = sock_sendmsg(&sock, &msg, left); 
    set_fs(oldmm); 

    if (len == -ERESTARTSYS) 
     goto repeat_send; 
    if (len > 0) { 
     written += len; 
     left -= len; 
     if (left) 
      goto repeat_send; 
    } 

close: 
    sock_release(&sock); 
} 

任何帮助将非常感激,谢谢!

+0

在LKM中使用类似的代码进行试验后,我能够确定问题是由于试图将我的套接字绑定到远程ip造成的!我应该一直使用连接。 – owst 2009-11-30 01:58:10

回答

2

您可能会发现使用UDP的netpoll API更容易。以netconsole为例说明如何使用它。您正在使用的API更适合用户空间(您不应该使用段描述符来发送网络数据!)

+0

从粗略的一瞥中看起来很有希望。谢谢,我会在早上正确地检查它。 – owst 2009-11-29 03:00:33

+0

netpoll API肯定看起来像我需要的,谢谢 – owst 2009-11-29 11:32:53

0

当您处于文本模式控制台(即按Ctrl + Alt + F1转到文本控制台)时运行您的代码。这样内核恐慌会打印出堆栈跟踪以及任何有关出错的额外信息。

如果这对您没有帮助,请使用堆栈跟踪更新您的问题。

+0

好的提示,我当然得到了堆栈跟踪,但它很快滚动出视图(我只能看到最后~25行)。任何方式存储/管道输出在某个方便的地方? – owst 2009-11-29 02:58:53

+1

您可以使用串行控制台,net​​console或可能的kexec崩溃转储。 – bdonlan 2009-11-29 03:02:41

0

我不是一个Linux内核开发者,但是你可以在那里扔一些printk的东西,然后在它关闭之前看dmesg吗?或者你有没有想过使用内核调试器?

0

我认为您应该尝试将mymethod()函数之外的所有变量都设置为静态。请记住,内核堆栈的大小是有限的做8KiB,所以大部分/太大的局部变量可能会导致堆栈溢出和系统挂断。