Отправка UDP-пакета в ядре Linux
-
06-07-2019 - |
Вопрос
Для проекта я пытаюсь отправлять UDP-пакеты из пространства ядра Linux.В настоящее время я "жестко кодирую" свой код в ядро (что, я ценю, не самый лучший / аккуратный способ), но я пытаюсь заставить простой тест работать (отправляя "TEST").Следует отметить, что я новичок во взломе ядра - я не настолько разбираюсь во многих принципах и техниках!
Каждый раз, когда запускается мой код, система зависает, и мне приходится перезагружаться - мышь / клавиатура не реагирует, а индикаторы клавиш прокрутки и caps lock мигают одновременно - я не уверен, что это значит, но я предполагаю, что это паника ядра?
Код repeat_send не нужен для этого тестового кода, но когда он работает, я хочу отправлять большие сообщения, для которых может потребоваться несколько отправок - я не уверен, что это может быть причиной моих проблем?
Н.Б.Этот код вставляется в neighbour.c из linux-source/net/core / origin, отсюда и использование 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.Взгляните на сетчатая подошва для примера того, как это используется.Используемые вами API больше предназначены для пользовательского пространства (вам никогда не придется играть с дескрипторами сегментов для отправки сетевых данных!).
Другие советы
Запустите свой код, когда вы находитесь в консоли текстового режима (т.е.нажмите Ctrl + Alt + F1, чтобы перейти к текстовой консоли).Таким образом, при панике ядра будет распечатана трассировка стека и любая дополнительная информация о том, что пошло не так.
Если это вам не поможет, обновите свой вопрос с помощью трассировки стека.
Я не большой специалист по разработке ядра Linux, но не могли бы вы добавить туда несколько printk и посмотреть dmesg, прежде чем он отключится?Или вы думали о том, чтобы подключиться к отладчику ядра?
Я думаю, вам следует попытаться поместить все переменные вне функции mymethod() и сделать их статичными.Помните, что размер стека ядра ограничен 8 КБ, поэтому большая часть / слишком большие локальные переменные могут вызвать переполнение стека и зависание системы.