snull.c
上传用户:wudi5211
上传日期:2010-01-21
资源大小:607k
文件大小:16k
源码类别:

嵌入式Linux

开发平台:

C/C++

  1. /*
  2.  * snull.c --  the Simple Network Utility
  3.  *
  4.  * $Id: snull.c,v 1.15 2001/07/11 08:51:51 rubini Exp $
  5.  */
  6. #ifndef __KERNEL__
  7. #  define __KERNEL__
  8. #endif
  9. #ifndef MODULE
  10. #  define MODULE
  11. #endif
  12. #include <linux/config.h>
  13. #include <linux/module.h>
  14. #include <linux/sched.h>
  15. #include <linux/kernel.h> /* printk() */
  16. #include <linux/malloc.h> /* kmalloc() */
  17. #include <linux/errno.h>  /* error codes */
  18. #include <linux/types.h>  /* size_t */
  19. #include <linux/interrupt.h> /* mark_bh */
  20. #include <linux/in.h>
  21. #include <linux/netdevice.h>   /* struct device, and other headers */
  22. #include <linux/etherdevice.h> /* eth_type_trans */
  23. #include <linux/ip.h>          /* struct iphdr */
  24. #include <linux/tcp.h>         /* struct tcphdr */
  25. #include <linux/skbuff.h>
  26. #include "snull.h"
  27. #ifdef LINUX_20
  28. #  include <linux/if_ether.h>
  29. #  define net_device_stats enet_statistics
  30. #else
  31. #  include <linux/in6.h>
  32. #endif
  33. #include <asm/checksum.h>
  34. MODULE_AUTHOR("Alessandro Rubini");
  35. /* This is a load-time options */
  36. static int eth = 0; /* Call yourself "ethX". Default is "sn0"/"sn1" */
  37. MODULE_PARM(eth, "i");
  38. /*
  39.  * Transmitter lockup simulation, normally disabled.
  40.  */
  41. static int lockup = 0;
  42. MODULE_PARM(lockup, "i");
  43. #ifdef HAVE_TX_TIMEOUT
  44. static int timeout = SNULL_TIMEOUT;
  45. MODULE_PARM(timeout, "i");
  46. #endif
  47. int snull_eth;
  48. /*
  49.  * This structure is private to each device. It is used to pass
  50.  * packets in and out, so there is place for a packet
  51.  */
  52. struct snull_priv {
  53.     struct net_device_stats stats;
  54.     int status;
  55.     int rx_packetlen;
  56.     u8 *rx_packetdata;
  57.     int tx_packetlen;
  58.     u8 *tx_packetdata;
  59.     struct sk_buff *skb;
  60.     spinlock_t lock;
  61. };
  62. extern struct net_device snull_devs[];
  63. void snull_tx_timeout (struct net_device *dev);
  64.         
  65. /*
  66.  * Open and close
  67.  */
  68. int snull_open(struct net_device *dev)
  69. {
  70.     MOD_INC_USE_COUNT;
  71.     
  72.     /* request_region(), request_irq(), ....  (like fops->open) */
  73. #if 0 && defined(LINUX_20)
  74.     /*
  75.      * We have no irq line, otherwise this assignment can be used to
  76.      * grab a non-shared interrupt. To share interrupt lines use
  77.      * the dev_id argument of request_irq. See snull_interrupt below.
  78.      */
  79.     irq2dev_map[dev->irq] = dev;
  80. #endif
  81.     /* 
  82.      * Assign the hardware address of the board: use "SNULx", where
  83.      * x is 0 or 1. The first byte is '' to avoid being a multicast
  84.      * address (the first byte of multicast addrs is odd).
  85.      */
  86.     memcpy(dev->dev_addr, "SNUL0", ETH_ALEN);
  87.     dev->dev_addr[ETH_ALEN-1] += (dev - snull_devs); /* the number */
  88. #ifndef LINUX_24                
  89.     dev->start = 1;             
  90. #endif                          
  91.     netif_start_queue(dev);
  92.     return 0;
  93. }
  94. int snull_release(struct net_device *dev)
  95. {
  96.     /* release ports, irq and such -- like fops->close */
  97.     netif_stop_queue(dev); /* can't transmit any more */
  98. #ifndef LINUX_24                
  99.     dev->start = 0;             
  100. #endif                          
  101.     MOD_DEC_USE_COUNT;
  102.     /* if irq2dev_map was used (2.0 kernel), zero the entry here */
  103.     return 0;
  104. }
  105. /*
  106.  * Configuration changes (passed on by ifconfig)
  107.  */
  108. int snull_config(struct net_device *dev, struct ifmap *map)
  109. {
  110.     if (dev->flags & IFF_UP) /* can't act on a running interface */
  111.         return -EBUSY;
  112.     /* Don't allow changing the I/O address */
  113.     if (map->base_addr != dev->base_addr) {
  114.         printk(KERN_WARNING "snull: Can't change I/O addressn");
  115.         return -EOPNOTSUPP;
  116.     }
  117.     /* Allow changing the IRQ */
  118.     if (map->irq != dev->irq) {
  119.         dev->irq = map->irq;
  120.         /* request_irq() is delayed to open-time */
  121.     }
  122.     /* ignore other fields */
  123.     return 0;
  124. }
  125. /*
  126.  * Receive a packet: retrieve, encapsulate and pass over to upper levels
  127.  */
  128. void snull_rx(struct net_device *dev, int len, unsigned char *buf)
  129. {
  130.     struct sk_buff *skb;
  131.     struct snull_priv *priv = (struct snull_priv *) dev->priv;
  132.     /*
  133.      * The packet has been retrieved from the transmission
  134.      * medium. Build an skb around it, so upper layers can handle it
  135.      */
  136.     skb = dev_alloc_skb(len+2);
  137.     if (!skb) {
  138.         printk("snull rx: low on mem - packet droppedn");
  139.         priv->stats.rx_dropped++;
  140.         return;
  141.     }
  142.     skb_reserve(skb, 2); /* align IP on 16B boundary */  
  143.     memcpy(skb_put(skb, len), buf, len);
  144.     /* Write metadata, and then pass to the receive level */
  145.     skb->dev = dev;
  146.     skb->protocol = eth_type_trans(skb, dev);
  147.     skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
  148.     priv->stats.rx_packets++;
  149. #ifndef LINUX_20                        
  150.     priv->stats.rx_bytes += len;
  151. #endif                                  
  152.     netif_rx(skb);
  153.     return;
  154. }
  155.     
  156.         
  157. /*
  158.  * The typical interrupt entry point
  159.  */
  160. #ifdef LINUX_24
  161. void snull_interrupt(int irq, void *dev_id, struct pt_regs *regs)
  162. {
  163.     int statusword;
  164.     struct snull_priv *priv;
  165.     /*
  166.      * As usual, check the "device" pointer for shared handlers.
  167.      * Then assign "struct device *dev"
  168.      */
  169.     struct net_device *dev = (struct net_device *)dev_id;
  170.     /* ... and check with hw if it's really ours */
  171.     if (!dev /*paranoid*/ ) return;
  172.     /* Lock the device */
  173.     priv = (struct snull_priv *) dev->priv;
  174.     spin_lock(&priv->lock);
  175.     /* retrieve statusword: real netdevices use I/O instructions */
  176.     statusword = priv->status;
  177.     if (statusword & SNULL_RX_INTR) {
  178.         /* send it to snull_rx for handling */
  179.         snull_rx(dev, priv->rx_packetlen, priv->rx_packetdata);
  180.     }
  181.     if (statusword & SNULL_TX_INTR) {
  182.         /* a transmission is over: free the skb */
  183.         priv->stats.tx_packets++;
  184.         priv->stats.tx_bytes += priv->tx_packetlen;
  185.         dev_kfree_skb(priv->skb);
  186.     }
  187.     /* Unlock the device and we are done */
  188.     spin_unlock(&priv->lock);
  189.     return;
  190. }
  191. #else /* LINUX_22 or earlier */
  192. void snull_interrupt(int irq, void *dev_id, struct pt_regs *regs)
  193. {
  194.     int statusword;
  195.     struct snull_priv *priv;
  196.     /*
  197.      * As usual, check the "device" pointer for shared handlers.
  198.      * Then assign "struct device *dev"
  199.      */
  200. #if 0 && defined(LINUX_20)
  201.     /* This is the way to do things for non-shared handlers */
  202.     struct device *dev = (struct device *)(irq2dev_map[irq]);
  203. #else
  204.     /* Otherwise use this SA_SHIRQ-safe approach */
  205.     struct net_device *dev = (struct net_device *)dev_id;
  206.     /* ... and check with hw if it's really ours */
  207. #endif
  208.     if (!dev /*paranoid*/ ) return;
  209.     /* Lock the device */
  210.     priv = (struct snull_priv *) dev->priv;
  211.     spin_lock(&priv->lock);
  212.     dev->interrupt = 1;
  213.     /* retrieve statusword: real netdevices use inb() or inw() */
  214.     statusword = priv->status;
  215.     if (statusword & SNULL_RX_INTR) {
  216.         /* send it to snull_rx for handling */
  217.         snull_rx(dev, priv->rx_packetlen, priv->rx_packetdata);
  218.     }
  219.     if (statusword & SNULL_TX_INTR) {
  220.         /* a transmission is over: tell we are no more busy */
  221.         priv->stats.tx_packets++;
  222. #ifndef LINUX_20
  223.         priv->stats.tx_bytes += priv->tx_packetlen;
  224. #endif
  225.         dev_kfree_skb(priv->skb);
  226.     }
  227.     spin_unlock(&priv->lock);
  228.     dev->interrupt = 0;
  229.     return;
  230. }
  231. #endif /* LINUX_22 or earlier */
  232. /*
  233.  * Transmit a packet (low level interface)
  234.  */
  235. void snull_hw_tx(char *buf, int len, struct net_device *dev)
  236. {
  237.     /*
  238.      * This function deals with hw details. This interface loops
  239.      * back the packet to the other snull interface (if any).
  240.      * In other words, this function implements the snull behaviour,
  241.      * while all other procedures are rather device-independent
  242.      */
  243.     struct iphdr *ih;
  244.     struct net_device *dest;
  245.     struct snull_priv *priv;
  246.     u32 *saddr, *daddr;
  247.     /* I am paranoid. Ain't I? */
  248.     if (len < sizeof(struct ethhdr) + sizeof(struct iphdr)) {
  249.         printk("snull: Hmm... packet too short (%i octets)n",
  250.                len);
  251.         return;
  252.     }
  253.     if (0) { /* enable this conditional to look at the data */
  254.         int i;
  255.         PDEBUG("len is %in" KERN_DEBUG "data:",len);
  256.         for (i=14 ; i<len; i++)
  257.             printk(" %02x",buf[i]&0xff);
  258.         printk("n");
  259.     }
  260.     /*
  261.      * Ethhdr is 14 bytes, but the kernel arranges for iphdr
  262.      * to be aligned (i.e., ethhdr is unaligned)
  263.      */
  264.     ih = (struct iphdr *)(buf+sizeof(struct ethhdr));
  265.     saddr = &ih->saddr;
  266.     daddr = &ih->daddr;
  267.     ((u8 *)saddr)[2] ^= 1; /* change the third octet (class C) */
  268.     ((u8 *)daddr)[2] ^= 1;
  269.     ih->check = 0;         /* and rebuild the checksum (ip needs it) */
  270.     ih->check = ip_fast_csum((unsigned char *)ih,ih->ihl);
  271.     if (dev == snull_devs)
  272.         PDEBUGG("%08x:%05i --> %08x:%05in",
  273.                ntohl(ih->saddr),ntohs(((struct tcphdr *)(ih+1))->source),
  274.                ntohl(ih->daddr),ntohs(((struct tcphdr *)(ih+1))->dest));
  275.     else
  276.         PDEBUGG("%08x:%05i <-- %08x:%05in",
  277.                ntohl(ih->daddr),ntohs(((struct tcphdr *)(ih+1))->dest),
  278.                ntohl(ih->saddr),ntohs(((struct tcphdr *)(ih+1))->source));
  279.     /*
  280.      * Ok, now the packet is ready for transmission: first simulate a
  281.      * receive interrupt on the twin device, then  a
  282.      * transmission-done on the transmitting device
  283.      */
  284.     dest = snull_devs + (dev==snull_devs ? 1 : 0);
  285.     priv = (struct snull_priv *) dest->priv;
  286.     priv->status = SNULL_RX_INTR;
  287.     priv->rx_packetlen = len;
  288.     priv->rx_packetdata = buf;
  289.     snull_interrupt(0, dest, NULL);
  290.     priv = (struct snull_priv *) dev->priv;
  291.     priv->status = SNULL_TX_INTR;
  292.     priv->tx_packetlen = len;
  293.     priv->tx_packetdata = buf;
  294.     if (lockup && ((priv->stats.tx_packets + 1) % lockup) == 0) {
  295.         /* Simulate a dropped transmit interrupt */
  296.         netif_stop_queue(dev);
  297.         PDEBUG("Simulate lockup at %ld, txp %ldn", jiffies,
  298.                         (unsigned long) priv->stats.tx_packets);
  299.     }
  300.     else
  301.         snull_interrupt(0, dev, NULL);
  302. }
  303. /*
  304.  * Transmit a packet (called by the kernel)
  305.  */
  306. int snull_tx(struct sk_buff *skb, struct net_device *dev)
  307. {
  308.     int len;
  309.     char *data;
  310.     struct snull_priv *priv = (struct snull_priv *) dev->priv;
  311. #ifndef LINUX_24
  312.     if (dev->tbusy || skb == NULL) {
  313.         PDEBUG("tint for %p, tbusy %ld, skb %pn", dev, dev->tbusy, skb);
  314.         snull_tx_timeout (dev);
  315.         if (skb == NULL)
  316.             return 0;
  317.     }
  318. #endif
  319.     len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
  320.     data = skb->data;
  321.     dev->trans_start = jiffies; /* save the timestamp */
  322.     /* Remember the skb, so we can free it at interrupt time */
  323.     priv->skb = skb;
  324.     /* actual deliver of data is device-specific, and not shown here */
  325.     snull_hw_tx(data, len, dev);
  326.     return 0; /* Our simple device can not fail */
  327. }
  328. /*
  329.  * Deal with a transmit timeout.
  330.  */
  331. void snull_tx_timeout (struct net_device *dev)
  332. {
  333.     struct snull_priv *priv = (struct snull_priv *) dev->priv;
  334.     PDEBUG("Transmit timeout at %ld, latency %ldn", jiffies,
  335.                     jiffies - dev->trans_start);
  336.     priv->status = SNULL_TX_INTR;
  337.     snull_interrupt(0, dev, NULL);
  338.     priv->stats.tx_errors++;
  339.     netif_wake_queue(dev);
  340.     return;
  341. }
  342. /*
  343.  * Ioctl commands 
  344.  */
  345. int snull_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
  346. {
  347.  
  348.     PDEBUG("ioctln");
  349.     return 0;
  350. }
  351. /*
  352.  * Return statistics to the caller
  353.  */
  354. struct net_device_stats *snull_stats(struct net_device *dev)
  355. {
  356.     struct snull_priv *priv = (struct snull_priv *) dev->priv;
  357.     return &priv->stats;
  358. }
  359. /*
  360.  * This function is called to fill up an eth header, since arp is not
  361.  * available on the interface
  362.  */
  363. #ifndef LINUX_20
  364. int snull_rebuild_header(struct sk_buff *skb)
  365. {
  366.     struct ethhdr *eth = (struct ethhdr *) skb->data;
  367.     struct net_device *dev = skb->dev;
  368.     
  369.     memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
  370.     memcpy(eth->h_dest, dev->dev_addr, dev->addr_len);
  371.     eth->h_dest[ETH_ALEN-1]   ^= 0x01;   /* dest is us xor 1 */
  372.     return 0;
  373. }
  374. #else /* LINUX_20 */
  375. int snull_rebuild_header(void *buff, struct net_device *dev, unsigned long dst,
  376.                     struct sk_buff *skb)
  377. {
  378.     struct ethhdr *eth = (struct ethhdr *)buff;
  379.     memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
  380.     memcpy(eth->h_dest, dev->dev_addr, dev->addr_len);
  381.     eth->h_dest[ETH_ALEN-1]   ^= 0x01;   /* dest is us xor 1 */
  382.     return 0;
  383. }
  384. #endif /* LINUX_20 */
  385. int snull_header(struct sk_buff *skb, struct net_device *dev,
  386.                 unsigned short type, void *daddr, void *saddr,
  387.                 unsigned int len)
  388. {
  389.     struct ethhdr *eth = (struct ethhdr *)skb_push(skb,ETH_HLEN);
  390.     eth->h_proto = htons(type);
  391.     memcpy(eth->h_source, saddr ? saddr : dev->dev_addr, dev->addr_len);
  392.     memcpy(eth->h_dest,   daddr ? daddr : dev->dev_addr, dev->addr_len);
  393.     eth->h_dest[ETH_ALEN-1]   ^= 0x01;   /* dest is us xor 1 */
  394.     return (dev->hard_header_len);
  395. }
  396. /*
  397.  * The "change_mtu" method is usually not needed.
  398.  * If you need it, it must be like this.
  399.  */
  400. int snull_change_mtu(struct net_device *dev, int new_mtu)
  401. {
  402.     unsigned long flags;
  403.     spinlock_t *lock = &((struct snull_priv *) dev->priv)->lock;
  404.     
  405.     /* check ranges */
  406.     if ((new_mtu < 68) || (new_mtu > 1500))
  407.         return -EINVAL;
  408.     /*
  409.      * Do anything you need, and the accept the value
  410.      */
  411.     spin_lock_irqsave(lock, flags);
  412.     dev->mtu = new_mtu;
  413.     spin_unlock_irqrestore(lock, flags);
  414.     return 0; /* success */
  415. }
  416. /*
  417.  * The init function (sometimes called probe).
  418.  * It is invoked by register_netdev()
  419.  */
  420. int snull_init(struct net_device *dev)
  421. {
  422. #if 0
  423.     /*
  424.      * Make the usual checks: check_region(), probe irq, ...  -ENODEV
  425.      * should be returned if no device found.  No resource should be
  426.      * grabbed: this is done on open(). 
  427.      */
  428. #endif
  429.     /* 
  430.      * Then, assign other fields in dev, using ether_setup() and some
  431.      * hand assignments
  432.      */
  433.     ether_setup(dev); /* assign some of the fields */
  434.     dev->open            = snull_open;
  435.     dev->stop            = snull_release;
  436.     dev->set_config      = snull_config;
  437.     dev->hard_start_xmit = snull_tx;
  438.     dev->do_ioctl        = snull_ioctl;
  439.     dev->get_stats       = snull_stats;
  440.     dev->change_mtu      = snull_change_mtu;  
  441.     dev->rebuild_header  = snull_rebuild_header;
  442.     dev->hard_header     = snull_header;
  443. #ifdef HAVE_TX_TIMEOUT
  444.     dev->tx_timeout     = snull_tx_timeout;
  445.     dev->watchdog_timeo = timeout;
  446. #endif
  447.     /* keep the default flags, just add NOARP */
  448.     dev->flags           |= IFF_NOARP;
  449. #ifndef LINUX_20                        
  450.     dev->hard_header_cache = NULL;      /* Disable caching */
  451. #endif                                  
  452.     SET_MODULE_OWNER(dev);
  453.     /*
  454.      * Then, allocate the priv field. This encloses the statistics
  455.      * and a few private fields.
  456.      */
  457.     dev->priv = kmalloc(sizeof(struct snull_priv), GFP_KERNEL);
  458.     if (dev->priv == NULL)
  459.         return -ENOMEM;
  460.     memset(dev->priv, 0, sizeof(struct snull_priv));
  461.     spin_lock_init(& ((struct snull_priv *) dev->priv)->lock);
  462.     return 0;
  463. }
  464. /*
  465.  * The devices
  466.  */
  467. #ifdef LINUX_24
  468. struct net_device snull_devs[2] = {
  469.     { init: snull_init, },  /* init, nothing more */
  470.     { init: snull_init, }
  471. };
  472. #else /* pre-2.4 */
  473. char snull_names[16];
  474. struct net_device snull_devs[2] = {
  475.     {
  476.         name: snull_names,
  477.         init: snull_init,  /* init function */
  478.     },
  479.     {
  480.         name: snull_names+8,
  481.         init: snull_init,            /* init function */
  482.     }
  483. };
  484. #endif /* LINUX_24 */
  485. /*
  486.  * Finally, the module stuff
  487.  */
  488. int snull_init_module(void)
  489. {
  490.     int result, i, device_present = 0;
  491.     snull_eth = eth; /* copy the cfg datum in the non-static place */
  492.     if (!snull_eth) { /* call them "sn0" and "sn1" */
  493.         strcpy(snull_devs[0].name, "sn0");
  494.         strcpy(snull_devs[1].name, "sn1");
  495.     } else { /* use automatic assignment */
  496. #ifdef LINUX_24                                                 
  497.         strcpy(snull_devs[0].name, "eth%d");
  498.         strcpy(snull_devs[1].name, "eth%d");
  499. #else                                                           
  500.         snull_devs[0].name[0] = snull_devs[1].name[0] = ' ';    
  501. #endif                                                          
  502.     }
  503.     for (i=0; i<2;  i++)
  504.         if ( (result = register_netdev(snull_devs + i)) )
  505.             printk("snull: error %i registering device "%s"n",
  506.                    result, snull_devs[i].name);
  507.         else device_present++;
  508. #ifndef SNULL_DEBUG
  509.     EXPORT_NO_SYMBOLS;
  510. #endif
  511.     return device_present ? 0 : -ENODEV;
  512. }
  513. void snull_cleanup(void)
  514. {
  515.     int i;
  516.    
  517.     for (i=0; i<2;  i++) {
  518.         kfree(snull_devs[i].priv);
  519.         unregister_netdev(snull_devs + i);
  520.     }
  521.     return;
  522. }
  523. module_init(snull_init_module);
  524. module_exit(snull_cleanup);