2010-07-14 11 views
3

Longue histoire courte, j'essaye de construire un UDP SKB d'os très nus juste pour obtenir quelque chose sur le fil. Le scénario est le suivant:construire un sk_buff pour le périphérique d'évacuation linux kernel

J'ai un chargement de module noyau qui (entre autres choses) remplace l'emplacement de mémoire de la fonction standard udp_sendmsg dans /net/ipv4/udp.c. De là, je voudrais construire un skb au point où je peux simplement le mettre sur le fil. Normalement, udp_sendmsg fait simplement un peu de comptabilité UDP, tapes sur un en-tête UDP et l'envoie vers la couche IP pour le routage, les en-têtes L3/L2, etc. J'apporte une partie de cette fonctionnalité dans la fonction sendmsg. A ce moment, je suis juste allouons un SKB:

skb = alloc_skb(1500, GFP_KERNEL); 
    //skb has 1500 bytes of tail room only 
    skb_reserve(skb, 500); 
    //now has head and tail but no data space 
    data = skb_put(skb, 500); 
    //now we have an skb with 500 head, 500 data sec, 500 tail 

Et puis (après une table de routage seteup) Je suis en train d'ajouter un udp_hdr:

struct udphdr *uh; 
    skb->transport_header = skb_push(skb, sizeof(struct udphdr)); 
    uh = udp_hdr(skb); 
    uh->source = 5555; 
    uh->dest = dport; 
    uh->len = 18; 
    uh->check = 0; 

et un ip_hdr (seulement les bases remplies):

struct iphdr *iph; 
    skb->network_header = skb_push(skb, sizeof(struct iphdr)); 
    iph = ip_hdr(skb); 
    iph->version = 4; 
    iph->ihl = 5; 
    iph->tos = inet->tos; 
    iph->tot_len = htons(skb->len); 
    iph->protocol = IPPROTO_UDP; 
    iph->saddr = saddr; 
    iph->daddr = daddr; 
    skb->dst = dst_clone(&rt->u.dst); 

note: Je suis plus de ce genre de choses de this page mais ils utilisent un noyau plus ancien (pré 2.6.24) où le réseau et les en-têtes de transport étaient des syndicats et appelé nh et h respectifs ly. La nouvelle façon consiste à utiliser skb-> transport_header/skb-> network_header et d'utiliser ces fonctions d'aide mais apparemment je fais quelque chose de mal parce que je reçois un noyau oups quand j'essaie d'invoquer le udp_sendmsg

Note: ceci a fonctionné sans Oops et déversé indésirable au fil quand au lieu de:

skb->transport_header = skb_push(skb, sizeof(struct udphdr)); 

je.

skb_reset_transport_header(skb); 

(et équivalent pour network_header Mais après avoir lu le lien ci-dessus et en regardant la source de la fonction de remise à zéro sous linux /sk_buff.h, il n'a pas vu Je voulais faire ce que je voulais.

Veuillez également noter que toute déclaration d'affectation ci-dessus avec (dans ce contexte) des variables non définies est simplement parce que je n'ai pas inclus la fonction entière. Je réalise que cette question pourrait tomber dans un domaine très spécifique, mais des conseils sur l'utilisation correcte de la nouvelle construction de skb seraient grandement utiles. Mon pote google arrive assez sec.

Le Oops Dépisteur:

[<ffffffff813dbf98>] oops_end+0xb9/0xc1 
[<ffffffff81030e21>] no_context+0x1f6/0x205 
[<ffffffff81030fd3>] __bad_area_nosemaphore+0x1a3/0x1c9 
[<ffffffff8101184e>] ? apic_timer_interrupt+0xe/0x20 
[<ffffffff8103100c>] bad_area_nosemaphore+0x13/0x15 
[<ffffffff813dd30a>] do_page_fault+0x125/0x222 
[<ffffffff813db485>] page_fault+0x25/0x30 
[<ffffffffa010924f>] ? udp_sendmsg_offload+0x1e3/0x250 [testmodule] 
[<ffffffffa010922e>] ? udp_sendmsg_offload+0x1c2/0x250 [testmodule] 
[<ffffffff81390a00>] inet_sendmsg+0x54/0x5d 
[<ffffffff8132f142>] __sock_sendmsg+0x61/0x6c 
[<ffffffff8132f8b9>] sock_sendmsg+0xcc/0xe5 
+0

S'il vous plaît nous montrer les Oops. – ninjalj

+0

poste édité pour refléter le oups –

Répondre

1

skb_push() renvoie un pointeur l'en-tête de transport, mais skb->transport_header est un sk_buff_data_t, qui est censé être un décalage - voir comment skb_transport_header() travaux. Vous devez également convertir les informations d'en-tête en ordre d'octets réseau.

La partie où vous définissez l'en-tête UDP doit être:

struct udphdr *uh; 
skb_push(skb, sizeof(struct udphdr)); 
skb_reset_transport_header(skb); 
uh = udp_hdr(skb); 
uh->source = __constant_htons(5555); 
/* ... */ 

et de même pour l'en-tête IP:

struct iphdr *iph; 
skb_push(skb, sizeof(struct iphdr)); 
skb_reset_network_header(skb); 
iph = ip_hdr(skb); 
iph->version = 4; 
/* ... */ 
+0

Oui, je suis d'accord. Je suis tombé dessus hier en regardant skbuff que l'utilisation du skb-> transport_header dépend de NET_SKBUFF_DATA_USES_OFFSET qui dépend à son tour de __WORDSIZE. Comme je suis sur une plate-forme 64 bits, il semblerait que le préprocesseur utilise effectivement cette méthode. Je vous remercie également d'avoir signalé l'ordre des octets. Après avoir piraté ce bit, j'ai complètement oublié –

+0

PS cela contourne le noyau oups (au moins où cela se passait avant) mais je n'ai toujours pas de chance avec mon objectif. Je suppose que c'est pour un autre poste cependant. –