[ its urgent ]
hi..
i am working on kernel 2.4.7-10 .. i am trying to write code for making pseudo linux network device driver for two virtual interfaces using orilley device driver book and source code.. if any body has written code for tht then plzz send it to me or if any body some useful link then plzz forward to me .....or
tell me where i am wrong in my code ....my system goes to hang up when i issue a ping command...
anil
#define __KERNEL__
#define MODULE
#include<linux/module.h>
#include<linux/netdevice.h> /* struct net_device & other headers*/
#define MODULE
#include<linux/module.h>
#include<linux/netdevice.h> /* struct net_device & other headers*/
#include<linux/config.h>
#include<linux/sched.h>
#include<linux/kernel.h> /* printk() */
#include<linux/malloc.h> /* kmalloc() */
#include<linux/errno.h> /* error codes */
#include<linux/types.h> /* size_t */
#include<linux/interrupt.h> /* mark_bh */
#include<linux/in.h>
#include<linux/etherdevice.h> /* eth_type_trans */
#include<linux/ip.h> /* struct iphdr */
#include<linux/tcp.h> /* struct tcphdr */
#include<linux/skbuff.h> /* struct sk_buff */
#include<linux/kernel.h> /* printk() */
#include<linux/malloc.h> /* kmalloc() */
#include<linux/errno.h> /* error codes */
#include<linux/types.h> /* size_t */
#include<linux/interrupt.h> /* mark_bh */
#include<linux/in.h>
#include<linux/etherdevice.h> /* eth_type_trans */
#include<linux/ip.h> /* struct iphdr */
#include<linux/tcp.h> /* struct tcphdr */
#include<linux/skbuff.h> /* struct sk_buff */
#define SNULL_RX_INTR 0x0001
#define SNULL_TX_INTR 0x0002
#define SNULL_TX_INTR 0x0002
/* CHECKSUM macro as defined in sk_buff.h
#define CHECKSUM_NONE 0
#define CHECKSUM_HW 1
#define CHECKSUM_UNNECESSARY 2
#define CHECKSUM_HW 1
#define CHECKSUM_UNNECESSARY 2
*/
extern struct net_device snull_devs[ ];
/* struct used for statical info of any interface by inconfig command */
struct snull_priv {
struct net_device_stats stats;
int status;
int rx_packetlen;
u8 *rx_packetdata;
int tx_packetlen;
u8 *tx_packetdata;
struct sk_buff *skb;
spinlock_t lock;
};
static int lockup = 0;
MODULE_PARM(lockup,"i");
MODULE_PARM(lockup,"i");
#define SNULL_TIMEOUT 5
/* in jiffies*/
#ifdef HAVE_TX_TIMEOUT
static int timeout = SNULL_TIMEOUT;
MODULE_PARM(timeout,"i");
#endif
static int eth=0;
MODULE_PARM(eth,"i");
int snull_eth;
/* in jiffies*/
#ifdef HAVE_TX_TIMEOUT
static int timeout = SNULL_TIMEOUT;
MODULE_PARM(timeout,"i");
#endif
static int eth=0;
MODULE_PARM(eth,"i");
int snull_eth;
int snull_open(struct net_device *dev);
void snull_interrupt(int irq,void *dev_id,struct pt_regs *regs);
void snull_rx(struct net_device *dev,int len,unsigned char *buf);
int snull_tx(struct sk_buff *skb,struct net_device *dev);
void snull_hw_tx(char *buf, int len, struct net_device *dev);
void snull_tx_timeout(struct net_device *dev);
int snull_rebuild_header(struct sk_buff *skb);
int snull_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, void *daddr, void *saddr,
unsigned int len);
struct net_device_stats *snull_stats(struct net_device *dev);
int snull_release(struct net_device *dev);
int snull_init(struct net_device *dev);
int snull_config(struct net_device *dev, struct ifmap *map);
int snull_ioctl(struct net_device *dev,struct ifreq *rq,int cmd);
int snull_open(struct net_device *dev)
{
printk("snull_open \n");
memcpy(dev->dev_addr,"\0SNUL0",ETH_ALEN);
dev->dev_addr[ETH_ALEN - 1] += (dev - snull_devs); /* the number */
netif_start_queue(dev);
return 0;
}
int snull_config(struct net_device *dev, struct ifmap *map)
{
printk("snull_ifconfig is called");
if(dev->flags & IFF_UP)
{
printk("snull_ifconfig :device is UP");
return -EBUSY;
}
return 0;
}
int snull_ioctl(struct net_device *dev,struct ifreq *rq,int cmd)
{
return 0;
}
{
printk("snull_ifconfig is called");
if(dev->flags & IFF_UP)
{
printk("snull_ifconfig :device is UP");
return -EBUSY;
}
return 0;
}
int snull_ioctl(struct net_device *dev,struct ifreq *rq,int cmd)
{
return 0;
}
/* The interface interrupts the processor to signal one of two possible events :
(1) a new packet is arrived
or
(2) transmission of outgoing packet is complete
*/
void snull_interrupt(int irq,void *dev_id,struct pt_regs *regs)
{
int statusword;
struct snull_priv *priv;
struct net_device *dev = (struct net_device *) dev_id;
printk(" snull_interrupt is called \n");
/* check with hw if it is really ours*/
if(!dev)
{
printk("hw is not ours\n");
return;
}
/* lock the device */
priv = (struct snull_priv *) dev->priv;
spin_lock(&priv->lock);
/* retrieve the statusword : real hardware use I/O instructions */
statusword = priv->status;
if(statusword && SNULL_RX_INTR)
{
/* send it to snull_rx for handling arrived packet */
snull_rx(dev,priv->rx_packetlen,priv->rx_packetdata);
}
if(statusword && SNULL_TX_INTR)
{
/* transmission is over : free skb */
priv->stats.tx_packets++;
priv->stats.tx_bytes += priv->tx_packetlen;
dev_kfree_skb(priv->skb);
}
/* unlock the device and we are done */
spin_unlock(&priv->lock);
&nbs! p; return;
}
/* receiving a packet & send it to upper layers */
/* snull_rx is called after the hardware has received packet & it is already in comp memory */
{
int statusword;
struct snull_priv *priv;
struct net_device *dev = (struct net_device *) dev_id;
printk(" snull_interrupt is called \n");
/* check with hw if it is really ours*/
if(!dev)
{
printk("hw is not ours\n");
return;
}
/* lock the device */
priv = (struct snull_priv *) dev->priv;
spin_lock(&priv->lock);
/* retrieve the statusword : real hardware use I/O instructions */
statusword = priv->status;
if(statusword && SNULL_RX_INTR)
{
/* send it to snull_rx for handling arrived packet */
snull_rx(dev,priv->rx_packetlen,priv->rx_packetdata);
}
if(statusword && SNULL_TX_INTR)
{
/* transmission is over : free skb */
priv->stats.tx_packets++;
priv->stats.tx_bytes += priv->tx_packetlen;
dev_kfree_skb(priv->skb);
}
/* unlock the device and we are done */
spin_unlock(&priv->lock);
&nbs! p; return;
}
/* receiving a packet & send it to upper layers */
/* snull_rx is called after the hardware has received packet & it is already in comp memory */
void snull_rx(struct net_device *dev,int len,unsigned char *buf)
{
struct sk_buff *skb;
struct snull_priv *priv = (struct snull_priv *) dev->priv;
printk("snull_rx is called\n");
/* the packet has been reterived from the transmission medium . Build an skb around it,
so upper layer can handle it
*/
skb = dev_alloc_skb(len+2);
if(!skb)
{
printk("snull_rx : low on mem hence packet dropped ");
priv->stats.rx_dropped++;
return;
}
memcpy(skb_put(skb,len),buf,len);
/* write metadata ,and then pass to the receive level */
skb->dev = dev;
skb->protocol = eth_type_trans(skb,dev);
skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't ch! eck it */
priv->stats.rx_packets++;
priv->stats.rx_bytes += len;
netif_rx(skb);
}
{
struct sk_buff *skb;
struct snull_priv *priv = (struct snull_priv *) dev->priv;
printk("snull_rx is called\n");
/* the packet has been reterived from the transmission medium . Build an skb around it,
so upper layer can handle it
*/
skb = dev_alloc_skb(len+2);
if(!skb)
{
printk("snull_rx : low on mem hence packet dropped ");
priv->stats.rx_dropped++;
return;
}
memcpy(skb_put(skb,len),buf,len);
/* write metadata ,and then pass to the receive level */
skb->dev = dev;
skb->protocol = eth_type_trans(skb,dev);
skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't ch! eck it */
priv->stats.rx_packets++;
priv->stats.rx_bytes += len;
netif_rx(skb);
}
/* the socket buffer passed to snull_tx (hard_start_xmit) contains the physical
packet as it should appear on the media , compelete with the
transmission-level headers. The interface doesn't neet to modify the data
being transmitted . skb->data points to the packet being transmitted,
and skb->len is its length, in octets.
*/
int snull_tx(struct sk_buff *skb,struct net_device *dev)
{
int len;
char *data;
struct snull_priv *priv = (struct snull_priv *) dev->priv;
printk("snull_tx is called \n");
len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
data = ""> /* svae the timestamp */
dev->trans_start = jiffies ;
/* remember the skb, so we can free at interrup time */
priv->skb = skb ;
/* actual delive! ry data that is device specific */
snull_hw_tx(data,len,dev);
return 0; /* Our simple device cann't fail */
}
packet as it should appear on the media , compelete with the
transmission-level headers. The interface doesn't neet to modify the data
being transmitted . skb->data points to the packet being transmitted,
and skb->len is its length, in octets.
*/
int snull_tx(struct sk_buff *skb,struct net_device *dev)
{
int len;
char *data;
struct snull_priv *priv = (struct snull_priv *) dev->priv;
printk("snull_tx is called \n");
len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
data = ""> /* svae the timestamp */
dev->trans_start = jiffies ;
/* remember the skb, so we can free at interrup time */
priv->skb = skb ;
/* actual delive! ry data that is device specific */
snull_hw_tx(data,len,dev);
return 0; /* Our simple device cann't fail */
}
void snull_hw_tx(char *buf, int len, struct net_device *dev)
{
struct iphdr *ih;
struct net_device *dest;
struct snull_priv *priv;
u32 *saddr, *daddr;
printk("snull_hw_tx is called \n");
/* I am paranoid ,Ain't I? */
if(len < sizeof(struct ethhdr) + sizeof(struct iphdr))
{
printk("snull_hw_tx:Packet is too short compare to size=%i(octets)\n", len);
return;
}
{
struct iphdr *ih;
struct net_device *dest;
struct snull_priv *priv;
u32 *saddr, *daddr;
printk("snull_hw_tx is called \n");
/* I am paranoid ,Ain't I? */
if(len < sizeof(struct ethhdr) + sizeof(struct iphdr))
{
printk("snull_hw_tx:Packet is too short compare to size=%i(octets)\n", len);
return;
}
/* Ethhdr is 14 bytes , but the kernel arranges for iphdr to be aligned
(i.e. ethhdr is unaligned
*/
ih = (struct iphdr *) (buf+sizeof(struct ethhdr));
/* sir i think here i am getting problem due to pointer derefrence */
saddr = &ih->saddr;
daddr = &ih->daddr;
/* change the third octet (class)*/
((u8 *)saddr)[2] ^= 1;
((u8 *)daddr)[2] ^= 1;
/* Ok,now packet is ready for transmission : first send a receive
interrupt on the twin device , then send a transmission-done
to the transmitting device
*/
dest = snull_devs + (dev==snull_devs ? 1 : 0);
priv = (struct snull_priv *) dest->priv;
priv->status! = SNULL_RX_INTR;
priv->rx_packetlen = len;
priv->rx_packetdata = buf;
snull_interrupt(0,dest,NULL);
priv = (struct snull_priv *) dev->priv;
priv->status = SNULL_TX_INTR;
priv->tx_packetlen = len;
priv->tx_packetdata = buf;
if(lockup && ((priv->stats.tx_packets + 1) % lockup) == 0)
{
/* Simulate a dropped transmit interrupt */
netif_stop_queue(dev);
printk("Simulate lockup at %ld ,txp %ld \n",jiffies,
(unsign! ed long) priv->stats.tx_packets);
}
else
snull_interrupt(0,dev,NULL);
}
(i.e. ethhdr is unaligned
*/
ih = (struct iphdr *) (buf+sizeof(struct ethhdr));
/* sir i think here i am getting problem due to pointer derefrence */
saddr = &ih->saddr;
daddr = &ih->daddr;
/* change the third octet (class)*/
((u8 *)saddr)[2] ^= 1;
((u8 *)daddr)[2] ^= 1;
/* Ok,now packet is ready for transmission : first send a receive
interrupt on the twin device , then send a transmission-done
to the transmitting device
*/
dest = snull_devs + (dev==snull_devs ? 1 : 0);
priv = (struct snull_priv *) dest->priv;
priv->status! = SNULL_RX_INTR;
priv->rx_packetlen = len;
priv->rx_packetdata = buf;
snull_interrupt(0,dest,NULL);
priv = (struct snull_priv *) dev->priv;
priv->status = SNULL_TX_INTR;
priv->tx_packetlen = len;
priv->tx_packetdata = buf;
if(lockup && ((priv->stats.tx_packets + 1) % lockup) == 0)
{
/* Simulate a dropped transmit interrupt */
netif_stop_queue(dev);
printk("Simulate lockup at %ld ,txp %ld \n",jiffies,
(unsign! ed long) priv->stats.tx_packets);
}
else
snull_interrupt(0,dev,NULL);
}
void snull_tx_timeout(struct net_device *dev)
{
struct snull_priv *priv = (struct snull_priv *) dev->priv;
printk("snull_tx_timeout is called \n");
printk("Transmission timeout at %ld, latency %ld \n",
jiffies, jiffies - dev->trans_start);
priv->status = SNULL_TX_INTR;
snull_interrupt(0,dev,NULL);
priv->stats.tx_errors++;
netif_wake_queue(dev);
return;
}
/* Snull cann't use ARP because driver change IP addresses in packets
being transmitted , and ARP packets exchanges IP addresses as well.
snull_header method handle physical-layer headers directly.
If device driver wants to use the usual hardware header without running
ARP, then we need to override the default dev->hard_header method (as
soon in snull_header method.
*/
being transmitted , and ARP packets exchanges IP addresses as well.
snull_header method handle physical-layer headers directly.
If device driver wants to use the usual hardware header without running
ARP, then we need to override the default dev->hard_header method (as
soon in snull_header method.
*/
int snull_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, void * daddr, void *saddr,
unsigned int len)
{
struct ethhdr *eth = ( struct ethhdr *) skb_push(skb,ETH_HLEN);
printk("snull_header is called \n");
eth->h_proto = ETH_P_IP;
memcpy(eth->h_source, saddr ? saddr : dev->dev_addr,dev->addr_len);
memcpy(eth->h_dest, daddr ? daddr : dev->dev_addr,dev->addr_len);
eth->h_dest[ETH_ALEN-1] ^= 0x11;
return (dev->hard_header_len);
}
int snull_rebuild_header(struct sk_buff *skb)
{
struct ethhdr *eth = (struct ethhdr *) skb->data;
struct net_device *dev = skb->dev;
&nbs! p; printk("snull_rebuild_header is called \n");
memcpy(eth->h_source,dev->dev_addr,dev->addr_len);
memcpy(eth->h_dest,dev->dev_addr,dev->addr_len);
eth->h_dest[ETH_ALEN-1] ^= 0x01;
return 0;
}
struct net_device_stats *snull_stats(struct net_device *dev)
{
struct snull_priv *priv = (struct snull_priv *) dev->priv;
printk("snull_stats is called \n");
return &priv->stats;
}
{
struct snull_priv *priv = (struct snull_priv *) dev->priv;
printk("snull_stats is called \n");
return &priv->stats;
}
int snull_release(struct net_device *dev)
{
printk("snull_release called\n");
netif_stop_queue(dev);
return 0;
}
int snull_init(struct net_device *dev)
{
printk("snull_init called \n");
ether_setup(dev);
dev->open = snull_open;
dev->stop = snull_release;
dev->set_config = snull_config;
dev->hard_start_xmit = snull_tx;
dev->do_ioctl = snull_ioctl;
dev->get_stats = snull_stats;
dev->rebuild_header = snull_rebuild_header;
dev->hard_header = snull_header;
#ifdef HAVE_TX_TIMEOUT
dev->tx_timeout = snull_tx_timeout;
dev->watchdog_timeo = timeout;
#endif
dev->flags |= IFF_NOARP; // keep default flags ,just add NOARP
dev->hard_header_cache = NULL; //disable caching
SET_MODULE_OWNER(dev);
dev->priv = kmalloc(sizeof( struct snull_priv),GFP_KERNEL);
if(dev->priv==NULL)
{
printk("could not allocated memory for statical info struct of dev = sn%i",(dev-snull_devs));
return -ENOMEM;
}
memset(dev->priv,0,sizeof(struct snull_priv));
spin_lock_init(&((struct snull_priv *)dev->priv)->lock);
return 0;
}
{
printk("snull_init called \n");
ether_setup(dev);
dev->open = snull_open;
dev->stop = snull_release;
dev->set_config = snull_config;
dev->hard_start_xmit = snull_tx;
dev->do_ioctl = snull_ioctl;
dev->get_stats = snull_stats;
dev->rebuild_header = snull_rebuild_header;
dev->hard_header = snull_header;
#ifdef HAVE_TX_TIMEOUT
dev->tx_timeout = snull_tx_timeout;
dev->watchdog_timeo = timeout;
#endif
dev->flags |= IFF_NOARP; // keep default flags ,just add NOARP
dev->hard_header_cache = NULL; //disable caching
SET_MODULE_OWNER(dev);
dev->priv = kmalloc(sizeof( struct snull_priv),GFP_KERNEL);
if(dev->priv==NULL)
{
printk("could not allocated memory for statical info struct of dev = sn%i",(dev-snull_devs));
return -ENOMEM;
}
memset(dev->priv,0,sizeof(struct snull_priv));
spin_lock_init(&((struct snull_priv *)dev->priv)->lock);
return 0;
}
struct net_device snull_devs[2] = {
{ init : snull_init },
{ init : snull_init },
};
{ init : snull_init },
{ init : snull_init },
};
int init_module(void)
{
int i,result,devs_present=0;
printk("init_module called\n");
snull_eth = eth;
if(!snull_eth)
{
strcpy(snull_devs[0].name,"sn0");
strcpy(snull_devs[1].name,"sn1");
}
else
{
strcpy(snull_devs[0].name,"eth%d");
strcpy(snull_devs[1].name,"eth%d");
}
for(i=0;i<2;i++)
{
if(result=register_netdev(snull_devs+i))
printk("eroor=%i while registering device = %s \n",
result,snull_devs[i].name);
else
devs_present++;
}
printk("no of registered devices = %i \n",devs_present);
return 0;
}
{
int i,result,devs_present=0;
printk("init_module called\n");
snull_eth = eth;
if(!snull_eth)
{
strcpy(snull_devs[0].name,"sn0");
strcpy(snull_devs[1].name,"sn1");
}
else
{
strcpy(snull_devs[0].name,"eth%d");
strcpy(snull_devs[1].name,"eth%d");
}
for(i=0;i<2;i++)
{
if(result=register_netdev(snull_devs+i))
printk("eroor=%i while registering device = %s \n",
result,snull_devs[i].name);
else
devs_present++;
}
printk("no of registered devices = %i \n",devs_present);
return 0;
}
void cleanup_module(void)
{
int i;
printk("cleanup_module");
for(i=0;i<2;i++)
{
kfree(snull_devs[i].priv);
unregister_netdev(snull_devs+i);
}
}
{
int i;
printk("cleanup_module");
for(i=0;i<2;i++)
{
kfree(snull_devs[i].priv);
unregister_netdev(snull_devs+i);
}
}
Do you Yahoo!?
Yahoo! Search - Find what you?re looking for faster.