Chinaunix首页 | 论坛 | 博客
  • 博客访问: 365319
  • 博文数量: 242
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 1134
  • 用 户 组: 普通用户
  • 注册时间: 2012-10-20 10:53
文章分类

全部博文(242)

文章存档

2015年(1)

2014年(10)

2013年(18)

2012年(213)

分类:

2012-11-09 17:25:01

snull网络设备驱动程序

头文件
  1. /*
  2.  * snull.h -- definitions for the network module
  3.  *
  4.  *
  5.  */

  6. #ifndef __SNULL_H__
  7. #define __SNULL_H__


  8. #define SNULL_RX_INTR 0x0001
  9. #define SNULL_TX_INTR 0x0002
  10. #define SNULL_TIMEOUT 5

  11. struct snull_priv {
  12.     struct net_device_stats stats;
  13.     int status;
  14.     int rx_packetlen;
  15.     u8 *rx_packetdata;
  16.     int tx_packetlen;
  17.     u8 *tx_packetdata;
  18.     struct sk_buff *skb;
  19.     spinlock_t lock;
  20.     struct net_device *dev;
  21. };


  22. #endif

驱动源码
  1. /*
  2.  * name:snull.c
  3.  * function:the Simple Network Utility
  4.  * time:2012-2-22
  5.  *
  6.  * author:txgcwm
  7.  * mail:txgcwm@163.com
  8.  * reference:Linux设备驱动程序(第三版)
  9.  */
  10. #ifndef __KERNEL__
  11. # define __KERNEL__
  12. #endif
  13. #ifndef MODULE
  14. # define MODULE
  15. #endif

  16. #include <linux/init.h>
  17. #include <linux/module.h>
  18. #include <linux/sched.h>
  19. #include <linux/kernel.h>
  20. #include <linux/slab.h>
  21. #include <linux/errno.h>
  22. #include <linux/types.h>
  23. #include <linux/interrupt.h>
  24. #include <linux/in.h>
  25. #include <linux/netdevice.h>
  26. #include <linux/etherdevice.h>
  27. #include <linux/ip.h>
  28. #include <linux/tcp.h>
  29. #include <linux/skbuff.h>
  30. #include <linux/in6.h>
  31. #include <asm/checksum.h>
  32. #include "snull.h"


  33. static int lockup = 0;
  34. module_param(lockup,int,0);
  35. static int timeout = SNULL_TIMEOUT;
  36. module_param(timeout,int,0);
  37. struct net_device *snull_devs[2];

  38. void snull_tx_timeout(struct net_device *dev);
  39.         


  40. int snull_open(struct net_device *dev)
  41. {
  42.     /*在接口能够和外界通讯之前,要将硬件(MAC)从硬件设备复制到dev->dev_addr。硬件地址可在打开期间拷贝到设备中。snull软件接口在open时赋予硬件地址--它其实使用了一个长度为ETH_ALEN的ASCII字符串作为假的硬件地址,其中ETH_ALEN是以太网硬件地址的长度*/
  43.     memcpy(dev->dev_addr, "\0SNUL0", ETH_ALEN);
  44.     if(dev == snull_devs[1])
  45.         dev->dev_addr[ETH_ALEN-1] ++;
  46.     netif_start_queue(dev);    //一旦准备好开始发送数据后,open方法还应该启动接口的传输队列,允许接口接受传输包。

  47.     return 0;
  48. }

  49. int snull_release(struct net_device *dev)
  50. {
  51.     netif_stop_queue(dev);    //在接口被关闭时,必须调用该函数,但该函数也可以用来临时停止传输。

  52.     return 0;
  53. }

  54. int snull_config(struct net_device *dev, struct ifmap *map)
  55. {
  56.     if (dev->flags & IFF_UP)
  57.         return -EBUSY;

  58.     if (map->base_addr != dev->base_addr)
  59.     {
  60.         printk(KERN_WARNING "snull: Can't change I/O address\n");
  61.         return -EOPNOTSUPP;
  62.     }

  63.     if (map->irq != dev->irq)
  64.     {
  65.         dev->irq = map->irq;
  66.     }

  67.     return 0;
  68. }

  69. void snull_rx(struct net_device *dev, int len, unsigned char *buf)
  70. {
  71.     struct sk_buff *skb;
  72.     struct snull_priv *priv = netdev_priv(dev);

  73.     skb = dev_alloc_skb(len+2);    //分配一个保存数据包的缓冲区
  74.     if (!skb)
  75.     {
  76.         printk("snull rx: low on mem - packet dropped\n");
  77.         priv->stats.rx_dropped++;
  78.         return;
  79.     }
  80.     skb_reserve(skb, 2);
  81.     memcpy(skb_put(skb, len), buf, len);    //skb_put函数刷新缓冲区内的数据末尾指针,并且返回新创建数据区的指针

  82.     skb->dev = dev;
  83.     skb->protocol = eth_type_trans(skb, dev);
  84.     skb->ip_summed = CHECKSUM_UNNECESSARY;
  85.     priv->stats.rx_packets++;
  86.     priv->stats.rx_bytes += len;
  87.     netif_rx(skb);    //将套接字缓冲区传递给上层软件处理

  88.     return;
  89. }

  90. void snull_interrupt(int irq, void *dev_id, struct pt_regs *regs)
  91. {
  92.     int statusword;
  93.     struct net_device *dev = (struct net_device *)dev_id;
  94.     struct snull_priv *priv = netdev_priv(dev);
  95.    
  96.     if (!dev)
  97.         return;

  98.     spin_lock(&priv->lock);
  99.     statusword = priv->status;
  100.     priv->status = 0;
  101.     if (statusword & SNULL_RX_INTR)
  102.     {
  103.         snull_rx(dev, priv->rx_packetlen, priv->rx_packetdata);
  104.     }
  105.     if (statusword & SNULL_TX_INTR)
  106.     {
  107.         priv->stats.tx_packets++;
  108.         priv->stats.tx_bytes += priv->tx_packetlen;
  109.         dev_kfree_skb(priv->skb);
  110.     }
  111.     spin_unlock(&priv->lock);

  112.     return;
  113. }

  114. void snull_hw_tx(char *buf, int len, struct net_device *dev)
  115. {
  116.     struct iphdr *ih;
  117.     struct net_device *dest;
  118.     struct snull_priv *priv = netdev_priv(dev);
  119.     u32 *saddr, *daddr;

  120.     if (len < sizeof(struct ethhdr) + sizeof(struct iphdr))
  121.     {
  122.         printk("snull: Hmm... packet too short (%i octets)\n",len);
  123.         return;
  124.     }
  125.  
  126.     ih = (struct iphdr *)(buf+sizeof(struct ethhdr));
  127.     saddr = &ih->saddr;
  128.     daddr = &ih->daddr;
  129.     ((u8 *)saddr)[2] ^= 1;
  130.     ((u8 *)daddr)[2] ^= 1;
  131.     ih->check = 0;
  132.     ih->check = ip_fast_csum((unsigned char *)ih,ih->ihl);

  133.     if (dev == snull_devs[0])
  134.         printk(KERN_INFO"%08x:%05i --> %08x:%05i\n",
  135.                ntohl(ih->saddr),ntohs(((struct tcphdr *)(ih+1))->source),
  136.                ntohl(ih->daddr),ntohs(((struct tcphdr *)(ih+1))->dest));
  137.     else
  138.         printk(KERN_INFO"%08x:%05i <-- %08x:%05i\n",
  139.                ntohl(ih->daddr),ntohs(((struct tcphdr *)(ih+1))->dest),
  140.                ntohl(ih->saddr),ntohs(((struct tcphdr *)(ih+1))->source));

  141.     dest = snull_devs[0] + (dev==snull_devs[0] ? 1 : 0);
  142.     priv->status = SNULL_RX_INTR;
  143.     priv->rx_packetlen = len;
  144.     priv->rx_packetdata = buf;
  145.     snull_interrupt(0, dest, NULL);

  146.     priv->status = SNULL_TX_INTR;
  147.     priv->tx_packetlen = len;
  148.     priv->tx_packetdata = buf;
  149.     if (lockup && ((priv->stats.tx_packets + 1) % lockup) == 0)
  150.     {
  151.         netif_stop_queue(dev);
  152.         printk(KERN_INFO"Simulate lockup at %ld, txp %ld\n", jiffies,(unsigned long) priv->stats.tx_packets);
  153.     }
  154.     else
  155.         snull_interrupt(0, dev, NULL);

  156.     return;
  157. }

  158. int snull_tx(struct sk_buff *skb, struct net_device *dev)
  159. {
  160.     int len;
  161.     char *data;
  162.     struct snull_priv *priv = netdev_priv(dev);

  163.     len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;    //当所需传输的数据包长度小于介质所支持的最小长度时,需要小心处理。
  164.     data = skb->data;
  165.     dev->trans_start = jiffies;
  166.     priv->skb = skb;

  167.     snull_hw_tx(data, len, dev);

  168.     return 0;
  169. }

  170. void snull_tx_timeout (struct net_device *dev)
  171. {
  172.     struct snull_priv *priv = netdev_priv(dev);
  173.     printk(KERN_INFO"Transmit timeout at %ld, latency %ld\n", jiffies,jiffies - dev->trans_start);

  174.     priv->status = SNULL_TX_INTR;
  175.     snull_interrupt(0, dev, NULL);
  176.     priv->stats.tx_errors++;
  177.     netif_wake_queue(dev);

  178.     return;
  179. }

  180. int snull_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
  181. {
  182.     return 0;
  183. }

  184. struct net_device_stats *snull_stats(struct net_device *dev)
  185. {
  186.     struct snull_priv *priv = netdev_priv(dev);

  187.     return &priv->stats;
  188. }

  189. int snull_rebuild_header(struct sk_buff *skb)
  190. {
  191.     struct ethhdr *eth = (struct ethhdr *) skb->data;
  192.     struct net_device *dev = skb->dev;
  193.     
  194.     memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
  195.     memcpy(eth->h_dest, dev->dev_addr, dev->addr_len);
  196.     eth->h_dest[ETH_ALEN-1] ^= 0x01;

  197.     return 0;
  198. }

  199. int snull_header(struct sk_buff *skb, struct net_device *dev,
  200.                 unsigned short type, const void *daddr, const void *saddr,
  201.                 unsigned int len)
  202. {
  203.     struct ethhdr *eth = (struct ethhdr *)skb_push(skb,ETH_HLEN);

  204.     eth->h_proto = htons(type);
  205.     memcpy(eth->h_source, saddr ? saddr : dev->dev_addr, dev->addr_len);
  206.     memcpy(eth->h_dest, daddr ? daddr : dev->dev_addr, dev->addr_len);
  207.     eth->h_dest[ETH_ALEN-1] ^= 0x01;

  208.     return (dev->hard_header_len);
  209. }

  210. int snull_change_mtu(struct net_device *dev, int new_mtu)
  211. {
  212.     unsigned long flags;
  213.     struct snull_priv *priv = netdev_priv(dev);
  214.     spinlock_t *lock = &((struct snull_priv *)priv)->lock;

  215.     if ((new_mtu < 68) || (new_mtu > 1500))    //以太网的MTU是1500个octet(ETH_DATA_LEN)
  216.         return -EINVAL;
  217.   
  218.     spin_lock_irqsave(lock, flags);
  219.     dev->mtu = new_mtu;
  220.     spin_unlock_irqrestore(lock, flags);

  221.     return 0;
  222. }

  223. //以下两个结构是相关接口函数的初始化
  224. static const struct net_device_ops snull_dev_ops = {
  225.     .ndo_open = snull_open,
  226.     .ndo_stop = snull_release,
  227.     .ndo_set_config = snull_config,
  228.     .ndo_start_xmit = snull_tx,
  229.     .ndo_do_ioctl = snull_ioctl,
  230.     .ndo_get_stats = snull_stats,
  231.     .ndo_change_mtu = snull_change_mtu,
  232.     .ndo_tx_timeout = snull_tx_timeout,
  233. };

  234. static const struct header_ops snull_header_ops= {
  235.     .create    = snull_header,
  236.     .rebuild = snull_rebuild_header,
  237.     .cache = NULL,
  238. };

  239. void snull_init(struct net_device *dev)
  240. {
  241.     struct snull_priv *priv = NULL;

  242.     ether_setup(dev); //对某些成员作一些初始化
  243.     
  244.     dev->netdev_ops = &snull_dev_ops;
  245.     dev->header_ops = &snull_header_ops;
  246.     dev->watchdog_timeo = timeout;
  247.     dev->flags |= IFF_NOARP;    //禁止ARP
  248.       dev->features |= NETIF_F_NO_CSUM;

  249.     priv = netdev_priv(dev);    //priv是net_device中的一个成员,它与net_device一起被分配,当需要访问私有成员priv时使用该函数
  250.     memset(priv, 0, sizeof(struct snull_priv));
  251.     priv->dev = dev;
  252.     spin_lock_init(&((struct snull_priv *)priv)->lock);

  253.     return;
  254. }

  255. static __init int snull_init_module(void)
  256. {
  257.     int result, i, device_present = 0;

  258.     /*alloc_netdev用来动态分配struct net_device内核数据结构,第一个参数为驱动程序的“私有数据“,第二个是接口的名字,第三个是用来设置net_device结构的初始化函数。对于设备名称,如果驱动程序设置的名称中包含%d格式化字符串,register_netdev将使用一个数字代替它,使之成为唯一的名字,分配的编号从零开始。*/
  259.     snull_devs[0] = alloc_netdev(sizeof(struct snull_priv),"sn%d",snull_init);
  260.     snull_devs[1] = alloc_netdev(sizeof(struct snull_priv),"sn%d",snull_init);
  261.     if(snull_devs[0] == NULL || snull_devs[1] == NULL)
  262.         goto fail;

  263.     for (i=0;i<2;i++)
  264.     {
  265.         //注册设备,必须在初始化一切事情后再注册
  266.         if((result = register_netdev(snull_devs[i])))
  267.             printk("snull: error %i registering device \"%s\"\n",result, snull_devs[i]->name);
  268.         else
  269.             device_present++;
  270.     }

  271.   fail:
  272.     return device_present ? 0 : -ENODEV;
  273. }

  274. static __exit void snull_cleanup(void)
  275. {
  276.     int i;
  277.    
  278.     for (i=0; i<2;i++)
  279.     {
  280.         if(snull_devs[i])
  281.         {            
  282.             unregister_netdev(snull_devs[i]);    //从系统中删除接口
  283.             free_netdev(snull_devs[i]);    //将net_device结构返还给系统
  284.         }    
  285.     }
  286.     return;
  287. }


  288. module_init(snull_init_module);
  289. module_exit(snull_cleanup);

  290. MODULE_AUTHOR("txgcwm");
  291. MODULE_VERSION("snull_v1.0");
  292. MODULE_LICENSE("GPL");

Makefile
  1. ifneq ($(KERNELRELEASE),)
  2.     obj-m := snull.o
  3. else
  4.     KERNELDIR ?= /lib/modules/$(shell uname -r)/build
  5.     PWD := $(shell pwd)
  6. all:
  7.     make -C $(KERNELDIR) M=$(PWD) modules
  8. clean:
  9.     rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.order
  10. endif

加载文件
  1. #!/bin/sh

  2. export PATH=/sbin:/bin

  3. # Use a pathname, as new modutils don't look in the current dir by default
  4. insmod ./snull.ko $*
  5. ifconfig sn0 local0
  6. ifconfig sn1 local1

  7. # The route commands are needed for 2.0, not for later kernels
  8. case "`uname -r`" in
  9.     2.0.*)
  10.         route add -net snullnet0 sn0
  11.         route add -net snullnet1 sn1
  12.         ;;
  13. esac

卸载文件
  1. #!/bin/sh

  2. /sbin/ifconfig sn0 down
  3. /sbin/ifconfig sn1 down
  4. /sbin/rmmod snull



附件:     snull.rar  
阅读(760) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~