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

嵌入式Linux

开发平台:

C/C++

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