S3C2440 网卡驱动介绍以及制作虚拟网卡驱动(二十五)

发布者:温柔的爱情最新更新时间:2020-07-07 来源: eefocus关键字:S3C2440  网卡驱动  虚拟网卡驱动 手机看文章 扫描二维码
随时随地手机看文章

1、描述


网卡的驱动其实很简单,它还是与硬件相关,主要是负责收发网络的数据包,它将上层协议传递下来的数据包以特定的媒介访问控制方式进行发送,并将接受到的数据包传递给上层协议。


网卡设备与字符设备和块设备不同,网络设备并不对应于/dev/目录下的文件,不过会存放在/sys/class/net目录下

2、Linux系统对网络设备驱动定义了4个层次,这4个层次有到下分为:


1)网络协议接口层:


实现统一的数据包收发的协议,该层主要负责调用dev_queue_xmit()函数发送数据,netif_rx()函数接收数据


2)网络设备接口层:


通过net_device结构体来描述一个具体的网络设备的信息,实现不同的硬件的统一


3)设备驱动功能层:


用来负责驱动网路设备硬件来完成各个功能,它通过hard_start_xmit()函数启动发送操作,并通过网络设备上的中断触发接收操作


4)网络设备与媒体层:


用来负责完成数据包发送和接受的物理实体,设备驱动功能层的函数都在这物理上驱动的


层次结构如下图所示:


3、网卡驱动初始化


而我们的网卡驱动程序,只需要编写网络设备接口层,填充net_device数据结构的内容并将net_device注册入内核,设置硬件相关操作,使能中断处理等。


3.1 其中net_device结构体的重要成员,整理后如下所示:


struct net_device

{

       char               name[IFNAMSIZ];              //网卡设备名称

       unsigned long              mem_end;             //该设备的内存结束地址

       unsigned long              mem_start;            //该设备的内存起始地址

       unsigned long              base_addr;            //该设备的内存I/O基地址

       unsigned int          irq;                       //该设备的中断号

 

       unsigned char        if_port;                  //多端口设备使用的端口类型

    unsigned char        dma;                     //该设备的DMA通道

 

       unsigned long              state;                    //网络设备和网络适配器的状态信息


      struct net_device_stats* (*get_stats)(struct net_device *dev); //获取流量的统计信息

                        //运行ifconfig便会调用该成员函数,并返回一个net_device_stats结构体获取信息

 

      struct net_device_stats  stats;      //用来保存统计信息的net_device_stats结构体

 

 

       unsigned long              features;        //接口特征,     

       unsigned int          flags; //flags指网络接口标志,以IFF_(Interface Flags)开头

//当flags =IFF_UP( 当设备被激活并可以开始发送数据包时, 内核设置该标志)、 IFF_AUTOMEDIA(设置设备可在多种媒介间切换)、

IFF_BROADCAST( 允许广播)、IFF_DEBUG( 调试模式, 可用于控制printk调用的详细程度) 、 IFF_LOOPBACK( 回环)、

IFF_MULTICAST( 允许组播) 、 IFF_NOARP( 接口不能执行ARP,点对点接口就不需要运行 ARP) 和IFF_POINTOPOINT( 接口连接到点到点链路) 等。

 

 

       unsigned        mtu;        //最大传输单元,也叫最大数据包

 

       unsigned short  type;     //接口的硬件类型

 

       unsigned short   hard_header_len;     //硬件帧头长度,一般被赋为ETH_HLEN,即14

 

 

    unsigned char   dev_addr[MAX_ADDR_LEN];      //存放设备的MAC地址

 

       unsigned long              last_rx;    //接收数据包的时间戳,调用netif_rx()后赋上jiffies即可

 

       unsigned long              trans_start;     //发送数据包的时间戳,当要发送的时候赋上jiffies即可

 

       unsigned char        dev_addr[MAX_ADDR_LEN];                //MAC地址

 

 

       int                 (*hard_start_xmit) (struct sk_buff *skb, struct net_device *dev);

                                   //数据包发送函数, sk_buff就是用来收发数据包的结构体

 

 

    void  (*tx_timeout) (struct net_device *dev); //发包超时处理函数

    ... ...

}

上面提到的统计信息net_device_stats结构体,其中重要成员如下所示:


struct net_device_stats

{

       unsigned long       rx_packets;            /*收到的数据包数*/

       unsigned long       tx_packets;            /*发送的数据包数    */

       unsigned long       rx_bytes;               /*收到的字节数,可以通过sk_buff结构体的成员len来获取*/

       unsigned long       tx_bytes;               /*发送的字节数,可以通过sk_buff结构体的成员len来获取*/

       unsigned long       rx_errors;              /*收到的错误数据包数*/

       unsigned long       tx_errors;              /*发送的错误数据包数*/

       ... ...

}

3.2 所以init()函数,初始化网卡步骤如下所示:

1) 使用alloc_netdev()来分配一个net_device结构体


2) 设置网卡硬件相关的寄存器


3) 设置net_device结构体的成员


4) 使用register_netdev()来注册net_device结构体


4、网卡驱动发包过程


在内核中,当上层要发送一个数据包时,就会调用网络设备层里net_device数据结构的成员hard_start_xmit()将数据包发送出去。


hard_start_xmit()发包函数需要我们自己构建,该函数原型如下所示:


int    (*hard_start_xmit) (struct sk_buff *skb, struct net_device *dev);

在这个函数中,需要涉及到sk_buff结构体,含义为(socket buffer)套接字缓冲区,用来网络各个层次之间传递数据。


4.1 sk_buff结构体是一个双向链表,其中重要成员如下所示:


struct sk_buff {

       /* These two members must be first. */

       struct sk_buff        *next;      //指向下一个sk_buff结构体

       struct sk_buff        *prev;     //指向前一个sk_buff结构体

    ... ...

       unsigned int          len,         //数据包的总长度,包括线性数据和非线性数据

                            data_len,        //非线性的数据长度

                            mac_len;         //mac包头长度

 

    __u32          priority;          //该sk_buff结构体的优先级   

 

    __be16        protocol;           //存放上层的协议类型,可以通过eth_type_trans()来获取

       ... ...

 

      sk_buff_data_t              transport_header;    //传输层头部的偏移值

      sk_buff_data_t              network_header;     //网络层头部的偏移值

      sk_buff_data_t              mac_header;          //MAC数据链路层头部的偏移值

 

    sk_buff_data_t              tail;                    //指向缓冲区的数据包末尾

      sk_buff_data_t              end;                     //指向缓冲区的末尾

      unsigned char            *head,                   //指向缓冲区的协议头开始位置

                                  *data;                   //指向缓冲区的数据包开始位置

       ... ...

}

其中sk_buff结构体的空间,如下图所示:



其中sk_buff->data数据包格式如下图所示:



4.2 所以,hard_start_xmit()发包函数处理步骤如下所示:


1)数据包发送出去之前,需要使用netif_stop_queue()来停止上层传下来的数据包


2)设置寄存器,通过网络设备硬件,来发送数据


3)当数据包发出去后,再调用dev_free_skb()函数来释放sk_buff,该函数原型如下:


void dev_kfree_skb(struct sk_buff *skb);   

4)当数据包发出成功,就会进入TX中断函数,然后更新统计信息,调用netif_wake_queue来唤醒,启动上层继续发数据包下来


5)若数据包发出去超时,一直进不到TX中断函数,就会调用net_device结构体的(*tx_timeout)超时成员函数,在该函数中更新


统计信息,调用netif_wake_queue()来唤醒


其中netif_wake_queue()和netif_stop_queue()函数原型如下所示:


void netif_wake_queue(struct net_device *dev);  //唤醒被阻塞的上层,启动继续向网络设备驱动层发送数据包

 

void netif_stop_queue(struct net_device *dev); //阻止上层向网络设备驱动层发送数据包

 

5、网卡驱动收包过程


而接收数据包主要是通过中断函数处理,来判断中断类型,如果等于ISQ_RECEIVER_EVENT,表示为接受中断,然后进入接收数据函数,通过netif_rx()将数据上交给上层


例如下图所示,参考的内核中自带的网卡驱动:drivers/net/cs89x0.c


如上图所示,通过获取的status标志来判断是什么中断,如果是接受中断,就进入net_rx()


5.1 其中net_rx()收包函数处理步骤如下所示:


1)使用dev_alloc_skb()来构造一个新的sk_buff


2)使用skb_reserve(rx_skb,2);将sk_buff缓冲区里的数据包先后位移2字节,来腾出sk_buff缓冲区里的头部空间


3)读取网络设备硬件上接收到的数据


4)使用memcpy()将数据复制到新的sk_buff里的data成员指向的地址处,可以使用skb_put()来动态扩大sk_buff结构体里中的数据区


5)使用eth_type_trans()来获取上层协议,将返回值赋给sk_buff的protocol成员里


6)然后更新统计信息,最后使用netif_rx()来将sk_buffer传递给上层协议中


其中skb_put()函数原型如下所示:


static inline unsigned char *skb_put(struct sk_buff *skb, unsigned int len);

//len:将数据区向下扩大len字节

使用skb_put()函数后,其中sk_buff缓冲区变化如下图:


6、写虚拟网卡驱动


本届便开始来写一个简单的虚拟网卡驱动,也就是说不需要硬件相关操作,所以就没有中断函数,我们通过linux的ping命令来实现发包,然后在发包函数中,伪造一个收的ping包函数,实现ping通任何ip地址

在init初始函数中:


1)使用alloc_netdev()来分配一个net_device结构体


2)设置net_device结构体的成员


3)使用register_netdev()来注册net_device结构体


在发包函数中:


1)使用netif_stop_queue()来阻止上层向网络设备驱动层发送数据包


2)调用收包函数,并代入发送的sk_buff缓冲区,里面来伪造一个收的ping包函数


3)使用dev_kfree_skb()函数来释放发送的sk_buff缓存区


4)更新发送的统计信息


5)使用netif_wake_queue()来唤醒被阻塞的上层


在收包函数中:


首先修改发送的sk_buff里数据包的数据,使它变为一个接受的sk_buff,其中数据包结构如下图所示:




1)需要对调上的ethhdr结构体“源/目的”MAC地址


2)需要对调上图的iphdr结构体"源/目的"IP地址


3)使用ip_fast_csum()来重新获取iphdr结构体的校验码


4)设置上图数据包的数据类型,之前是发送ping包0x08,需要改为0x00,表示接受ping包


5)使用dev_alloc_skb()来构造一个新的sk_buff


6)使用skb_reserve(rx_skb,2);将sk_buff缓冲区里的数据包先后位移2字节,来腾出sk_buff缓冲区里的头部空间


7)使用memcpy()将之前修改好的sk_buff->data复制到新的sk_buff里的data成员指向的地址处


memcpy(skb_put(rx_skb, skb->len), skb->data, skb->len);

// skb_put():来动态扩大sk_buff结构体里中的数据区,避免溢出

8)设置新的sk_buff其它成员


9)使用eth_type_trans()来获取上层协议,将返回值赋给sk_buff的protocol成员里


10)然后更新接收统计信息,最后使用netif_rx()来将sk_fuffer传递给上层协议中


 


7、驱动具体代码如下:


 

/* 参考

 * driversnetcs89x0.c

 */

 

#include

#include

#include

#include

#include

#include

[1] [2]
关键字:S3C2440  网卡驱动  虚拟网卡驱动 引用地址:S3C2440 网卡驱动介绍以及制作虚拟网卡驱动(二十五)

上一篇:S3C2440 Nor Flash驱动(二十四)
下一篇:S3C2440 热拔插驱动 修改mdev配置支持U盘自动挂载(三十三)

推荐阅读最新更新时间:2024-11-02 12:06

uboot-2011.12移植到S3C2440(四)——SDRAM初始化之后,卡在board.c的memset不动
按照转载的(四序)中设置SDRAM,并且修改uboot.lds之后,程序走到memset不再运行,无法解决。暂停。这应该是NANDFLASH代码挪窝的问题,说是2410和2440不兼容。研究中。 uboot-2010.09和201112这两个版本的memset不同,在2011.12版本中,将memset写成汇编语言了,这个比较难整,等待N人解决吧。 这一部分,csdn有csuwzc进行了201103的版本的移植,简单看了下,发现做的很好,我出错的原因大致就在于栈设置不正确,以及其它的小细节,我不打算继续深究,我现在以uboot-2010.09为模板移植。
[单片机]
s3c2440 K9F2G08 nandflash支持硬件ECC校验
S3c2440的nandflash K9F2G08是支持硬件ECC的,NandFlash的每一页分为main区和spare区,S3C2440的NandFlash控制器支持这两个区的硬件ECC,这里我们实现main区的硬件ECC。在include/configs/fl2440.h文件中,如果我们定义了nandflash的硬件ECC校验,那么我们就可以控制相应的nandflash寄存器,实现硬件ECC。 nandflash的每一页有两区:main区和spare区,main区用于存储正常的数据,spare区用于存储其他附加信息,其中就包括ECC校验码。 当我们在写入数据的时候,我们就计算这一页数据的ECC校验码,然后把校验码
[单片机]
存储器控制器与SDRAM(S3C2440)
S3C2440属于统一编址,即存储器和外设统一编址。 CPU可以通过寻址的方式来访问诸如a.GPIO、b.UART、IIC、c.NOR、NAND、网卡等不同的设备。 问:那么CPU是如何访问各个不同的寄存器的呢? 答:CPU只管发出一个地址给内存控制器,内存控制器根据该地址选择不同的模块,然后从模块中得到数据或者发送数据到模块中。 S3C2440存储器控制器概述 –大/小端(通过软件选择) –地址空间:每个 Bank 有 128M 字节(总共 1G/8 个 Bank) –大/小端(通过软件选择) –除了 BANK0(16/32 位)之外,其它全部 BANK 都可编程访问宽度(8/16/32 位) –总共 8 个存储器
[单片机]
存储器控制器与SDRAM(<font color='red'>S3C2440</font>)
s3c2440存储控制器和地址以及启动的理解
1.首先应该先了解Flash ROM的种类 NOR FLASH地址线和数据线分开,来了地址和控制信号,数据就出来。 NAND Flash地址线和数据线在一起,需要用程序来控制,才能出数据。 通俗的说,只给地址不行,要先命令,再给地址,才能读到NAND的数据,在一个总线完成的。 结论是:ARM无法从NAND直接启动。除非装载完程序,才能使用NAND Flash. 2.Nand Flash的命令、地址、数据都通过I/O口发送,管脚复用,这样做做的好处是,可以明显减少NAND FLASH的管脚数目,将来如果设计者想将NAND FLASH更换为更高密度、更大容量的,也不必改动电路板。在S3C2440中NANDFLASH的控制依靠NAND F
[单片机]
一种基于WinCE6.0的数字调频收音机的设计
本设计利用数字收音机芯片Si4730,为基于WincE6.0的智能系统集成FM功能提供了一种很好的解决方案,该方案实现了全频手动与自动搜台等功能。 1 基于WinCE6.0的系统设计流程 如图1所示,基于WinCE 6.0的系统设计一般分为3个过程:针对不同的硬件平台设计BSP包,BSP包括Boot-loader、OAL和驱动程序;针对系统的需求,利用Platform Builder for CE 6.0选择合适的组件,构建操作系统并导出SDK;在SDK的支撑下开发应用程序。 WinCE 6.0与其早期版本相比,开发工具有了较大的变化。Platform Builder已经不是一个单独发行的工具,Platform B
[单片机]
一种基于WinCE6.0的数字调频收音机的设计
关于S3C2440 u-boot支持nand hw ecc
https://blog.csdn.net/hurry_liu/article/details/8741565 ---这篇文章(文章1)讲的很详细。 http://www.xuebuyuan.com/zh-hant/916448.html ----这篇文章(文章2)也讲的差不多。 文章1和文章2的描述是一样的,只是代码内容不一样。 一开始我是看到了文章1,按照那个代码来修改自己的代码,结果还是不成功,总是在读取的时候出现如下错误。 S3C NAND: ECC uncorrectable errordetected. Not correctable. NAND read from offset 0 failed -74 后来看
[单片机]
关于<font color='red'>S3C2440</font> u-boot支持nand hw ecc
基于Linux和s3C2440的GPC控制器设计
近年来,基于Internet的网络化控制系统已成为国内外测控领域研究的热点,在石油勘探开发、钢铁化工等领域有着广阔的应用前景。而控制器的设计和研发是整个网络控制系统的关键和核心。在一些地域高度分散以及环境恶劣的控制现场,使用嵌入式系统作为控制器节点,可更有利于多点分布式综合布控及并行处理,实现更好的测控效果。然而由于网络传输本身的特点,网络时延会不可避免地影响网络控制系统的控制性能和稳定性,因此本文提出基于S3C2440A及嵌入式Linux的GPC(Generalized PredictiveControl)控制器的设计方案,具有一定的通用性。 1 控制器硬件平台设计 控制器节点是嵌入式网络化测控系统的中心。在测控系统中,
[单片机]
基于Linux和<font color='red'>s3C2440</font>的GPC控制器设计
S3C2440 GPIO例子在ISRAM内仿真分析
在mini2440(S3C2440)的板子上运行LED 的程序,使GPB5输出低电平,点亮LED. 将代码在ISRAM 内仿真 1.Led_on.s的完整程序如下 程序代码: -----------------------------led_on.S---------------------------------------------------- PRESERVE8 ;保持堆栈8字节对齐,符合新的ARM ABI标准 AREA LED,CODE, READONLY ENTRY START1 LDR R0,=0x56000010 ;@ R0设为GPBCON寄存
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved