zoukankan      html  css  js  c++  java
  • 网卡驱动

      说到网络,对于学过计算机网络的人来说,大概会先想到网络5层协议,但是由于一般的操作系统都集成了网络协议模块,所以网卡驱动模块跟协议模块的关系其实是微乎其微的,硬要说是在协议中的哪一部分的话,应该是在物理层,网卡驱动就是连接物理层跟其它上层协议的模块。

      网卡驱动的主要功能有

      1.接收硬件传来的数据,并且向上层汇报。

         当硬件接收到数据,就会发生中断,在该中断内进行数据的读取,并且复制到内存的网络缓冲区中,其余事情交由网络上层协议处理

      2.提供给网络上层协议向物理层传输的接口。

         当需要向外界发送数据时,需要对硬件进行操作,这时就需要驱动向上层协议提供操作硬件的接口。

      3.完善网卡驱动的其他操作...

         如:

            1. 提供网卡的读写函数

            2. 采用NAPI(当接收数据忙的时候不采用中断方式,而是用poll轮询加快数据传送)

            3. 当网卡空闲一段时间后采用看门狗重启网卡

            4. 进行信息统计

              ...

    以下是基于mini2440的虚拟网卡驱动:

    View Code
      1 #include <linux/errno.h>
      2 #include <linux/netdevice.h>
      3 #include <linux/etherdevice.h>
      4 #include <linux/kernel.h>
      5 #include <linux/types.h>
      6 #include <linux/fcntl.h>
      7 #include <linux/interrupt.h>
      8 #include <linux/ioport.h>
      9 #include <linux/in.h>
     10 #include <linux/skbuff.h>
     11 #include <linux/slab.h>
     12 #include <linux/spinlock.h>
     13 #include <linux/string.h>
     14 #include <linux/init.h>
     15 #include <linux/bitops.h>
     16 #include <linux/delay.h>
     17 
     18 #include <asm/system.h>
     19 #include <asm/io.h>
     20 #include <asm/irq.h>
     21 
     22 #include <linux/ip.h>
     23 //#include <module.h>
     24 
     25 static struct net_device *vnet_dev; 
     26 
     27 static void emulator_rx_packet(struct sk_buff *skb,struct net_device *dev)
     28 {
     29     /* 参考LDD3 */
     30     unsigned char *type;
     31     struct iphdr *ih;
     32     __be32 *saddr, *daddr, tmp;
     33     unsigned char    tmp_dev_addr[ETH_ALEN];
     34     struct ethhdr *ethhdr;
     35     
     36     struct sk_buff *rx_skb;
     37         
     38     // 从硬件读出/保存数据
     39     /* 对调"源/目的"的mac地址 */
     40     ethhdr = (struct ethhdr *)skb->data;
     41     memcpy(tmp_dev_addr, ethhdr->h_dest, ETH_ALEN);
     42     memcpy(ethhdr->h_dest, ethhdr->h_source, ETH_ALEN);
     43     memcpy(ethhdr->h_source, tmp_dev_addr, ETH_ALEN);
     44 
     45     /* 对调"源/目的"的ip地址 */    
     46     ih = (struct iphdr *)(skb->data + sizeof(struct ethhdr));
     47     saddr = &ih->saddr;
     48     daddr = &ih->daddr;
     49 
     50     tmp = *saddr;
     51     *saddr = *daddr;
     52     *daddr = tmp;
     53     
     54     //((u8 *)saddr)[2] ^= 1; /* change the third octet (class C) */
     55     //((u8 *)daddr)[2] ^= 1;
     56     type = skb->data + sizeof(struct ethhdr) + sizeof(struct iphdr);
     57     //printk("tx package type = %02x\n", *type);
     58     // 修改类型, 原来0x8表示ping
     59     *type = 0; /* 0表示reply */
     60     
     61     ih->check = 0;           /* and rebuild the checksum (ip needs it) */
     62     ih->check = ip_fast_csum((unsigned char *)ih,ih->ihl);
     63     
     64     // 构造一个sk_buff
     65     rx_skb = dev_alloc_skb(skb->len + 2);
     66     skb_reserve(rx_skb, 2); /* align IP on 16B boundary */    
     67     memcpy(skb_put(rx_skb, skb->len), skb->data, skb->len);
     68 
     69     /* Write metadata, and then pass to the receive level */
     70     rx_skb->dev = dev;
     71     rx_skb->protocol = eth_type_trans(rx_skb, dev);
     72     rx_skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
     73     dev->stats.rx_packets++;
     74     dev->stats.rx_bytes += skb->len;
     75 
     76     // 提交sk_buff
     77     netif_rx(rx_skb);
     78 }
     79 static int virt_net_send_packet(struct sk_buff *skb,struct net_device *dev)
     80 {
     81     static int count=0;
     82     printk("sending packet...count = %d\n",count++);
     83     /*对于真实的网卡,把skb里的数据通过网卡发送出去*/
     84     netif_stop_queue(dev);                    /*停止该网卡的队列,表示当前正在发送数据包,缓冲区不允许写入*/
     85     /*...*/                                                    /*把skb的数据写入网卡*/
     86     emulator_rx_packet(skb,dev);        /*由于这里是虚拟网卡,我们在这里模拟一个接收到的数据包,进行上报,原本是网卡接收到数据然后才在中断程序内上报数据的*/
     87     dev_kfree_skb(skb);                            /*释放skb*/
     88     netif_wake_queue(dev);                    /*数据发送完成后会产生中断(这里省略),然后中断内唤醒队列*/
     89     
     90     /*完善:*/
     91     /*添加统计信息*/
     92     dev->stats.tx_packets++;
     93     dev->stats.tx_bytes+=skb->len;
     94     return 0;
     95 }
     96 
     97 static const struct net_device_ops virt_net_ops = {
     98     .ndo_start_xmit     = virt_net_send_packet,
     99 };
    100 
    101 
    102 
    103 static int virt_net_init(void)
    104 {
    105     /*1.分配一个net_device结构体*/
    106     //vnet_dev= alloc_etherdev(sizeof(struct net_device));
    107     vnet_dev = alloc_netdev(0, "vnet%d", ether_setup);
    108     
    109     /*2.设置*/ 
    110     vnet_dev->netdev_ops    = &virt_net_ops;
    111     /*设置MAC地址*/
    112     vnet_dev->dev_addr[0]=0x08;
    113     vnet_dev->dev_addr[1]=0x08;
    114     vnet_dev->dev_addr[2]=0x08;
    115     vnet_dev->dev_addr[3]=0x08;
    116     vnet_dev->dev_addr[4]=0x08;
    117     vnet_dev->dev_addr[5]=0x08;
    118     
    119     /* 设置下面两项才能ping通 */
    120     vnet_dev->flags           |= IFF_NOARP;
    121     vnet_dev->features        |= NETIF_F_NO_CSUM;    
    122     
    123     /*3.注册*/
    124     //register_netdevice(vnet_dev);
    125     register_netdev(vnet_dev);
    126     
    127     return 0;
    128 }
    129 
    130 static void virt_net_exit(void)
    131 {
    132     unregister_netdev(vnet_dev);
    133     free_netdev(vnet_dev);
    134 }
    135 
    136 module_init(virt_net_init);
    137 module_exit(virt_net_exit);
    138 
    139 MODULE_AUTHOR("taigacon");
    140 MODULE_LICENSE("GPL");

    网卡驱动编写能分为以下几个步骤:

    1.  分配net_device结构体  alloc_netdev  (对于不同的网卡会分配不同的私有空间,并且会对分配函数进行封装)

    2.  设置net_device,包括:

        设置网卡mac地址

        设置netdev_ops(编写提供上层协议传输数据的接口.ndo_start_xmit)

        注册和编写中断处理函数(当硬件数据到来的时候,发出中断,中断处理程序内部读取数据,并且通知上层协议)。

    3.  注册net_device结构体。

    4.  硬件方面的操作。

        因为要操作到硬件,而且对网卡的读写跟对内存的读写一致:都是发送命令和发送地址之后,进行数据的读写,

        所以我们需要根据时序图,对网卡所在的bank进行内存控制器的设置。

    一般来说,网卡产商都会提供该网卡的相应驱动,该驱动一般是以总线设备驱动框架进行编写,因此会在probe函数内部进行网卡的初始化操作(上面步骤)。

    但是因为网卡产商并不知道我们的芯片型号,所以驱动其中的某些部分是不适合我们的芯片的,所以我们需要在该驱动上进行相应的修改,这就是所谓的移植网卡驱动,

    修改的主要部分主要是与我们的芯片相关,其中就有芯片型号的判定,芯片内存控制器的初始化等。

      

  • 相关阅读:
    python2中的SSL:CERTIFICATE_VERIFY_FAILED错误的解决办法
    head first 设计模式第一章笔记
    pycharm设置python脚本模板
    zip的压缩和解压命令
    js数组和集合互转
    查看Oracle的连接数
    转 小辉_Ray DOM性能小记
    学习总结之javaScript document对象详解
    MySQL 表的一些操作
    MySQL 的一些操作
  • 原文地址:https://www.cnblogs.com/TaigaCon/p/2781697.html
Copyright © 2011-2022 走看看