1、Linux网络子系统

网络子系统采用分层的结构:

我们这里研究内核空间即可,在内核空间分成5层,分别是:

1、系统调用接口,它面向的客户是应用层序,为应用程序提供访问网络子系统的统一方法,比如说socket,send等函数的系统调用

2、协议无关接口,它提供通用的方法来使用传输层协议,把所有的协议统一起来

3、网络协议,它的作用就是实现具体的网络协议

4、设备无关接口,这个接口是为了屏蔽底层硬件的差异

5、设备驱动,这里实现具体的网卡驱动

2、重要的数据结构

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

char name[IFNAMSIZ]
设备名,如:eth%d

unsigned long base_addr
I/O 基地址

const struct net_device_ops *netdev_ops;

类似于字符设备驱动中的file_operations结构,net_device_ops结构记录了网卡所支持的操作,当用户使用网络传输数据时,内核就会找到这些操作函数来实现具体的硬件操作,比如说DM9000的操作函数是如下的:
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,
};

这里还有另外一个重要的结构,sk_buff。在应用程序发送数据时,数据包在内核空间中传递,由上到下或者由下到上,这个时候必须使用一个结构来描述这种数据包,sk_buf起到的作用就是这个。

Linux内核中的每个网络数据包都由一个套接字缓冲区结构 struct sk_buff 描述,即一个sk_buff结构就是一个网络包,指向sk_buff的指针通常被称做skb。在这个结构中有这4个成员:

1、head,包头

2、data,数据起始位置

3、tail,数据结尾的位置

4、end,包尾

3、网卡驱动架构分析

我们这里分析CS8900这个网卡驱动,这个分析过程主要分为3步

1、网卡初始化分析

2、数据发送分析

3、数据接收分析

1、网卡初始化分析

初始的第一项工作是分配一个net_device结构:

struct net_device *dev = alloc_etherdev(sizeof(struct net_local));

第二项工作就是初始化这个结构:

dev->irq = irq;
dev->base_addr = io;

在这里完成中断号和设备基地址的初始化。

第三项工作就是调用cs89x0_probe1完成其他的初始化:

1、初始化MAC地址

2、初始化netdev_ops操作集函数

3、初始化硬件

4、注册网卡驱动

2、数据发送分析

怎么寻找发送数据的函数呢?联系上面的netdev_ops结构可以知道,我们可以去这里找:

static const struct net_device_ops net_ops = {.ndo_open     = net_open,.ndo_stop       = net_close,.ndo_tx_timeout        = net_timeout,.ndo_start_xmit  = net_send_packet,.ndo_get_stats       = net_get_stats,.ndo_set_multicast_list = set_multicast_list,.ndo_set_mac_address     = set_mac_address,
#ifdef CONFIG_NET_POLL_CONTROLLER.ndo_poll_controller   = net_poll_controller,
#endif.ndo_change_mtu       = eth_change_mtu,.ndo_validate_addr    = eth_validate_addr,
};

ndo_start_xmit对应的函数net_send_packet应该就是网卡发送函数了。

static netdev_tx_t net_send_packet(struct sk_buff *skb,struct net_device *dev)
{struct net_local *lp = netdev_priv(dev);unsigned long flags;if (net_debug > 3) {printk("%s: sent %d byte packet of type %x\n",dev->name, skb->len,(skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);}/* keep the upload from being interrupted, since weask the chip to start transmitting before thewhole packet has been completely uploaded. */spin_lock_irqsave(&lp->lock, flags);netif_stop_queue(dev);/* initiate a transmit sequence */writeword(dev->base_addr, TX_CMD_PORT, lp->send_cmd);writeword(dev->base_addr, TX_LEN_PORT, skb->len);/* Test to see if the chip has allocated memory for the packet */if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {/** Gasp!  It hasn't.  But that shouldn't happen since* we're waiting for TxOk, so return 1 and requeue this packet.*/spin_unlock_irqrestore(&lp->lock, flags);if (net_debug) printk("cs89x0: Tx buffer not free!\n");return NETDEV_TX_BUSY;}/* Write the contents of the packet */writewords(dev->base_addr, TX_FRAME_PORT,skb->data,(skb->len+1) >>1);spin_unlock_irqrestore(&lp->lock, flags);dev->stats.tx_bytes += skb->len;dev_kfree_skb (skb);/** We DO NOT call netif_wake_queue() here.* We also DO NOT call netif_start_queue().** Either of these would cause another bottom half run through* net_send_packet() before this packet has fully gone out.  That causes* us to hit the "Gasp!" above and the send is rescheduled.  it runs like* a dog.  We just return and wait for the Tx completion interrupt handler* to restart the netdevice layer*/return NETDEV_TX_OK;
}

这里首先调用

netif_stop_queue

,这个函数用于告诉上层协议栈,暂停往网卡中发送数据。
然后开始将skb中的数据写入寄存器:

 /* initiate a transmit sequence */writeword(dev->base_addr, TX_CMD_PORT, lp->send_cmd);writeword(dev->base_addr, TX_LEN_PORT, skb->len);/* Test to see if the chip has allocated memory for the packet */if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {/** Gasp!  It hasn't.  But that shouldn't happen since* we're waiting for TxOk, so return 1 and requeue this packet.*/spin_unlock_irqrestore(&lp->lock, flags);if (net_debug) printk("cs89x0: Tx buffer not free!\n");return NETDEV_TX_BUSY;}

数据发送完之后,什么时候告诉上层可以继续发送数据呢?其实我们应该想到应该在中断里通知上层协议可以给网卡发送数据了。

3、数据接收分析

接收数据一般在中断中进行的。找到static irqreturn_t net_interrupt(int irq, void *dev_id)这个函数。这里面实现对各种中断的处理,比如说接收数据中断:

     case ISQ_RECEIVER_EVENT:/* Got a packet(s). */net_rx(dev);break;

这里调用net_rx,因此我们主要分析这个函数。这里面的实现流程如下:

1、读取接收状态寄存器

2、读取接收的长度

status = readword(ioaddr, RX_FRAME_PORT);
length = readword(ioaddr, RX_FRAME_PORT);

3、构造一个skb

/* Malloc up new buffer. */
skb = dev_alloc_skb(length + 2);

4、然后将受到的数据填入skb包。

skb_reserve(skb, 2);

5、最后把skb包交给上层协议栈

netif_rx(skb);

Linux网卡驱动(1)-网卡驱动架构分析相关推荐

  1. arm平台linux的ethtool配置,ARM-Linux驱动--DM9000网卡驱动分析(四)

    原标题:ARM-Linux驱动--DM9000网卡驱动分析(四) 硬件平台:FL2440 (S3C2440) 内核版本:2.6.35 主机平台:Ubuntu 11.04 内核版本:2.6.39 交叉编 ...

  2. linux无线usb网卡,Linux下USB无线网卡WL-167G驱动安装过程

    最近经过前期调研选定网卡,又折腾一两天,终于搞定了Linux下的无线网卡,对遇到的问题进行了分析,并整理了下详细过程,现与大家分享,还有更具体的开发文档,有需要的可以联系下一步工作要将其移植到ARM平 ...

  3. linux 服务器 安装网卡驱动,linux下安装编译网卡驱动的方法

    安装linux操作系统后发现没有网卡驱动,表现为 system → Administration → Network下Hardware列表为空. 以下为安装编译网卡驱动的过程,本人是菜鸟,以下是我从网 ...

  4. linux+网卡驱动社区,Linux下如何确定网卡所使用的驱动程序

    有些时候你可能想知道某个Linux系统的网卡正在使用什么驱动程序,下面简单介绍下如何解决这个问题. 1. 无论是集成网卡还是独立的网卡,都必须通过某种方式连接到PCI总线上,这样的话,必定有有一个代号 ...

  5. 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】PowerPC + Linux2.6.25平台下的I2C驱动架构分析

    PowerPC + Linux2.6.25平台下的I2C驱动架构分析 Sailor_forever  sailing_9806#163.com (本原创文章发表于Sailor_forever 的个人b ...

  6. 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】PowerPC + Linux2.6.25平台下的SPI驱动架构分析

    PowerPC + Linux2.6.25平台下的SPI驱动架构分析 Sailor_forever  sailing_9806#163.com (本原创文章发表于Sailor_forever 的个人b ...

  7. linux下安装编译网卡驱动

    安装linux操作系统后发现没有网卡驱动,表现为 system → Administration → Network下Hardware列表为空. 以下为安装编译网卡驱动的过程,本人是菜鸟,以下是我从网 ...

  8. r8169驱动下载linux,CentOS自带R8169驱动与R8168网卡之间的烦恼

    前几周我装了5台高性能PC机用来性能测试,网卡是板载的并没有太在意.这周开始做测试了,开始跑测试程序的时候总出问题,没跑一会儿服务器就卡死了.开始开发的同事以为是测试程序的问题,开始从头到尾找问题(多 ...

  9. Linux(Ubuntu)下WiFi网卡(intel ax201)驱动与Nvidia显卡驱动冲突的解决办法

    Linux(Ubuntu)下WiFi网卡(intel ax201)驱动与Nvidia显卡驱动冲突的解决办法 环境: 系统 Ubuntu 22.04 LTS 网卡ax201(微星b660m迫击炮wifi ...

最新文章

  1. 2018-2019-1 20165214 《信息安全系统设计基础》第六周学习总结
  2. 脑机接口创造“第六感”:激活特定神经元,大鼠训练出新感官,逃出水迷宫,像用视觉一样轻松...
  3. Ubuntu14升级MySQL
  4. GIMP用Path作画了解一下
  5. [导入]一个asp中关于execute的测试
  6. 手机新趋势:智能大屏
  7. swift中闭包的循环引用
  8. jquery 多个class操作
  9. 外贸自建站优势渐明,你还要观望多久!2018加油
  10. 在shell中向应用程序的socket发送信息
  11. ttys和tty_Linux中tty、pty、/dev/ttySn等概念讲解
  12. 新建git分支(歪门邪道)
  13. 联想k860i 去掉相机和开关机的声音
  14. BZOJ2754: [SCOI2012]喵星球上的点名(AC自动机/后缀自动机)
  15. Windows Phone 8.1中ScrollViewer(一)
  16. 笔记本插网线无法联网解决方法
  17. 软件工程与计算II - 软件工程的发展
  18. 2022年煤气考试题库及在线模拟考试
  19. PhysX SDK 编译
  20. 微信小程序 长按图片不出现菜单_微信小程序长按保存图片

热门文章

  1. H.265高清网络编码器在视频网站中的应用
  2. 拼音分词器多音字处理
  3. WPS和office有什么不同
  4. 【python】本地音乐播放器(PyQt5界面版)
  5. “普信男”威马能靠IPO翻身吗?
  6. PAT 甲级 1011 World Cup Betting
  7. QBASIC在win8-64位系统中的编译及运行
  8. 物流企业对计算机网络技术的投资,计算机网络技术在现代物流中的应用探究.doc...
  9. 点歌服务器怎么查看系统报错,网乐活动大师常见问题大全2017
  10. VMware虚拟化- VSphere vCenter 虚拟交换机理论及应用