Invio del pacchetto UDP nel kernel Linux
-
06-07-2019 - |
Domanda
Per un progetto, sto cercando di inviare pacchetti UDP dallo spazio kernel Linux. Attualmente sto "codificando" il mio codice nel kernel (che apprezzo non è il modo migliore / più accurato) ma sto cercando di far funzionare un semplice test (invio di "TEST"). Dovrebbe essere menzionato che sono un principiante dell'hacking del kernel - non sono così informato su molti principi e tecniche!
Ogni volta che il mio codice viene eseguito il sistema si blocca e devo riavviare - nessuna risposta da mouse / tastiera e le spie dei tasti di scorrimento e blocco maiuscole lampeggiano insieme - Non sono sicuro di cosa significhi, ma suppongo sia un panico del kernel?
Il codice repeat_send non è necessario per questo codice di prova, ma quando funziona voglio inviare messaggi di grandi dimensioni che potrebbero richiedere più "invii - non sono sicuro che se potrebbe essere una causa dei miei problemi?
NB. Questo codice viene inserito in neighbour.c di linux-source / net / core / origin, quindi l'uso di NEIGH_PRINTK1, è solo un macro wrapper attorno a printk.
Sto davvero sbattendo la testa contro un muro di mattoni qui, non riesco a individuare nulla di ovvio, qualcuno può indicarmi la giusta direzione (o individuare quell'errore accecantemente ovvio!)?
Ecco quello che ho finora:
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);
}
Qualsiasi aiuto sarebbe molto apprezzato, grazie!
Soluzione
Potresti trovare più facile usare API netpoll per UDP. Dai un'occhiata a netconsole per un esempio di come è usato. Le API che stai utilizzando sono più destinate allo spazio utenti (non devi mai giocare con i descrittori di segmenti per inviare dati di rete!)
Altri suggerimenti
Esegui il codice quando sei in una console in modalità testo (ovvero premi Ctrl + Alt + F1 per accedere alla console di testo). In questo modo un panico del kernel stamperà la traccia dello stack e qualsiasi ulteriore informazione su cosa è andato storto.
Se ciò non ti aiuta, aggiorna la tua domanda con la traccia dello stack.
Non sono uno sviluppatore del kernel Linux, ma puoi buttarci dentro alcuni printk e guardare dmesg prima che vada giù? O hai pensato di collegarti con un debugger del kernel?
Penso che dovresti provare a mettere tutte le variabili fuori dalla funzione mymethod () e renderle statiche. Ricorda che le dimensioni dello stack del kernel sono limitate a 8 KiB, quindi a gran parte delle variabili locali troppo grandi possono causare overflow dello stack e blocco del sistema.