【Linux高级驱动】网卡驱动分析
两个重要的结构体简单介绍
*sk_buff
如果把网络传输看成是运送货物的话,那么sk_buff就是这个“货物”了,所有经手这个货物的人都要干点什么事儿,要么加个包装,要么印个戳儿等等。收货的时候就要拆掉这些包装,得到我们需要的货物(payload data)。没有货物你还运输什么呢?由此可见sk_buff的重要性了。
*net_device
又是一个庞大的结构体。它在内核中就是指代了一个网络设备。驱动程序需要在探测的时候分配并初始化这个结构体,然后使用register_netdev来注册它,这样就可以把操作硬件的函数与内核挂接在一起。
两个重要结构体的说明
========================================================================================
1.net_device
========================================================================================
)硬件信息
)接口信息
)设备操作函数
)辅助成员
================
/* 此成员记录了最后的数据包开始发送时的时间戳 */
unsigned long trans_start; /* Time (in jiffies) of last Tx */
/* 此成员记录了最后一次接收到数据包时的时间戳,注意:这两个时间戳记录的都是jiffies */
unsigned long last_rx; /* Time of last Rx */
}
========================================================================================
2.网络设备的初始
========================================================================================
(1)进行硬件上的准备工作,检查网络设备是否存在,如果存在,则检测设备所使用的硬件资源
(2)进行软件接口上的准备工作,分配net_device结构体并对其数据和函数指针成员赋值。
(3)获得设备的私有信息指针并初始化其各成员的值,如果私有信息中包括自选锁或信号量等并
发或同步机制,则需对其进行初始化。
一个网络设备驱动初始化函数的模版如下所示:
{
/* 设备的私有信息结构体 */
struct xxx_priv *priv
/* 检测设备是否存在和设备所使用的硬件资源 */
xxx_hw_init();
/* 初始化以太网的共用成员 */
ether_setup (dev);
/* 设置设备的成员函数指针 */
dev->open = cs8900_start;
dev->stop = cs8900_stop;
dev->hard_start_xmit = cs8900_send_start;
dev->get_stats = cs8900_get_stats;
dev->set_multicast_list = cs8900_set_receive_mode;
dev->tx_timeout = cs8900_transmit_timeout;
dev->watchdog_timeo = HZ;
/* 取得私有信息,并初始化它 */
priv =netdev_priv(dev);
... /* 初始化设备私有数据区 */
}
xxx_hw_init()函数完成的基本操作如下所示:
(1)探测xxx网络设备是否存在。探测的方法类似与数学上“反证法”,即先假设存在设备xxx,
访问设备,如果设备的表现与预期的一致,就确定设备存在;否则,假设错误,设备xxx
不存在
(2)探测设备的具体硬件配置。一些设备驱动编写得非常通用,对于同类设备使用统一的驱动,
我们需要在初始化时探测设别的具体型号。另外,即便是同一设备,在硬件上的配置也可
能不一样,我们也可以探测设备所使用的硬件资源
(3)申请设备所需要的硬件资源,如用request_region()函数进行I/O端口的申请等,但是这个
过程可以放在设备的打开函数xxx_open()中完成。
========================================================================================
3. 数据发送流程
========================================================================================
(1)网络设备驱动程序从上层协议传递过来的sk_buff参数获得数据包的有效数据和长度,将有效数据
放入一个临时缓冲区
(2)对于以太网,如果有效数据的长度小于以太网冲突检测所要求数据帧的最小长度ETH_ZLEN,则给
临时缓冲区的末尾填充0
(3)设备硬件的寄存器,驱动网络设备进行数据发送操作
memcpy(shortpkt, skb->data, skb->len);
len = ETH_ZLEN;
data = shortpkt;
}
dev->trans_start = jiffies; /* 记录发送时间戳 */
/* 设置硬件寄存器让硬件把数据包发送出去 */
xxx_hw_tx(data, len, dev);
} ...
else
{
netif_stop_queue(dev);
...
}
}
注意:1)当发送队列满或因其他原因来不及发送当前上层传下来的包,则调用此函数阻止上层继续向网络设备
驱动传递数据包,当忙于发送的数据包发送完成后,TX结束的中断处理中,应该调用netif_wake_queue
来唤醒被阻塞的上层以启动它继续向网络设备驱动传递数据包。
2)当数据传输超时时,意味着当前的发送操作失败或硬件已陷入未知状态,此时,数据包发送超时
处理函数xxx_tx_timeout()将被调用,在此函数中也应该调用netif_wake_queue()函数重新启动
设备发送队列。
========================================================================================
4. 数据接收流程
========================================================================================
网络设备接收数据的主要方法是由中断引发设备的中断处理函数,中断处理函数判断中断类型,如果为接收中断,则读取接收到的数据,分配sk_buffer数据结构和数据缓冲区,将接收到的数据复制到数据缓冲区,并调用netif_rx()函数将sk_buffer传递给上层协议
接收数据流程的典型模版如下所示:
); );
)
kb] = inw(ioaddr + RX_FRAME_PORT);
/* 获取上层协议类型 */
skb->protocol = eth_type_trans(skb, dev);
/* 把数据包交给上层 */
netif_rx(skb);
/* 记录接收时间戳 */
dev->last_rx = jiffies;
...
}
========================================================================================
5. 网络设备的连接状态分析
========================================================================================
网络适配器硬件电路可以检测出链路上是否有载波,载波反映了网络的连接是否正常。
网络设备驱动可以通过netif_carrier_on()和netif_carrier_off()函数改变设备的连接状态,
如果驱动检测到连接状态发生变化,也应该以netif_carrier_on()和netif_carrier_off()函数显式地通知内核。
void netif_carrier_off(struct net_device *dev);
int netif_carrier_ok(struct net_device *dev);
========================================================================================
6. 参数设置和统计数据
在网络设备的驱动程序中还提供一些方法供系统对设备的参数进行设置或读取设备相关的信息。
========================================================================================
当用户调用ioctl()函数,并制定SIOCSIFHWADDR命令时,意味着要设备这个设备的MAC地址。设置网络设备的
MAC地址可用如下代码清单模版:
}
注意:调用xxx_set_mac函数在网络适配器硬件内写入新的MAC地址。这要求设备在硬件上支持MAC地址的修改,而实际上,
许多设备并不提供修改MAC地址的接口。
如果用户调用ioctl()时,命令类型在SIOCDEVPRIVATE和SIOCDEVPRIVATE+15之间,系统会调用驱动程序的do_ioctl()函数
进行设备专用数据的设备,这个设置大多数情况下也并不需要。
驱动程序还应提供get_stats()函数用以向用户反馈设备状态和统计信息,该函数返回的是一个net_device_stats结构体,
如下代码清单模版所示:
{
board_info_t *db = (board_info_t *) dev->priv;
return &db->stats;
}
net_device_stats结构体定义在内核的include/linux/netdevice.h文件中,它包含了比较完整的统计信息,如代码清单所示:
struct net_device_stats
{
unsigned long rx_packets; /* 收到的数据包数 */
unsigned long tx_packets; /* 发送的数据包数 */
unsigned long rx_bytes; /* 收到的字节数 */
unsigned long tx_bytes; /* 发送的字节数 */
unsigned long rx_errors; /* 收到的错误数据包数 */
unsigned long tx_errors; /* 发送的错误数据包数 */
...
...
}
@成鹏致远
(blogs:http://lcw.cnblogs.com)
(email:wwwlllll@126.com)
)
【Linux高级驱动】网卡驱动分析的更多相关文章
- Linux下查看网卡驱动和版本信息
Linux下查看网卡驱动和版本信息 查看网卡生产厂商和信号 查看基本信息:lspci 查看详细信息:lspci -vvv # 3个小写的v 查看网卡信息:lspci | grep Ethernet 查 ...
- 新装Linux系统没有网卡驱动的解决办法和步骤
Linux下查看网卡驱动和版本信息 - CSDN博客 https://blog.csdn.net/guyan1101/article/details/72770424/ 检查网卡是否加载 - Linu ...
- 怎样在linux下安装网卡驱动
由于我电脑的各种奇葩问题的存在,导致我装上Ubuntu13.10之后网卡居然无法使用,坚持了挺久使用无线网,终于坚持不住了,百度了各种解决方式,终于成功解决.这里也记录一下我的解决过程,供大家参考.大 ...
- linux回环网卡驱动设计
回环网卡驱动 1.回环网卡和普通网卡的区别是他是虚拟的不是实际的物理网卡,它相当于把普通网卡的发送端和接收端短接在一起. 2.在内核源代码里的回环网卡程序(drivers/net/loopback.c ...
- linux 高级字符设备驱动 ioctl操作介绍 例程分析实现【转】
转自:http://my.oschina.net/u/274829/blog/285014 1,ioctl介绍 ioctl控制设备读写数据以及关闭等. 用户空间函数原型:int ioctl(int f ...
- Linux高级字符设备驱动
转载:http://www.linuxidc.com/Linux/2012-05/60469p4.htm 1.什么是Poll方法,功能是什么? 2.Select系统调用(功能) Select ...
- Linux系统安装-MacBook网卡驱动问题解决
先附上MacBook的linux安装教程 需要注意的是第7步中可能无法识别出OS X的系统,也没关系,只要格式化磁盘的时候注意选择对应磁盘即可,格式化成EXT4分区. 安装好后发现无法连接无线网络,应 ...
- Linux高级字符设备驱动 poll方法(select多路监控原理与实现)
1.什么是Poll方法,功能是什么? 2.Select系统调用(功能) Select系统调用用于多路监控,当没有一个文件满足要求时,select将阻塞调用进程. int selec ...
- Linux网卡驱动
<网络知识> a:网络模型 OSI模型 TCP模型 虽然OSI模型看着挺完美的,但是过于复杂,这样就会导致不实用,在Linux系统中 ...
- 【Linux高级驱动】如何分析并移植网卡驱动
dm9000的驱动分析 m9000_init platform_driver_register(); db); db); ); ; id_val ; id_val ; /* 获取芯片型号 */ id ...
随机推荐
- HTML之marquee妙用
下面简短几句代码就实现了电子相册自动轮播 <center><h1>网页电子相册</h1></center> <marquee scrollamou ...
- 在 xilinx SDK 使用 math.h
在使用到cos sin tan等算法的时候添加了math库 #include <math.h> 但是却报错了 'Invoking: ARM gcc linker'arm-xilinx-ea ...
- mysql5.7一键安装脚本
0. 概述 最近鼓捣出了一个mysql安装脚本,将该脚本,mysql的my.cnf文件,mysql的安装包这三个文件放在同一个目录下面,执行sh mysql-auto-install.sh就可以完成m ...
- emlog编辑器探寻之旅
本文同步于我的个人博客 emlog编辑器探寻之旅 一直想要寻找一个好用的emlog文本编辑器,寻觅了很久,从默认的KindEditor编辑器开始,用了几天就感觉特别难用,很多需求根本满足不了.后来想要 ...
- 生产环境中tomcat的配置
生产环境中要以daemon方式运行tomcat 通常在开发环境中,我们使用$CATALINA_HOME/bin/startup.sh来启动tomcat, 使用$CATALINA_HOME/bin/sh ...
- BZOJ.2453.维护队列([模板]带修改莫队)
题目链接 带修改莫队: 普通莫队的扩展,依旧从[l,r,t]怎么转移到[l+1,r,t],[l,r+1,t],[l,r,t+1]去考虑 对于当前所在的区间维护一个vis[l~r]=1,在修改值时根据是 ...
- 把url的参数解析出来
https://zhidao.baidu.com/question/455797151306205205.html
- linux中内存超出后可以这样
http://www.cnblogs.com/hongten/archive/2012/11/16/java_PermGen_space.html
- __getattr__和__setattt__使用
# coding:utf-8 """ __setattr__(self, name, value),如果要给name赋值,调用此方法 __getattr__(self, ...
- java三大特性--封装
1.定义: 封装,顾名思义,就是密封包装起来.在面向对象程式设计方法中,封装(英语:Encapsulation)是指,一种将抽象性函式接口的实作细节部份包装.隐藏起来的方法. 封装可以被认为是一个保护 ...