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

嵌入式Linux

开发平台:

C/C++

  1. /*
  2.  * snull.c --  the Simple Network Utility
  3.  *
  4.  * Tested with 2.0 on the x86, Sparc
  5.  */
  6. #ifndef __KERNEL__
  7. #  define __KERNEL__
  8. #endif
  9. #ifndef MODULE
  10. #  define MODULE
  11. #endif
  12. #define __NO_VERSION__ /* don't define kernel_verion in module.h */
  13. #include <linux/module.h>
  14. #include <linux/version.h>
  15. char kernel_version [] = UTS_RELEASE;
  16. #include <linux/sched.h>
  17. #include <linux/kernel.h> /* printk() */
  18. #include <linux/malloc.h> /* kmalloc() */
  19. #include <linux/errno.h>  /* error codes */
  20. #include <linux/types.h>  /* size_t */
  21. #include <linux/interrupt.h> /* mark_bh */
  22. #include <linux/netdevice.h>   /* struct device, and other headers */
  23. #include <linux/etherdevice.h> /* eth_type_trans */
  24. #include <linux/ip.h>          /* struct iphdr */
  25. #include <linux/tcp.h>         /* struct tcphdr */
  26. #include <linux/skbuff.h>
  27. #include <asm/checksum.h>
  28. #include "snull.h"
  29. /* This is a load-time options */
  30. static int eth = 0; /* Call yourself "ethX". Default is "sn0"/"sn1" */
  31. int snull_eth;
  32. /*
  33.  * This structure is private to each device. It is used to pass
  34.  * packets in and out, so there is place for a packet
  35.  */
  36. struct snull_priv {
  37.     struct enet_statistics stats;
  38.     int packetlen;
  39.     int status;
  40.     u8 *packetdata;
  41. };
  42. extern struct device snull_devs[];
  43.         
  44. /*
  45.  * Open and close
  46.  */
  47. int snull_open(struct device *dev)
  48. {
  49.     int i;
  50.     /* request_region(), request_irq(), ....  (like fops->open) */
  51. #if 0
  52.     /*
  53.      * We have no irq line, otherwise this assignment can be used to
  54.      * grab a non-shared interrupt. To share interrupt lines use
  55.      * the dev_id argument of request_irq. Seel snull_interrupt below.
  56.      */
  57.     irq2dev_map[dev->irq] = dev;
  58. #endif
  59.     /* 
  60.      * Assign the hardware address of the board: use "SNULx", where
  61.      * x is 0 or 1. The first byte is '': a safe choice with regard
  62.      * to multicast
  63.      */
  64.     for (i=0; i < ETH_ALEN; i++)
  65.         dev->dev_addr[i] = "SNUL0"[i];
  66.     dev->dev_addr[ETH_ALEN-1] += (dev - snull_devs); /* the number */
  67.     dev->start = 1;
  68.     dev->tbusy = 0;
  69.     MOD_INC_USE_COUNT;
  70.     return 0;
  71. }
  72. int snull_release(struct device *dev)
  73. {
  74.     /* release ports, irq and such -- like fops->close */
  75.     dev->start = 0;
  76.     dev->tbusy = 1; /* can't transmit any more */
  77.     MOD_DEC_USE_COUNT;
  78.     /* if irq2dev_map was used, zero the entry here */
  79.     return 0;
  80. }
  81. /*
  82.  * Configuration changes (passed on by ifconfig)
  83.  */
  84. int snull_config(struct device *dev, struct ifmap *map)
  85. {
  86.     if (dev->flags & IFF_UP) /* can't act on a running interface */
  87.         return -EBUSY;
  88.     /* Don't allow changing the I/O address */
  89.     if (map->base_addr != dev->base_addr) {
  90.         printk(KERN_WARNING "snull: Can't change I/O addressn");
  91.         return -EOPNOTSUPP;
  92.     }
  93.     /* Allow changing the IRQ */
  94.     if (map->irq != dev->irq) {
  95.         dev->irq = map->irq;
  96.         /* request_irq() is delayed to open-time */
  97.     }
  98.     /* ignore other fields */
  99.     return 0;
  100. }
  101. /*
  102.  * Receive a packet: retrieve, encapsulate and pass over to upper levels
  103.  */
  104. void snull_rx(struct device *dev, int len, unsigned char *buf)
  105. {
  106.     struct sk_buff *skb;
  107.     struct snull_priv *privp = (struct snull_priv *)dev->priv;
  108.     /*
  109.      * The packet has been retrieved from the transmission
  110.      * medium. Build an skb around it, so upper layers can handle it
  111.      */
  112.     skb = dev_alloc_skb(len+2);
  113.     if (!skb) {
  114.         printk("snull rx: low on memn");
  115.         return;
  116.     }
  117.     skb_reserve(skb, 2); /* align IP on 16B boundary */  
  118.     memcpy(skb_put(skb, len), buf, len);
  119.     /* Write metadata, and then pass to the receive level */
  120.     skb->dev = dev;
  121.     skb->protocol = eth_type_trans(skb, dev);
  122.     skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
  123.     privp->stats.rx_packets++;
  124.     netif_rx(skb);
  125.     return;
  126. }
  127.     
  128.         
  129. /*
  130.  * The typical interrupt entry point (1.3.70 and later)
  131.  */
  132. void snull_interrupt(int irq, void *dev_id, struct pt_regs *regs)
  133. {
  134.     int statusword;
  135.     struct snull_priv *privptr;
  136.     /*
  137.      * As usual, check the "device" pointer for shared handlers.
  138.      * Then assign "struct device *dev"
  139.      */
  140. #if 0
  141.     /* This is the way to do things for non-shared handlers */
  142.     struct device *dev = (struct device *)(irq2dev_map[irq]);
  143. #else
  144.     /* Otherwise use this SA_SHIRQ-safe approach */
  145.     struct device *dev = (struct device *)dev_id;
  146.     /* ... and check with hw if it's really ours */
  147. #endif
  148.     if (!dev /*paranoid*/ ) return;
  149.     dev->interrupt = 1; /* lock */
  150.     /* retrieve statusword: real netdevices use inb() or inw() */
  151.     privptr = (struct snull_priv *)(dev->priv);
  152.     statusword = privptr->status;
  153.     if (statusword & SNULL_RX_INTR) {
  154.         /* send it to snull_rx for handling */
  155.         snull_rx(dev, privptr->packetlen, privptr->packetdata);
  156.     }
  157.     if (statusword & SNULL_TX_INTR) {
  158.         /* a transmission is over: tell we are no more busy */
  159.         privptr->stats.tx_packets++;
  160.         dev->tbusy = 0;
  161.         mark_bh(NET_BH);
  162.     }
  163.     dev->interrupt = 0; /* release lock */
  164.     return;
  165. }
  166. /*
  167.  * Transmit a packet (low level interface)
  168.  */
  169. void snull_hw_tx(char *buf, int len, struct device *dev)
  170. {
  171.     /*
  172.      * This function deals with hw details. This interface loops
  173.      * back the packet to the other snull interface (if any).
  174.      * In other words, this function implements the snull behaviour,
  175.      * while all other procedures are rather device-independent
  176.      */
  177.     struct iphdr *ih;
  178.     struct device *dest;
  179.     struct snull_priv *privp;
  180.     u32 *saddr, *daddr;
  181.     /* I am paranoid. Ain't I? */
  182.     if (len < sizeof(struct ethhdr) + sizeof(struct iphdr)) {
  183.         printk("snull: Hmm... packet too short (%i octets)n",
  184.                len);
  185.         return;
  186.     }
  187.     if (0) { /* enable this conditional to look at all the data */
  188.         int i;
  189.         PDEBUG("snull: len is %in" KERN_DEBUG "data:",len);
  190.         for (i=14 ; i<len; i++)
  191.             printk(" %02x",buf[i]&0xff);
  192.         printk("n");
  193.     }
  194.     /*
  195.      * Ethhdr is 14 bytes, but the kernel arranges for iphdr
  196.      * to be aligned (i.e., ethhdr is unaligned)
  197.      */
  198.     ih = (struct iphdr *)(buf+sizeof(struct ethhdr));
  199.     saddr = &ih->saddr;
  200.     daddr = &ih->daddr;
  201.     ((u8 *)saddr)[2] ^= 1; /* change the third octet (class C) */
  202.     ((u8 *)daddr)[2] ^= 1;
  203.     ih->check = 0;         /* and rebuild the checksum (ip needs it) */
  204.     ih->check = ip_fast_csum((unsigned char *)ih,ih->ihl);
  205.     if (dev == snull_devs)
  206.         PDEBUGG("%08lx:%05i --> %08lx:%05in",
  207.                ntohl(ih->saddr),ntohs(((struct tcphdr *)(ih+1))->source),
  208.                ntohl(ih->daddr),ntohs(((struct tcphdr *)(ih+1))->dest));
  209.     else
  210.         PDEBUGG("%08lx:%05i <-- %08lx:%05in",
  211.                ntohl(ih->daddr),ntohs(((struct tcphdr *)(ih+1))->dest),
  212.                ntohl(ih->saddr),ntohs(((struct tcphdr *)(ih+1))->source));
  213.     /*
  214.      * Ok, now the packet is ready for transmission: first send a
  215.      * receive interrupt on the twin device, then send a
  216.      * transmission-done to the transmitting device
  217.      */
  218.     dest = snull_devs + (dev==snull_devs ? 1 : 0);
  219.     privp = (struct snull_priv *)dest->priv;
  220.     privp->status = SNULL_RX_INTR;
  221.     privp->packetlen = len;
  222.     privp->packetdata = buf;
  223.     snull_interrupt(0, dest, NULL);
  224.     privp = (struct snull_priv *)dev->priv;
  225.     privp->status = SNULL_TX_INTR;
  226.     snull_interrupt(0, dev, NULL);
  227. }
  228. /*
  229.  * Transmit a packet (called by the kernel)
  230.  */
  231. int snull_tx(struct sk_buff *skb, struct device *dev)
  232. {
  233.     int len, retval=0;
  234.     char *data;
  235.     if (dev->tbusy) {/* shouldn't happen */
  236.         retval = -EBUSY;
  237.         goto tx_done;
  238.     }
  239.     if (skb == NULL) {
  240.         PDEBUG("tint for %pn",dev);
  241.         dev_tint(dev); /* we are ready to transmit */
  242.         return 0;
  243.     }
  244.     dev->tbusy = 1; /* transmission is busy */
  245.     len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; /* minimum len */
  246.     data = skb->data;
  247.     dev->trans_start = jiffies; /* save the timestamp */
  248.     /* actual deliver of data is device-specific, and not shown here */
  249.     snull_hw_tx(data, len, dev);
  250.   tx_done:
  251.     dev_kfree_skb(skb, FREE_WRITE); /* release it */
  252.     return retval; /* zero == done; nonzero == fail */
  253. }
  254. /*
  255.  * Ioctl commands 
  256.  */
  257. int snull_ioctl(struct device *dev, struct ifreq *rq, int cmd)
  258. {
  259.  
  260.     PDEBUG("ioctln");
  261.     return 0;
  262. }
  263. /*
  264.  * Return statistics to the caller
  265.  */
  266. struct enet_statistics *snull_stats(struct device *dev)
  267. {
  268.     struct snull_priv *priv = (struct snull_priv *)dev->priv;
  269.     return &priv->stats;
  270. }
  271. /*
  272.  * This function is called to fill up an eth header, since arp is not
  273.  * available on the interface
  274.  */
  275. int snull_rebuild_header(void *buff, struct device *dev, unsigned long dst,
  276.     struct sk_buff *skb)
  277. {
  278.     struct ethhdr *eth = (struct ethhdr *)buff;
  279.     memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
  280.     memcpy(eth->h_dest, dev->dev_addr, dev->addr_len);
  281.     eth->h_dest[ETH_ALEN-1]   ^= 0x01;   /* dest is us xor 1 */
  282.     return 0;
  283. }
  284. /*
  285.  * The "change_mtu" method is usually not needed.
  286.  * If you need it, it must be like this.
  287.  */
  288. int snull_change_mtu(struct device *dev, int new_mtu)
  289. {
  290.     /* chack ranges */
  291.     if ((new_mtu < 68) || (new_mtu > 1500))
  292.         return -EINVAL;
  293.     /*
  294.      * Do anything you need, and the accept the value
  295.      */
  296.     dev->mtu = new_mtu;
  297.     return 0; /* success */
  298. }
  299. /*
  300.  * The init function (sometimes called probe).
  301.  * It is invoked by register_netdev()
  302.  */
  303. int snull_init(struct device *dev)
  304. {
  305. #if 0
  306.     /*
  307.      * Make the usual checks: check_region(), probe irq, ...  -ENODEV
  308.      * should be returned if no device found.  No resource should be
  309.      * grabbed: this is done on open(). 
  310.      */
  311. #endif
  312.     /* 
  313.      * Then, assign other fields in dev, using ether_setup() and some
  314.      * hand assignments
  315.      */
  316.     ether_setup(dev); /* assign some of the fields */
  317.     dev->open            = snull_open;
  318.     dev->stop            = snull_release;
  319.     dev->set_config      = snull_config;
  320.     dev->hard_start_xmit = snull_tx;
  321.     dev->do_ioctl        = snull_ioctl;
  322.     dev->get_stats       = snull_stats;
  323.     dev->change_mtu      = snull_change_mtu;  
  324.     dev->rebuild_header = snull_rebuild_header;
  325.     /* keep the default flags, just add NOARP */
  326.     dev->flags           |= IFF_NOARP;
  327.     /*
  328.      * Then, allocate the priv field. This encloses the statistics
  329.      * and a few private fields.
  330.      */
  331.     dev->priv = kmalloc(sizeof(struct snull_priv), GFP_KERNEL);
  332.     if (dev->priv == NULL)
  333.         return -ENOMEM;
  334.     memset(dev->priv, 0, sizeof(struct snull_priv));
  335.     return 0;
  336. }
  337. /*
  338.  * The devices
  339.  */
  340. char snull_names[16]; /* two eight-byte buffers */
  341. struct device snull_devs[2] = {
  342.     {
  343.         snull_names, /* name -- set at load time */
  344.         0, 0, 0, 0,  /* shmem addresses */
  345.         0x000,       /* ioport */
  346.         0,           /* irq line */
  347.         0, 0, 0,     /* various flags: init to 0 */
  348.         NULL,        /* next ptr */
  349.         snull_init,  /* init function, fill other fields with NULL's */
  350.     },
  351.     {
  352.         snull_names+8,/* name -- set at load time */
  353.         0, 0, 0, 0,  /* shmem addresses */
  354.         0x000,       /* ioport */
  355.         0,           /* irq line */
  356.         0, 0, 0,     /* various flags: init to 0 */
  357.         NULL,        /* next ptr */
  358.         snull_init,  /* init function, fill other fields with NULL's */
  359.     }
  360. };
  361. /*
  362.  * Finally, the module stuff
  363.  */
  364. int init_module(void)
  365. {
  366.     int result, i, device_present = 0;
  367.     snull_eth = eth; /* copy the cfg datum in the non-static place */
  368.     if (!snull_eth) { /* call them "sn0" and "sn1" */
  369.         memcpy(snull_devs[0].name, "sn0", 4);
  370.         memcpy(snull_devs[1].name, "sn1", 4);
  371.     } else { /* use automatic assignment */
  372.         snull_devs[0].name[0] = snull_devs[1].name[0] = ' ';
  373.     }
  374.     for (i=0; i<2;  i++)
  375.         if ( (result = register_netdev(snull_devs + i)) )
  376.             printk("snull: error %i registering device "%s"n",
  377.                    result, snull_devs[i].name);
  378.         else device_present++;
  379. #ifndef SNULL_DEBUG
  380.     register_symtab(NULL); /* hide symbols */
  381. #endif
  382.     return device_present ? 0 : -ENODEV;
  383. }
  384. void cleanup_module(void)
  385. {
  386.     int i;
  387.    
  388.     for (i=0; i<2;  i++) {
  389.         kfree(snull_devs[i].priv);
  390.         unregister_netdev(snull_devs + i);
  391.     }
  392.     return;
  393. }