对于一个项目,我正在尝试从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);
}
非常感谢任何帮助,谢谢!
答案 0 :(得分:2)
您可能会发现将netpoll API用于UDP更容易。请查看netconsole以获取如何使用它的示例。您正在使用的API更适合用户空间(您不应该使用段描述符来发送网络数据!)
答案 1 :(得分:0)
当您处于文本模式控制台时运行代码(即按Ctrl + Alt + F1转到文本控制台)。这样一来,内核恐慌会打印出堆栈跟踪以及有关错误的任何额外信息。
如果这对您没有帮助,请使用堆栈跟踪更新您的问题。
答案 2 :(得分:0)
我不是一个Linux内核开发人员,但是你可以在那里抛出一些printk并在它停止之前观看dmesg吗?或者您是否考虑过与内核调试器连接?
答案 3 :(得分:0)
我认为你应该尝试将所有变量放在mymethod()函数之外并使它们变为静态。请记住,内核堆栈的大小限制为8KiB,因此对于大部分/太大的局部变量可能会导致堆栈溢出和系统挂起。