对于一个项目,我正在尝试从Linux内核空间发送UDP数据包。我目前正在将我的代码“硬编码”到内核中(我很欣赏这不是最好/最好的方式),但我正在尝试进行简单的测试(发送“TEST”)。应该提到的是,我是内核黑客的新手 - 我不是很多原则和技术!

每次我的代码运行时,系统都会挂起,我必须重启 - 没有鼠标/键盘响应,滚动和大写锁定键闪烁在一起 - 我不确定这意味着什么,但我假设它是一个内核恐慌?

对于这个测试代码,repeat_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);
}

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

有帮助吗?

解决方案

您可能会发现使用 netpoll API 用于UDP。请参阅 netconsole ,了解示例它被使用了。您正在使用的API更适合用户空间(您不应该使用段描述符来发送网络数据!)

其他提示

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

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

我不是一个Linux内核开发人员,但是你可以在那里抛出一些printk并在它停止之前观看dmesg吗?或者您是否考虑过与内核调试器连接?

我认为你应该尝试将所有变量放在mymethod()函数之外并使它们变为静态。请记住,内核堆栈的大小限制为8KiB,因此对于大部分/太大的局部变量可能会导致堆栈溢出和系统挂起。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top