Chinaunix首页 | 论坛 | 博客
  • 博客访问: 97038
  • 博文数量: 38
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 384
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-06 16:52
文章分类

全部博文(38)

文章存档

2014年(38)

我的朋友

分类: 嵌入式

2014-05-13 16:50:24

目的:使虚拟网卡能ping通3.3.3.4

方法:由于是虚拟网卡,没有与真实网络连接,为了ping通,可以在驱动程序中构造一个函数,这个函数的作用是修改网卡发出去的报文,把报文中的目标mac和源mac对调,把目标ip和源ip对调,等等,假装这个修改后的报文就是接收到的报文,通过netif_rx上报,系统接收到这个上报的报文后,由于格式和3.3.3.4的回复报文的格式一样,系统以为这就是3.3.3.4回复的报文,显示ping通了

代码如下

点击(此处)折叠或打开

  1. /*
  2.  * 参考drivers\net\dm9000.c
  3.  */
  4. #include <linux/module.h>
  5. #include <linux/ioport.h>
  6. #include <linux/netdevice.h>
  7. #include <linux/etherdevice.h>
  8. #include <linux/init.h>
  9. #include <linux/interrupt.h>
  10. #include <linux/skbuff.h>
  11. #include <linux/spinlock.h>
  12. #include <linux/crc32.h>
  13. #include <linux/mii.h>
  14. #include <linux/ethtool.h>
  15. #include <linux/dm9000.h>
  16. #include <linux/delay.h>
  17. #include <linux/platform_device.h>
  18. #include <linux/irq.h>
  19. #include <linux/slab.h>
  20. #include <linux/ip.h>

  21. #include <asm/delay.h>
  22. #include <asm/irq.h>
  23. #include <asm/io.h>

  24. static struct net_device *vnet_dev;

  25. static void emulate_receive_package(struct sk_buff *skb, struct net_device *dev)
  26. {
  27.     /* 参考LDD3 */
  28.     unsigned char *type;
  29.     struct iphdr *ih;
  30.     __be32 *saddr, *daddr, tmp;
  31.     unsigned char    tmp_dev_addr[ETH_ALEN];
  32.     struct ethhdr *ethhdr;
  33.     
  34.     struct sk_buff *rx_skb;
  35.         
  36.     // 从硬件读出/保存数据
  37.     /* 对调"源/目的"的mac地址 */
  38.     ethhdr = (struct ethhdr *)skb->data;
  39.     memcpy(tmp_dev_addr, ethhdr->h_dest, ETH_ALEN);
  40.     memcpy(ethhdr->h_dest, ethhdr->h_source, ETH_ALEN);
  41.     memcpy(ethhdr->h_source, tmp_dev_addr, ETH_ALEN);

  42.     /* 对调"源/目的"的ip地址 */
  43.     ih = (struct iphdr *)(skb->data + sizeof(struct ethhdr));
  44.     saddr = &ih->saddr;
  45.     daddr = &ih->daddr;

  46.     tmp = *saddr;
  47.     *saddr = *daddr;
  48.     *daddr = tmp;
  49.     
  50.     //((u8 *)saddr)[2] ^= 1; /* change the third octet (class C) */
  51.     //((u8 *)daddr)[2] ^= 1;
  52.     type = skb->data + sizeof(struct ethhdr) + sizeof(struct iphdr);
  53.     //printk("tx package type = %02x\n", *type);
  54.     // 修改类型, 原来0x8表示ping
  55.     *type = 0; /* 0表示reply */
  56.     
  57.     ih->check = 0;         /* and rebuild the checksum (ip needs it) */
  58.     ih->check = ip_fast_csum((unsigned char *)ih,ih->ihl);
  59.     
  60.     // 构造一个sk_buff
  61.     rx_skb = dev_alloc_skb(skb->len + 2);
  62.     skb_reserve(rx_skb, 2); /* align IP on 16B boundary */    
  63.     memcpy(skb_put(rx_skb, skb->len), skb->data, skb->len);

  64.     /* Write metadata, and then pass to the receive level */
  65.     rx_skb->dev = dev;
  66.     rx_skb->protocol = eth_type_trans(rx_skb, dev);
  67.     rx_skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
  68.     dev->stats.rx_packets++;
  69.     dev->stats.rx_bytes += skb->len;

  70.     // 提交sk_buff
  71.     netif_rx(rx_skb);
  72. }

  73. static int vnet_send_packet(struct sk_buff *skb, struct net_device *dev)//发包函数
  74. {
  75.     /* 如果是真实的网卡:
  76.      * 1. 停止网卡的队列: netif_stop_queue(dev);
  77.      * 2. 把skb的数据移到网卡的内存去
  78.      * 3. 释放skb
  79.      * 4. 数据真正发送出去之后产生中断
  80.      * 5. 在中断处理函数里:
  81.      * 更新网卡的统计信息
  82.      * netif_wake_queue(dev);
  83.      */
  84.     
  85.     static int cnt = 0;
  86.     printk("vnet_send_packet %d\n", ++cnt);
  87.     
  88.     netif_stop_queue(dev);//停止网卡的队列
  89.     
  90.     /* 把skb的数据移到网卡的内存去,我们是虚拟网卡,没有这一步 */
  91.     
  92.     /* 构造一个假的sk_buff,上报 */
  93.     emulate_receive_package(skb, dev);

  94.     dev_kfree_skb(skb);//释放skb
  95.     
  96.     /*真实网卡的以下信息应该在中断处理函数中完成*/
  97.     /*更新统计信息*/
  98.     dev->stats.tx_bytes += skb->len;//发送的字节数
  99.     dev->stats.tx_packets++;//发送的包个数
  100.     
  101.     netif_wake_queue(dev);//数据全部发送出去后,唤醒网卡队列
  102.     


  103.     return 0;
  104. }

  105. static struct net_device_ops vnet_dev_ops =
  106. {
  107.     /* 2.1 在结构体net_device_ops中定义发包函数:nodo_start_xmit */
  108.     .ndo_start_xmit        = vnet_send_packet,
  109. };

  110. static int vnet_init(void)
  111. {
  112.     /* 1. 分配一个net_device */
  113.     vnet_dev = alloc_netdev(0, "vnet%d", ether_setup); // alloc_etherdev;

  114.     /* 2. 设置: */
  115.     /* 2.2 其他信息 */
  116.     /*设置mac地址*/
  117.     vnet_dev->dev_addr[0] = 0x00;
  118.     vnet_dev->dev_addr[1] = 0xE0;
  119.     vnet_dev->dev_addr[2] = 0x4A;
  120.     vnet_dev->dev_addr[3] = 0xbc;
  121.     vnet_dev->dev_addr[4] = 0x15;
  122.     vnet_dev->dev_addr[5] = 0xe8;
  123.     
  124.     /* 设置下面这项才能ping通 */
  125.     vnet_dev->flags |= IFF_NOARP;    

  126.     /* 3. 硬件相关的: request_irq, 在中断函数里得到数据后用netif_rx上报 */

  127.     /* 4. 注册net_device */
  128.     vnet_dev->netdev_ops = &vnet_dev_ops;//必须添加,否则会注册失败
  129.     register_netdev(vnet_dev);

  130.     
  131.     return 0;
  132. }

  133. static void vnet_exit(void)
  134. {
  135.     unregister_netdev(vnet_dev);
  136.     free_netdev(vnet_dev);
  137. }

  138. module_init(vnet_init);
  139. module_exit(vnet_exit);

  140. MODULE_LICENSE("GPL");

阅读(1559) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~