pseudo snull linux network device driver [ its urgent ]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



[ 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*/

#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 */
 
#define SNULL_RX_INTR 0x0001
#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
*/
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");
#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;
 

 
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;
}
 

/* 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 */
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);

      
/* 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 */
}
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;
     }
  
   /* 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);
}
 

 
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. 
*/
 

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; 

  
 
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;
}
struct net_device snull_devs[2] = { 
                                     { 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;
}
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);
     
    }
}


Do you Yahoo!?
Yahoo! Search - Find what you?re looking for faster.

[Index of Archives]     [Kernel Newbies]     [Red Hat General]     [Fedora]     [Red Hat Install]     [Linux Kernel Development]     [Yosemite News]

  Powered by Linux