I need your help :/ I've made a module to create an UDP packet, with data, udp header, ip header and ethernet header, in a kernel.
I've look lots of topic, sites and blogs but nothing help me. I didn't success to do what i want :(
Now, i want to send it to the device, or to the wire (loopback).
#include <linux/init.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/ip.h>
#include <net/ip.h>
#include <Create6.h>
void compute_udp_checksum(struct iphdr *pIph, unsigned short *ipPayload) {
register unsigned long sum = 0;
struct udphdr *udphdrp = (struct udphdr*)(ipPayload);
unsigned short udpLen = htons(udphdrp->len);
sum += (pIph->saddr>>16)&0xFFFF;
sum += (pIph->saddr)&0xFFFF;
sum += (pIph->daddr>>16)&0xFFFF;
sum += (pIph->daddr)&0xFFFF;
sum += htons(IPPROTO_UDP);
sum += udphdrp->len;
udphdrp->check = 0;
while (udpLen > 1) {
sum += * ipPayload++;
udpLen -= 2;
}
if(udpLen > 0) {
sum += ((*ipPayload)&htons(0xFF00));
}
while (sum>>16) {
sum = (sum & 0xffff) + (sum >> 16);
}
sum = ~sum;
udphdrp->check = ((unsigned short)sum == 0x0000)?0xFFFF:(unsigned short)sum;
}
void compute_ip_checksum(struct iphdr* iphdrp){
iphdrp->check = 0;
iphdrp->check = compute_checksum((unsigned short*)iphdrp, iphdrp->ihl<<2);
}
static unsigned short compute_checksum(unsigned short *addr, unsigned int count) {
register unsigned long sum = 0;
while (count > 1) {
sum += * addr++;
count -= 2;
}
if(count > 0) {
sum += ((*addr)&htons(0xFF00));
}
while (sum>>16) {
sum = (sum & 0xffff) + (sum >> 16);
}
sum = ~sum;
return ((unsigned short)sum);
}
void aff_skb_info(struct sk_buff *skb){
printk(KERN_INFO "Skb : %x", (unsigned int) skb);
printk(KERN_INFO "Head : %x", (unsigned int) skb->head);
printk(KERN_INFO "Data : %x", (unsigned int) skb->data);
printk(KERN_INFO "Tail : %x", (unsigned int) skb->tail);
printk(KERN_INFO "End : %x", (unsigned int) skb->end);
printk(KERN_INFO "Mac header : %x", (unsigned int) skb->mac_header);
printk(KERN_INFO "Transport header : %x", (unsigned int) skb->transport_header);
printk(KERN_INFO "Network header : %x", (unsigned int) skb->network_header);
}
static int temp_init(void)
{
struct sk_buff *skb = NULL;
struct iphdr *newip = NULL;
struct udphdr *newudp = NULL;
struct ethhdr *neweth = NULL;
u_char *data_for = NULL;
int i=0;
printk(KERN_INFO "Create6 : Registering LKM...\n");
/************************************ ALLOCATION *****************************************/
printk(KERN_INFO " -------------------------------------- ALLOCATION -------------------------------------- \n");
skb = alloc_skb(320,GFP_KERNEL);
aff_skb_info(skb);
/************************************ RESERVE ESPACE HEADER ****************************************/
printk(KERN_INFO " -------------------------------------- RESERVE ESPACE HEADER -------------------------------------- \n");
skb_reserve(skb, 70);
aff_skb_info(skb);
/************************************ DATA ****************************************/
printk(KERN_INFO " -------------------------------------- DATA -------------------------------------- \n");
u_char payload[] = "AAAAAAAAAA";
u32 payload_len = 10;
skb_push(skb, payload_len);
memset(skb->data, 0, payload_len);
memcpy(skb->data, payload, payload_len);
aff_skb_info(skb);
i=1;
for(data_for = skb->data; data_for<skb->tail; data_for++ ){
printk(KERN_INFO "\tPayload %d\t: %.2x à l'adresse : %x", i, *data_for, (unsigned int) data_for);
i++;
}
/************************************ UDP *****************************************/
printk(KERN_INFO " -------------------------------------- UDP -------------------------------------- \n");
skb->transport_header = (void *)skb_push(skb, sizeof(struct udphdr));
memset(skb->data,0,sizeof(struct udphdr));
newudp = udp_hdr(skb);
newudp->source = htons(59046);
newudp->dest = htons(5001);
newudp->len = htons(sizeof(struct udphdr));
newudp->check = 0;
newudp->check = csum_tcpudp_magic(in_aton("169.254.121.80"),in_aton("169.254.121.80"),sizeof(struct udphdr), IPPROTO_UDP,csum_partial(newudp, sizeof(struct udphdr), 0));
aff_skb_info(skb);
printk(KERN_INFO "Source Port : %x à l'adresse %x", newudp->source,&(newudp->source));
printk(KERN_INFO "Dest Port : %x à l'adresse %x", newudp->dest,&(newudp->dest));
printk(KERN_INFO "Len : %x à l'adresse %x", newudp->len,&(newudp->len));
printk(KERN_INFO "Check : %x à l'adresse %x", newudp->check,(&newudp->check));
i=1;
for(data_for = skb->data; data_for<skb->tail; data_for++ ){
printk(KERN_INFO "\tPayload %d\t: %.2x à l'adresse : %x", i, *data_for, (unsigned int) data_for);
i++;
}
/************************************ IP *****************************************/
printk(KERN_INFO " -------------------------------------- IP -------------------------------------- \n");
skb->network_header = (void *)skb_push(skb, sizeof(struct iphdr));
memset(skb->data,0,sizeof(struct iphdr));
newip = iph_hdr(skb);
newip->version = 4;
newip->ihl = 4;
newip->tos = 0;
newip->id = 0;
newip->frag_off = 0;
newip->ttl = 64;
newip->protocol = IPPROTO_UDP;
newip->saddr = in_aton("169.254.121.80");
newip->daddr = in_aton("169.254.121.80");
newip->check = 0;
compute_ip_checksum(newip);
aff_skb_info(skb);
printk(KERN_INFO "\n");
printk(KERN_INFO "Version : %x", newip->version);
printk(KERN_INFO "Ihl : %x", newip->ihl);
printk(KERN_INFO "TOS : %x à l'adresse %x", newip->tos,&(newip->tos));
printk(KERN_INFO "ID : %x à l'adresse %x", newip->id,(&newip->id));
printk(KERN_INFO "Frag Off : %x à l'adresse %x", newip->frag_off,&(newip->frag_off));
printk(KERN_INFO "TTL : %x à l'adresse %x", newip->ttl,&(newip->ttl));
printk(KERN_INFO "Protocol : %x à l'adresse %x", newip->protocol,&(newip->protocol));
printk(KERN_INFO "Source @ : %x à l'adresse %x", newip->saddr,&(newip->saddr));
printk(KERN_INFO "Destination @ : %x à l'adresse %x", newip->daddr,&(newip->daddr));
printk(KERN_INFO "Check IP : %x à l'adresse %x", newip->check,&(newip->check));
i=1;
for(data_for = skb->data; data_for<skb->tail; data_for++ ){
printk(KERN_INFO "\tPayload %d\t: %.2x à l'adresse : %x", i, *data_for, (unsigned int) data_for);
i++;
}
/************************************ ETHERNET *****************************************/
printk(KERN_INFO " -------------------------------------- ETHERNET -------------------------------------- \n");
skb->mac_header = (void *)skb_push(skb, sizeof(struct ethhdr));
memset(skb->data,0,sizeof(struct ethhdr));
neweth = eth_hdr(skb);
neweth->h_dest[0] = 0x04;neweth->h_dest[1] = 0x7d;neweth->h_dest[2] = 0x7b;neweth->h_dest[3] = 0x4d;neweth->h_dest[4] = 0xa8;neweth->h_dest[5] = 0x75;
neweth->h_source[0] = 0x04;neweth->h_source[1] = 0x7d;neweth->h_source[2] = 0x7b;neweth->h_source[3] = 0x4d;neweth->h_source[4] = 0xa8;neweth->h_source[5] = 0x75;
neweth->h_proto = ETH_P_IP;
aff_skb_info(skb);
printk(KERN_INFO "\n");
printk(KERN_INFO "MAC Destination : %x", neweth->h_dest);
printk(KERN_INFO "MAC Source : %x", neweth->h_source);
printk(KERN_INFO "Protocole : %x à l'adresse %x", neweth->h_proto);
i=1;
for(data_for = skb->data; data_for<skb->tail; data_for++ ){
printk(KERN_INFO "\tPayload %d\t: %.2x à l'adresse : %x", i, *data_for, (unsigned int) data_for);
i++;
}
dev_queue_xmit(skb);
kfree_skb(skb);
printk(KERN_INFO "\nCreate7 : LKM loaded.\n");
return 0;
}
static void temp_exit(void)
{
printk(KERN_INFO "Create7 : Unregistering LKM...\n");
printk(KERN_INFO "Create7: Unloaded LKM\n");
}
module_init(temp_init);
module_exit(temp_exit);
Here is my code. I think there is 2 problems.
First, i don't know how to build my net_device structure for skb->dev
The, how to send my packet on my loopback ? I see to used
hard_start_xmit(skb,dev)
or dev_queue_xmit(skb)
but i've kernel panic when i do it.
So, if you know how do to this, thank you very much !!!