I wrote a module to create dummy ethernet device, the intention is to add it to a bridge and transmit modified packets. I get ethernet device created but its xmit function is not called when the bridge receives a packet.
I feel I have missed some information to register netdevice.
To add to bridge I did the following: brctl addbr br0 brctl addif bro eth0 brctl addif br0 firsteth0 ifconfig etho 0.0.0.0 ifconfig bro 172.16.2.100 up
When I try to add IP address to firsteth0, I get a kernel panic!! Can we give IP to dummy ethernet device?
Please help, I am given little time to complete this :( I am attaching the code for the dummy ethernet device.
-Ravi
#ifndef __KERNEL__ # define __KERNEL__ #endif #ifndef MODULE # define MODULE #endif #define DEVNAME "firsteth" #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/slab.h> #include <linux/netdevice.h> #include <linux/if_ether.h> #include <linux/rtnetlink.h> #include <linux/if_arp.h> /* netfilters related */ #include <linux/netfilter.h> #include <linux/netfilter_ipv4.h> #include <linux/in.h> #include <linux/udp.h> #include <net/ip.h> int test_open(struct inode *,struct file *); int test_release(struct inode *,struct file*); struct test_struct{ struct net_device *dev; char name[IFNAMSIZ]; }; struct file_operations test_fop={ llseek: NULL, read: NULL, write: NULL, ioctl: NULL, open: test_open, release: test_release, }; struct test_struct pTestStruct; static int testdev_xmit(struct sk_buff *skb, struct net_device *dev) { struct iphdr *oldiph; unsigned char tos=0; unsigned short df =0; unsigned char ttl; printk(KERN_INFO " In xmit function\n"); oldiph = (skb->protocol==htons(ETH_P_IP)) ? (struct iphdr*)(skb->data+ETH_HLEN) : NULL; tos = oldiph->tos; df = oldiph->frag_off; ttl = oldiph->ttl; printk(KERN_INFO"src IP: %x dst IP: %x , protocol %d \n",ntohl(oldiph->saddr), ntohl(oldiph->daddr),oldiph->protocol); return 0; } int test_open(struct inode *inode, struct file *filep) { MOD_INC_USE_COUNT; return 0; } int test_release(struct inode *inode, struct file *filep) { MOD_DEC_USE_COUNT; return 0; } int testdev_open(struct net_device *dev) { MOD_INC_USE_COUNT; return 0; } int testdev_close(struct net_device *dev) { unregister_netdev(dev); MOD_DEC_USE_COUNT; return 0; } //t test_ioctl(struct inode *inode, static int test_init_dev(struct net_device *dev) { struct test_struct *c; printk(KERN_INFO "in test_init_dev\n"); c = (struct test_struct *)dev->priv; if(!c) return -ENODEV; memset(c,0,sizeof(struct test_struct)); c->dev = dev; // ether_setup(dev); dev->open = testdev_open; dev->stop = testdev_close; dev->hard_start_xmit = testdev_xmit; dev->mtu = ETH_DATA_LEN - sizeof(struct udphdr) - sizeof(struct iphdr) ; dev_init_buffers(dev); printk(KERN_INFO "completed test_init_dev\n"); return 0; } int init_module(void) { int result,i; struct net_device *tempDev; struct test_struct *temp_struct; char devname[25]; // Remove the hardcode for(i=0;i<99;i++) { sprintf(devname,"firseth%d",i); if(__dev_get_by_name(devname) == NULL) break; } if(i==100) return -ENFILE; printk(KERN_INFO "********MACOUDP TUNNEL******\n"); temp_struct = (struct test_struct *)kmalloc(sizeof(struct test_struct),GFP_KERNEL); if(!temp_struct) { printk(KERN_ERR "error in allocating memory\n"); return -ENOMEM; } result = register_chrdev(244,"testdrv",&test_fop); if( result != 0 ){ printk(KERN_WARNING "test: cant get major\n"); return result; } i=0; memset(temp_struct,0,sizeof(struct test_struct)); //sprintf(temp_struct->name, DEVNAME "%d",i); tempDev = (struct net_device *)kmalloc(sizeof(struct net_device),GFP_KERNEL); if( !tempDev) { printk(KERN_ERR "kmalloc faied\n"); return -ENOMEM; } memset(tempDev,0,sizeof(struct net_device)); temp_struct->dev = tempDev; temp_struct->dev->priv = &pTestStruct; temp_struct->dev->next = NULL; temp_struct->dev->base_addr=0; temp_struct->dev->init = test_init_dev; temp_struct->dev->dev_addr[0]=0xFC; temp_struct->dev->dev_addr[1]=0xFC; temp_struct->dev->dev_addr[2]=0xA; temp_struct->dev->dev_addr[3]=0xB; temp_struct->dev->dev_addr[4]=0xC; temp_struct->dev->addr_len = ETH_ALEN; i = dev_alloc_name(temp_struct->dev,"firsteth%d"); if(i < 0 ) { printk(KERN_ERR "cant allocate device\n"); return -ENODEV; } ether_setup(temp_struct->dev); rtnl_lock(); printk(KERN_INFO "Before calling register_netdevice\n"); i = register_netdevice((temp_struct->dev)); rtnl_unlock(); memcpy(&pTestStruct,temp_struct,sizeof(struct test_struct)); if( i < 0 ){ printk(KERN_ERR "register netdevice failed\n"); return -1; } return 0; } void cleanup_module(void) { rtnl_lock(); unregister_netdevice(pTestStruct.dev); rtnl_unlock(); unregister_chrdev(244,"testdrv"); }