【Linux高级驱动】网卡驱动分析

时间:2022-04-11 04:17:30

两个重要的结构体简单介绍

*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)获得设备的私有信息指针并初始化其各成员的值,如果私有信息中包括自选锁或信号量等并
     发或同步机制,则需对其进行初始化。
    
一个网络设备驱动初始化函数的模版如下所示:

void xxx_init(struct net_device *dev)
{
  /* 设备的私有信息结构体 */
  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)设备硬件的寄存器,驱动网络设备进行数据发送操作

, ETH_ZLEN);
     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_on(struct net_device *dev);
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结构体,
    如下代码清单模版所示:

static struct net_device_stats *xxx_get_stats(struct net_device *dev)
{
  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)

(emailwwwlllll@126.com)

【Linux高级驱动】网卡驱动分析的更多相关文章

  1. Linux下查看网卡驱动和版本信息

    Linux下查看网卡驱动和版本信息 查看网卡生产厂商和信号 查看基本信息:lspci 查看详细信息:lspci -vvv # 3个小写的v 查看网卡信息:lspci | grep Ethernet 查 ...

  2. 新装Linux系统没有网卡驱动的解决办法和步骤

    Linux下查看网卡驱动和版本信息 - CSDN博客 https://blog.csdn.net/guyan1101/article/details/72770424/ 检查网卡是否加载 - Linu ...

  3. 怎样在linux下安装网卡驱动

    由于我电脑的各种奇葩问题的存在,导致我装上Ubuntu13.10之后网卡居然无法使用,坚持了挺久使用无线网,终于坚持不住了,百度了各种解决方式,终于成功解决.这里也记录一下我的解决过程,供大家参考.大 ...

  4. linux回环网卡驱动设计

    回环网卡驱动 1.回环网卡和普通网卡的区别是他是虚拟的不是实际的物理网卡,它相当于把普通网卡的发送端和接收端短接在一起. 2.在内核源代码里的回环网卡程序(drivers/net/loopback.c ...

  5. linux 高级字符设备驱动 ioctl操作介绍 例程分析实现【转】

    转自:http://my.oschina.net/u/274829/blog/285014 1,ioctl介绍 ioctl控制设备读写数据以及关闭等. 用户空间函数原型:int ioctl(int f ...

  6. Linux高级字符设备驱动

    转载:http://www.linuxidc.com/Linux/2012-05/60469p4.htm 1.什么是Poll方法,功能是什么? 2.Select系统调用(功能)      Select ...

  7. Linux系统安装-MacBook网卡驱动问题解决

    先附上MacBook的linux安装教程 需要注意的是第7步中可能无法识别出OS X的系统,也没关系,只要格式化磁盘的时候注意选择对应磁盘即可,格式化成EXT4分区. 安装好后发现无法连接无线网络,应 ...

  8. Linux高级字符设备驱动 poll方法(select多路监控原理与实现)

    1.什么是Poll方法,功能是什么? 2.Select系统调用(功能)      Select系统调用用于多路监控,当没有一个文件满足要求时,select将阻塞调用进程.      int selec ...

  9. Linux网卡驱动

    <网络知识> a:网络模型               OSI模型               TCP模型 虽然OSI模型看着挺完美的,但是过于复杂,这样就会导致不实用,在Linux系统中 ...

  10. 【Linux高级驱动】如何分析并移植网卡驱动

    dm9000的驱动分析 m9000_init platform_driver_register(); db); db); );  ; id_val ; id_val ; /* 获取芯片型号 */ id ...

随机推荐

  1. html5 audio总结

    前言 html5中对音频,视频播放原生支持.最近做了一个音乐播放器,得益于快过年了,才能抽出一点时间来总结一下.总的来说,html5对audio的支持非常强大, 难怪flash要死.浏览器上装播放插件 ...

  2. C&plus;&plus;类成员函数的重载、覆盖和隐藏区别?

    C++类成员函数的重载.覆盖和隐藏区别? a.成员函数被重载的特征:(1)相同的范围(在同一个类中):(2)函数名字相同:(3)参数不同:(4)virtual 关键字可有可无.b.覆盖是指派生类函数覆 ...

  3. 关于PS激活的一些感想(附上PS CC2015)

    最近跟着慕课学了一些前端的必备PS技能,就顺道把PS CC2015装上. 安装的过程没什么大问题,最要命的是激活环节!各种踩坑,但万万没想到,最终我还是成功的把它激活了. 本人所安装PS版本信息 好了 ...

  4. 三、服务解析(Resolving Services)

    当你完成组件注册,并将组件暴露为适当的服务后你就可以通过容器或者容器的子生命周期域来解析服务(After you have your components registered with approp ...

  5. jquery 根据网站url给导航nav添加active效果

    后台的同事因为把nav公用了,所以无法单页添加active,一下方法通过判断url的后缀给当前页添加active $(function(){ var _nava= $('.nav .nav-wrapp ...

  6. hdu Write a simple HTML Browser

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1088 对比输出 代码: #include <stdio.h> #include <s ...

  7. HDU 1361 Parencodings&lpar;栈&rpar;

    题目链接 Problem Description Let S = s1 s2 … s2n be a well-formed string of parentheses. S can be encode ...

  8. POJ1308 Is It A Tree&quest;

    题目大意:和HDU1272-小希的迷宫题目一样, 如果有一个通道连通了房间A和B,那么既可以通过它从房间A走到房间B,也可以通过它从房间B走到房间A,为了提高难度,小希希望任意两个房间有且仅有一条路径 ...

  9. 关于C&sol;S框架网单表绑定,查询

    这种绑定暂时支持单表,并且不支持主键自增长!保存,删除,查看,修改用框架现成的. 1.先生成tb.bll.dal三个类.框架有生成工具,在debug文件里面有个叫CSFramework.Tools.C ...

  10. Linux&&num;160&semi;学习笔记之超详细基础linux命令&&num;160&semi;Part&&num;160&semi;4

    Linux学习笔记之超详细基础linux命令 by:授客 QQ:1033553122 ---------------------------------接Part 3----------------- ...