Chinaunix首页 | 论坛 | 博客
  • 博客访问: 564700
  • 博文数量: 208
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2049
  • 用 户 组: 普通用户
  • 注册时间: 2014-11-19 21:54
文章分类

全部博文(208)

文章存档

2019年(18)

2018年(27)

2017年(5)

2016年(53)

2015年(88)

2014年(17)

分类: LINUX

2015-09-09 20:43:01

原文地址:网络驱动自学笔记 作者:InodeMan

 

************************************ 16.1 linux网络设备驱动的结构*******************************

【结构概述】

计算机生成了可选文字: 网络协议接U层
网络设各接n层
设条驱动功能层
两络没备与媒介层

图:linux网络设备驱动程序的体系结构

 

1、网络协议接口层:向网络层协议提供提供统一的数据包收发接口。不论上层协议为ARP还是IP,都通过dev_queue_xmit()函数发送数据,并通过netif_rx()函数接受数据。这一层的存在使得上层协议独立于具体的设备。

 

2、网络设备接口层:向协议接口层提供统一的用于描述具体网络设备属性和操作的结构体net_device,该结构体是设备驱动功能层中各函数的容器。

 

3、设备驱动功能层:各函数是网络设备接口层net_device数据结构的具体成员,是驱使网络设备硬件完成相应动作的程序,他通过hard_start_xmit()函数启动发送操作,并通过网络设备上的中断触发接受操作。

 

4、网络设备与媒介层:完成数据包发送和接受的物理实体,包括网络适配器和具体的传输媒介,网络适配器被驱动功能层中的函数物理上驱动。对于Linux系统而言,网络设备和媒介都可以是虚拟的。

 

驱动程序员的主要工作:编写设备驱动功能层的相关函数以填充net_device数据结构的内容并将net_device注册;

 

16.1.1】网络协议接口层

1】当上层ARPIP发包时,将调用网络协议接口层的dev_queue_xmit()函数发送数据包。

 dev_queue_xmit(struct sk_buff * skb);

 

2】当上层接收数据包,调用netif_rx()函数;

 int netif_rx(struct sk_buff *skb);

 

3sk_buff结构体

1、含义:套接字缓冲区

2、作用:用于linux网络子系统中的各层之间传递数据;

3、原型:

 struct sk_buff {

struct device *dev;正在处理该包的设备

__u32 saddr ;                           //IP元地址

__u32 daddr;                           //IP目的地址

__u32 raddr;                           //IP路由器地址

…...

 unsigned int len , data_len ;                                  

 _u16  mac_len ,  hdr_len ;

……

 sk_buff_data_t  transport_header;

 sk_buff_data_t  network_header ;

 sk_buff_data_t  mac_header;

……

 sk_buff_data_t tail ;

 sk_buff_data_t end ;

 unsigned char * head , * data;

};

 

4、重要成员:

Head:整个缓冲区的头指针

data:有效数据的头指针

tail   有效数据的尾指针

end  指向分配的内存块的结尾

 

 transport_header :传输层包头位置

 network_header:网络层包头位置

 mac_headerMAC层的包头位置

 

4】套接字缓冲区( sk_buff )的操作

1、分配:申请一个套接字缓冲区和一个数据缓冲区;

1) struct sk_buff *alloc_skb(unsigned int len , gfp_t  priority)

参数

len:数据缓冲区的空间大小,通常以L1_CACHE_BYTES字节对齐;

priority:内存分配的优先级;

 

2) struct sk_buff *dev_alloc_skb(unsigned  int len);

GFP_ATOMIC优先级进行skb的分配;

 

2、释放

linux内核内部使用

1) void kfree_skb(struct sk_buff *skb);

 

网络设备驱动程序中使用

2)void dev_kfree_skb(struct sk_buff * skb)

用于非中断上下文

 

3)void dev_kfree_skb_irq(struct sk_buff *skb);

用于中断上下文

 

4)void dev_kfree_skb_any(struct sk_buff * skb)

在中断和非中断上下文中皆可使用;

 

3、变更

1)在缓冲区尾部增加数据

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

会导致skb->tail后移len, skb->len增加len的大小;

 

2)在缓冲区开头增加数据

 unsigned char * skb_push(struct sk_buff * skb,unsiged int len );

会导致skb->data前移len,而skb->len增加len的大小;

与之相反功能的是:skb_pull——在缓冲区开头移除数据

 

3)空缓冲区,调整缓冲区的头部

 static inline void skb_reserve(struct sk_buff * skb, int len);

skb_data skb_tail 同时后移len

 

16.1.2 网络设备接口层

1net_device:包含网络设备的属性描述和操作接口;

 

2】结构体net_device的关键成员

1、全局变量

1) char name(IFNAMESIZ);              name:网络设备的名称;

 

2)int (* init)(struct net_device *dev);

init:初始化函数指针

如果指针被设置,则网络设备驱动注册时将调用此函数初始化net_device结构体,可以不实现此函数并将其值设置为NULL

 

2、硬件信息

 unsigned long mem_end;                                     //设备使用的共享内存的结束地址

 unsigned long mem_start;                                  // 设备使用的共享内存的起始地址

 

 unsigned long base_addr;            //网络设备I/O基地址

 unsigned char irq;                                                //设备使用的中断号

 unsigned  char if_port;                                        //指定多端口设备使用哪一个端口

 unsigned char dma;                  //指定分配给设备的DMA通道

 

3、接口信息

 unsigned short hard_header_len;     //网络设备的硬件头长度,以太网初始化函数中赋值为ETH_HLEN,14

 

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

 unsigned mtu;                                                 //最大传输单位

 

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

 unsigned char broadcast[MAX_ADDR_LEN];    //存放设备的广播地址

//以太网:这两个地址都是6个字节  ——  广播地址为60XFFMAC地址需要从硬件读出;

 

 unsigned short flags;                                             //网络接口标志

 

4、设备操作函数

 int (*open)(struct net_device * dev);                //打开网络接口设备

 int(*stop)(struct net_device *dev);                   //停止网络接口设备

 

 int (*hard_start_xmit)(struct sk_buff * skb , struct net_device * dev);              //启动数据包的发送

 void (*tx_timeout )(struct net_device *dev);                                                    

//数据包发送超时时,调用此函数,重新发包或者重启硬件等;

 

//完成硬件帧头填充,返回填充的字节数。

 int (*hard_header)(struct sk_buff *skb,                                         //套接字缓冲区指针

 struct net_device *dev,                              //设备指针

 unsigned short type,                                   //协议类型

 void *daddr,                                                  //目的地址

 void *saddr,                                                  //源地址

  unsigned len);                                              //数据长度

 

 struct net_device_stats*(*get_stats)(struct net_device *dev);

//获得网络设备的状态信息,包括网络设备详细的流量统计信息;

 

 int (*do_ioctl)(struct net_device *dev , struct ifreq *ifr, int cmd);                 //进行设备特定的I/O控制

 int (*set_config)(struct net_device *dev , struct ifmap *map );                     

……

……

 

5、辅助成员

 unsigned long trans_start;                                                        //最后的数据包开始发送时的时间戳;

 unsigned long last_rx;                                                                //最后一次接收到数据包的时间戳

……

……

 

16.1.3 设备驱动功能层】

1】编写net_device结构体内部成员的同形函数;

 xxx_open(),xxx_stop(),xxx_get_stats()等等

 

2】中断触发的网络数据包的接收;

 xxx_interrupt()                                                  //完成中断类型判断的基本工作

 xxx_rx()                                                               //完成数据包的生成和递交上层的复杂工作;

 

3】定义私有数据和操作

封装一个私有结构体xxx_private,并将该结构体指针赋值给net_devicepriv成员。

包括特殊的设备属性和操作、自旋锁与信号量、定时器及统计信息;

 

16.1.4 网络设备与媒介层】

对应于实际的硬件设备,定义一组宏和一组访问设备内部寄存器的函数。

#define DATA_REG 0x0004

#define CMD_REG 0x0008

 

//寄存器读写函数

 static u16 xxx_readword(u32 base_addr , int portno){

……  //读取寄存器值并返回

}

 

 static void xxx_writeword(u32 base_addr , int portno , u16 value){

……   //向寄存器写入数值

}

 

********************************** 16.2 linux网络设备驱动的注册与注销 *******************************

1】网络设备驱动的注册

 int register_netdev(struct net_device *dev);

 

2】网络设备驱动的注销

 void unregister_netdev(struct net_device *dev);

 

3net_device结构体的生成和赋值

1、使用宏定义填充

#define alloc_netdev(sizeof_priv , name ,setup)   alloc_netdev_mq(sizeof_priv, name ,setup , 1)

 

 struct net_device *alloc_netdev_mq(int sizeof_priv , const char *name , void (*setup)(struct net_device *),

 unsigned int queue_count);

 参数解析

 sizeof_priv :设备私有成员的大小

 name:设备名

 setupstruct net_devicesetup函数指针,预置net_device成员的值;

 queue_count:要分配的子队列的数量

2、针对以太网,使用宏定义填充

#define alloc_etherdev(sizeof_priv)     alloc_etherdev_mq(sizeof_priv, 1)

Struct net_device *alloc_etherdev_mq(int  sizeof_priv, unsigned int queue_count)

{

 return   alloc_netdev_mq(sizeof_priv, "eth%d" , ether_setup , queue_count);

}

 

 

**********************************16.3 网络设备的初始化 **************************************

1】需要完成如下工作

1、检查网络设备是否存在,存在,检测设备所使用的硬件资源

2、分配net_device结构体并对其内部数据和函数指针赋值

3、获得设备的私有信息指针并初始化其各成员值

 

初始化函数模板 P371

 

**********************************16.4 网络设备的打开与释放 **********************************

1】打开函数

 xxx_open(struct net_device *dev)

open函数内部完成如下工作

1、使能设备使用的硬件资源,申请I/O区域、中断和DMA通道等

2、调用linux内核提供的netif_start_queue(struct net_device *dev),激活设备发送队列

 

2】关闭函数

 xxx_release(struct net_device *dev)

release函数内部完成如下工作

1、调用Linux内核提供的netif_stop_queue(struct net_device *dev), 停止设备传输包

2、释放设备所使用的I/O区域、中断和DMA资源

 

***********************************16.5 数据发送流程 ****************************************

 int xxx_tx(struct sk_buff *skb , struct net_device *dev)

 

1、网络设备驱动程序从上层协议传递过来的sk_buff参数获得数据包的有效数据和长度,将有效数据放入临时缓冲区

2、对于以太网,如果有效数据的长度小于以太网冲突检测所要求数据帧的最小长度,则给临时缓冲区的末尾填充0

3、设置硬件的寄存器,驱使网络设备惊醒数据发送操作

 

【特殊事件处理】

1、发送队列满或者其他原因导致执行netif_stop_queue() TX结束的中断处理中,应该调用netif_wake_queue()唤醒被阻塞的上层,启动继续发送;

 

2、当数据传输超时,xxx_tx_timeout()将被调用,处理完成之后,也要调用netif_wake_queue唤醒;

 

************************************ 16.6 数据接收流程 **************************************

 

计算机生成了可选文字: ,断触发
接攻中断
读取搂收的数据
分绮己sk-七uff区域
将接收数据交赵到
故据姆冲l板
诚坏neti仁rx(l
发送skbuff给上层

 

*********************************** 16.7  网络连接状态 *****************************

1】改变设备的连接状态

 void netif_carrier_on(struct net_device *dev);

 void netif_carrier_off(struct net_device *dev);

 

2】检测链路上的载波信号是否存在

 int netif_carrier_ok(struct  net_device *dev);

 

 

****************************** 16.8 参数设置和统计数据 *****************************

1】当用户调用ioctl()函数,并指定SIOCSIFHWADDR命令时,需要设置MAC地址

 static int set_mac_address(struct net_device *dev , void *addr){                      

If(netif_running(dev))                           //判断设备是否正在运行

 return -EBUSY;                             //设备忙

 

 xxx_set_mac(dev,addr);                       //设置以太网的MAC地址

 return  0;

}

 

2】当用户调用ioctl()函数时,并指定命令为SIOCSIFMAP,系统会调用驱动程序的set_config()函数;

 int xxx_config(struct net_device *dev , struct ifmap * map){

 if(netif_runing(dev))                         //不能设置一个正在运行状态的设备

 return  -EBUSY;                       

 

 /* 假设不允许改变I/O地址 */

 if(map->base_addr != dev->base_addr){

 printk(KERN_WARNING "xxx:Can't change I/O adress \n");

 return  -EOPNOTSUPP;

}

 

/* 假设允许改变IRQ*/

 if(map->irq != dev->irq)

 dev->irq = malp->irq;

Return 0;

}

 

 

3】驱动程序还应提供get_stats()函数用以反馈设备的状态和统计信息

 struct net_device_stats *xxx_stats(struct net_device *dev){

 struct xxx_priv *priv = netdev_priv(dev);

 return  &priv->stats;

}

 

 

 

 

计算机生成了可选文字: 获城套接字缓冲区
i,s气卜uff的分配
1)、t川Ct、k--加ff"alloc--、kb心u甩i朗ed.nt她n,g印eetpr,ority)
21"ructsk一uff'd创ealloc一kb【unslgn司.ntIen);
2,s悦卜uff的释故
2脚.dde,eskfree_skb("ructsk--buff'skb):
3网.ddev-kfree_skb_I叫峨Structsk_buff.skb】;
4冲Idde,eekfree一kbjny《鱿ruCts卜esbuff今skb}
s.njct'k_加ff{
"ruct血vlce.d即二正在处理该包灼设备
_u32、addrjlllP元池111二
一“32dadd仁111户目的地十:
一“32raddr;lllp跳111器1七址
、气buff--翻a_tta.l;
sk--buff--d以a一e间;
unsi名nedchar"head,护data;
3、Sk_b研的奎史
unsi。触dchar's肚bjut(structsKbuff'skb.uns嗯n司intl即!;11尾琳加
un、i。触dchar.5肚b夕u幽("ructsk--buff.,kb,un、i。“.ntIenj;11头名加
由ti。.nlinevoid:kh_吧ervel,tructsk--buff.s卜b,intlen);11空缓冲区
数据包发送尹/尹
de,esqueue_xmit【stnJCtsk_加ff.5取b】
双络协议接‘:层
1、网络哑动的注示
intreoist侧吐netdev(structnet--de,优e"de,);
网络设备接n层
【1】改变设备的连接状杰
voidn"if--ca厅ier一的("ructn.t--d晰帕’
"rudnet一,Eel
i、令局恋里
使川宏定义填充
aIloc_netd创卜12即f_pnv,name,,etUp)
voldn帆i仁ca川.r--Off(structnet_de,Ke
血,)
de甘)
2、硬件信息
针对以太叫,宋定义泊充
a!IOCesdherdevl、izeol--Pnv)
【2】检测链路‘几的载波信号是舌存在
i咐netifseca币e仁。闷鱿了U'tnet一溯ce.改v)二
3、接门信盘
4、改备操作函数
v以d泊侧」nl叹‘tt优tnetesdevi住今d创l
5、转助哎员
1、世置MAC地址
由tic.nt犯t_mac月dd"55(structnet一蝴(e.dev,vaid’司dr}
2、系统四用seteec团飞0
'et-confi创蛇nXtnel-device'd我蛇njctifmap今map);
3、设备状态及统计信息
‘加以tneLdevicejta七.xxx--如ts峨蛇陇tnetdevice.d即l;
1、检查网络设备是否存在,存在,检侧设备所住用的硬件资源
2、分画协e七山洲ice结构休井对其内男散据和的效指针肤倩
3、获得设备的私右信众指针井切始化其各成员信
、初如化
将函欲队给函数于后针
1、实现陇t一创l份结构休内部的效指针的同创纳散
int口xee口阵n峨5廿优tne创evice'devl;
int众xeehard_'tart--城mit('truct‘气加ff"'kb.st川ctn时--de,Ice"d创)
,。d(.tU.n货例t】l从ruct院t_device'dev】;
2、数招包的接收
以t川terrup叫》I以x_洲峨]
3、私有脸据农很作封公成结构休
改备驱动;,J能层
尽de行neDATAREGOxO仪劝
#d城neCMDRE石oxolX】8
网络改备与媒介层
s.atlcu16xxx_read帅rd《u32base_.ddr,in.portno)
st而cvo记xxx-Writ曰囚Ord《u32base_addr.Intp"tno,u16value)

 

 

 

【】

阅读(792) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
请登录后评论。

登录 注册