博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
网卡驱动流程分析
阅读量:2433 次
发布时间:2019-05-10

本文共 4520 字,大约阅读时间需要 15 分钟。

1.网卡驱动架构分析

1.1linux网络子系统
1.2.重要数据结构
1.3.网卡驱动架构分析

1.1linux网络子系统

linux网络子系统可以分为System call interface(系统调用接口),Protocol agnostic interface(协议无关接口),Network protocols(网络协议栈),Device agnostic interface(设备无关接口),(Device drivers)设备驱动程序

系统调用接口层
为应用程序提供访问网络子系统的统一方法。
协议无关层
提供通用的方法来使用传输层协议。
协议栈的实现
实现具体的网络协议
设备无关层
协议与设备驱动之前通信的通用接口
设备驱动程序

1.2.重要数据结构.

在Linux内核中,每个网卡都由一个net_device结构来描述,其中的一些重要成员有:

char name[IFNAMSIZ]
设备名,如:eth%d
unsigned long base_addr
I/O 基地址
const struct net_device_ops *netdev_ops;
net_device_ops结构记录了网卡所支持的操作。
static const struct net_device_ops dm9000_netdev_ops =
{
.ndo_open = dm9000_open,
.ndo_stop = dm9000_stop,
.ndo_start_xmit = dm9000_start_xmit,
.ndo_do_ioctl = dm9000_ioctl,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
};
Linux内核中的每个网络数据包都由一个套接字缓冲区结构struct sk_buff 描述,即一个
sk_buff结构就是一个网络包,指向sk_buff的指针通常被称做skb。其中包含4个成员,head,data,tail,end,其中data和tail指向数据的头和尾,head和end指向数据包的头和尾。

1.3.网卡驱动架构分析

1.3.1初始化

1.3.1.1分配net_device结构-alloc_etherdev
1.3.1.2初始化net_device结构(设备号,基地址,MAC地址,netdev_ops)
1.3.1.3初始化硬件
1.3.1.4注册网卡驱动—register_netdev
1.3.2数据发送
1.3.2.1通知上层协议,暂停向网卡发送数据-netif_stop_queue
1.3.2.2将SKb的数据写入网卡寄存器,发送走。
1.3.2.3释放skb结构-dev_kfree_skb
1.3.2.4在发送中断处理过程中,通知上层协议可以向网卡送数据-netif_wake_queue
1.3.3数据接收
1.3.3.1读取接收状态
1.3.3.2读取接收到数据的长度
1.3.3.3分配skb结构-dev_alloc_skb
1.3.3.4把网卡寄存器读出数据存入skb
1.3.3.5把收到的skb数据包交给协议栈处理-netif_rx

1.4回环网卡驱动设计

回环网卡是一个纯软件的网卡,可以认为是将TX与RX连接在一起的网卡。

范例代码

unsigned long bytes = 0;unsigned long packets = 0;//数据发送int loopback_xmit(struct sk_buff *skb,struct net_device *dev){    skb->protocol = eth_type_trans(skb,dev);//标明数据包的协议    bytes+=skb->len;//记录发送数据包的长度    packets++;//记录数据包的数目    netif_rx(skb);//将收到的包送回去    return 0;}static struct net_device_stats *loopback_get_stats(struct net_device *dev){    struct net_device_stats *stats = &dev->stats;//将状态指针指向网卡网卡描述结构的状态    stats->tx_bytes = bytes;//字节    stats->rx_bytes = bytes;    stats->rx_packets = packets;//数据包    stats->tx_packets = packets;//数据包    return stats;}struct net_device_ops loopback_ops ={    .ndo_start_xmit = loopback_xmit,    .ndo_get_stats = loopback_get_stats,};void static loopback_setup(struct net_device *dev)//对net_devic结构进行初始化{    dev->mtu = (16*1024)+20+20+12;//接收包的大小    dev->flags = IFF_LOOPBACK;//设置网卡的标志    dev->header_ops = ð_header_ops;//构造包的大小    dev->netdev_ops = &loopback_ops;//初始化网卡操作函数集结构    //dev->addr_len     = ETH_ALEN;以太网地址大小    //dev->type = ARPHRD_LOOPBACK;//环路设备        dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;    //dev->hw_features= NETIF_F_ALL_TSO | NETIF_F_UFO;}static __net_init int loopback_net_init(struct net *net){    struct net_device *dev;    dev = alloc_netdev(0,"lo%d",loopback_setup);    register_netdev(dev);    net->loopback_dev = dev;    return 0;}static __net_exit void loopback_net_exit(struct net *net){    struct net_device *dev = net->loopback_dev;    unregister_netdev(dev);}/* Registered in net/core/dev.c */struct pernet_operations __net_initdata loopback_net_ops = {       .init = loopback_net_init,       .exit = loopback_net_exit,};

2网络子系统深度分析

linux网卡驱动程序

linux网络子系统可以分为System call interface(系统调用接口),Protocol agnostic interface(协议无关接口),Network protocols(网络协议栈),Device agnostic interface(设备无关接口),(Device drivers)设备驱动程序

数据包传输流程

用户程序UDP发送:

创建socket,再调用write函数。
sock_aio_write是发送接口,sock_aio_write调用do_sock_write
在调用 sock_sendmesg,调用udp_sendmsg,调用ip_route_output_flow(选择路由)
udp_push_pending_fram

DM9000网卡驱动程序分析

DM9000采用平台设备编写

DM9000的初始化

1.先分配net_device结构

2.从platform_device中获取地址、中断号
3.将获取到的地址映射为虚拟地址
4.读取芯片类型
5.设置操作函数集
6.从eeprom读取MAC地址
7.使用register_dev注册网卡结构
8.dm9000的硬件初始化在open函数中进行
8.1.request_irp()注册中断处理函数
8.2.dm9000_init_dm9000()包含设置片选、使能发送、接受中断,启动发送队列

dm9000的发送函数

dm9000_start_xmit()

netif_stop_queue,通知协议栈,暂停向驱动发送数据
iow()写入发送skb数包的长度
writeb写数据进入dm9000的数据寄存器
iow()启动发送向dm9000的DM9000_TCR寄存器写数据
当发送方完成触发中断
dev_kfree_skb释放SKB

DM9000的发送中断

ior(db,DM9000_ISR)获取中断类型

判断是否发送中断
dm9000_tx_done()发送中断函数
读取DM9000_TCR寄存器判断发送是否正确
发送正确,netif_work_queue通知协议栈可以继续发送数据

DM9000接收数据

接收dm9000_rx()

Dummy read空读
读取dm9000的的接收状态和数据长度
分配skb,分配整个数据包
skb_reserve将数据报的data和tail的指针向后移动两位
tail的位置是数据包的位置减4
将接收的数据填充入skb包
将skb提交到协议栈netif_rx

dm9000范例代码

struct intdm9000_start_xmit(struct sk_buff *skb,struct net_device *dev){   board_info_t *db = netdev_priv(dev);    //通知协议栈,暂停向驱动发送数据    netif_stop_queue(dev);    //将skb的数据写入寄存器    iow(db,DM9000_TXPLL,skb->len);    iow(db,DM9000_TXPLH,skb->len>>8);    writeb(DM9000_MWCMD,db->io_addr);    (db->outblk)(db->io_data,skb->data,skb->len);    iow(db,DM9000_TCR,TCR_TXREQ);    //释放skb    dev_kfree_skb(skb);    return 0;}

转载地址:http://gvomb.baihongyu.com/

你可能感兴趣的文章
攥在手掌里的Java(转)
查看>>
sql server 安全检查列表(转)
查看>>
教你如何用手工迅速剿灭QQ广告弹出木马(转)
查看>>
Windows系统维护完全图形化攻略(转)
查看>>
WAP2.0移动互联(转)
查看>>
WAP手机防毒攻略(转)
查看>>
如何建立C++ BuilderX 1.5 Mobile Edition开发环境(转)
查看>>
蓝牙套接字概述(转)
查看>>
TCPDUMP简介(转)
查看>>
Symbian智能手机特殊号码搜集(转)
查看>>
Linux操作系统下媒体播放器的初步探讨(转)
查看>>
网站内页权重如何提高-SEO优化技术群课堂笔记(转)
查看>>
用MSDOS.SYS同装两个WIN98(转)
查看>>
用DHTML来模拟实现下拉菜单(转)
查看>>
oracle数据库应用中实现汉字“同音”查询(转)
查看>>
关于无盘网络正确网络配置建议,减少卡机蓝屏关键(转)
查看>>
交换机及路由器如何才能更加安全?(转)
查看>>
chinaunix
查看>>
bxp读写分离怎么设置(转)
查看>>
复制表结构的通用存储过程(转)
查看>>