学習Linuxドライバ(4) - ネットワーク・デバイス・ドライバ

(A)アーキテクチャ

必要な知識ポイント:

1. Linuxをスタックレベル
2 Linuxのネットワークサブシステムアーキテクチャ

(B)プロトコルスタック

Linuxのの利点の一つは、それが豊かで安定したネットワーク・プロトコル・スタックであるということです。様々な特定のネットワークプロトコルに依存しない層のプロトコル(例えば、一般的なソケット層インターフェースまたはデバイス層)の範囲。

プロトコルの概要

ネットワーク理論の導入に一般的に使用さOSI(開放型システム間相互接続)モデルが、Linuxネットワークスタックを導入するために、一般的にインターネットモデルの4層に分かれています。

 

ネットワークインタフェースレイヤ

データリンクと物理層とネットワークインタフェース層は、一緒に結合された物理デバイスドライバへのアクセスを提供し、ネットワークプロトコルは、主にイーサネット・プロトコルに対応します

インターネット層

このようなIPプロトコルなどのネットワーク層プロトコル離散管理コンピュータとの間のデータ伝送が正しく、そのパケットの宛先マシンを確実にするために、リモートコンピュータとユーザーにパケットを送信するための方法を提供します。重要なネットワーク層プロトコルARP(アドレス解決プロトコル)、ICMP(インターネット制御メッセージプロトコル)プロトコルとIP(インターネット・プロトコル)

トランスポート層

機能トランスポート層であって、情報の流れをフォーマットする信頼性の高い伝送を提供します。トランスポート層は、主トランスポート層プロトコルであるTCP(伝送制御プロトコル、伝送制御プロトコル)およびUDP(ユーザデータグラムプロトコル、ユーザデータグラムプロトコル)を含みます。

アプリケーション層

上部のプロトコルスタックのアプリケーション層は、その主なタスクは、FTP(ファイル転送プロトコル)ファイル転送と同様に、アプリケーションを提供することです。一般的なアプリケーション層プロトコルは、以下のとおりです。HTTP、FTP、Telnetおよびように。アプリケーション層は、Linuxのネットワーク構成は、重要な層、アプリケーション層プロトコルを目的としたLinuxのサーバー設定文書です。

(C)Linuxのネットワークサブシステム

トップLinuxネットワークサブシステムは、システムコールインターフェース層です。これは、ユーザー空間のアプリケーションのためのアクセス・コア・ネットワーク・サブシステムへの道を提供します。それはプロトコルに依存しない層である下に、それはトランスポート層プロトコルを使用する一般的な方法を提供します。そして、それはLinuxの組み込みプロトコルTCP、UDP、そしてもちろんIPに含まれ、具体的な契約を締結し、達成することです。次いで、デバイスドライバと通信するための共通のインタフェース・プロトコルを提供する装置に依存しない層、デバイスドライバが最下位であります

系统调用接口

为应用程序提供访问内核网络子系统的方法:Socket系统调用。

协议无关接口

实现一组通用函数来访问各种不同的协议:通过socket实现。Linux 中的 socket 使用struct sock来描述,这个结构包含了特定socket 所需要的所有状态信息,还包括socket 所使用的特定协议和在 socket 上可以执行的一些操作。

网络协议

网络协议层用于实现各种具体的网络协议,如: TCP、UDP 等。

设备无关接口

设备无关接口将协议与各种网络设备驱动连接在一起。这一层提供一组通用函数供底层网络设备驱动程序使用,让它们可以对高层协议栈进行操作。首先,设备驱动程序可能会通过调用 register_netdevice 或unregister_netdevice 在内核中进行注册或注销。调用者首先填写 net_device 结构,然后传递这个结构进行注册。内核调用它的 init 函数(如果定义了这种函数),然后执行一组健全性检查,并将新设备添加到设备列表中(内核中的活动设备链表)。

要从协议层向设备发送数据,需要使用dev_queue_xmit函数,这个函数对数据进行排队,并交由底层设备驱动程序进行最终传输报文的接收通常是使用netif_rx 执行的。当底层设备驱动程序接收到一个报文(包含在所分配的sk_buff中)时,就会通过调用 netif_rx 将 数据上传至设备无关层,然后,这个函数通过 netif_rx_schedule将 sk_buff 在上层协议队列中进行排队,供以后进行处理。

驱动程序

网络体系结构的最底部是负责管理物理网络设备的设备驱动程序层

(四)网卡驱动设计

设备描述

每个网络接口都由一个net_device结构来描述, 该结构可使用如下内核函数动态分配:
1、struct net_device *alloc_netdev(int sizeof_priv, const char *mask, void (*setup)(struct net_device *))
sizeof_priv 私有数据区大小; mask:设备名; setup 初始化函数
2、struct net_device *alloc_etherdev(int sizeof_priv)

net_device

结构 net_device 的主要成员包括:

    • char name[IFNAMSIZ] 设备名,如:eth%d
    • unsigned long state 设备状态
    • unsigned long base_addr I/O 基地址
    • unsigned int irq 中断号

int (*init)(struct net_device *dev)
初始化函数。该函数在register_netdev时被调用来完成对 net_device 结构的初始化

和字符驱动一样, 网络设备也要声明能操作它的函数。有些操作可以保留为 NULL, 有的可以通过 ether_setup 来使用默认设置。网络接口的设备方法可分为两组:基本的和可选的,基本方法包括那些使用接口所必需的;可选的方法实现更多高级的功能。

基本方法

int (*open)(struct net_device *dev)
打开接口。ifconfig 激活时,接口将被打开。
int (*stop)(struct net_device *dev)
停止接口。该什么时候调用呢?
int (*hard_start_xmit) (struct sk_buff *skb, struct net_device *dev)
数据发送函数

可选操作

int (*do_ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd)
处理特定于接口的 ioctl 命令
int (*set_mac_address)(struct net_device *dev, void *addr)
改变Mac地址的函数,需要硬件支持该功能

设备注册

网络接口驱动的注册方式与字符驱动不同之处在于它没有主次设备号,并使用如下函数注册。
int register_netdev(struct net_device *dev)

sk_buff

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

      • struct device *dev; //处理该包的设备
      • __u32 saddr; //IP源地址
      • __u32 daddr; //IP目的地址
      • __u32 raddr; //IP路由器地址
      • unsigned char *head; //分配空间的开始
      • unsigned char *data; //有效数据的开始
      • unsigned char *tail; //有效数据的结束
      • unsigned char *end; //分配空间的结束
      • unsigned long len; //有效数据的长度

Skb操作函数

操作sk_buff的内核函数如下
struct sk_buff *alloc_skb(unsigned int len, int priority)
分配一个sk_buff 结构,供协议栈代码使用

struct sk_buff *dev_alloc_skb(unsigned int len)
分配一个sk_buff 结构,供驱动代码使用

unsigned char *skb_push(struct sk_buff *skb, int len)
向后移动skb的tail指针,并返回tail移动之前的值。函数常用来:

unsigned char *skb_put(struct sk_buff *skb, int len)
向前移动skb的head指针,并返回head移动之后的值。函数常用来:

kfree_skb(struct sk_buff *skb)
释放一个sk_buff 结构,供协议栈代码使用

dev_kfree_skb(struct sk_buff *skb)
释放一个sk_buff 结构,供驱动代码使用

设备打开

int net_open(struct net_device *dev)
{
  /*申请中断*/
  request_irq(dev->irq, &net_interrupt, SA_SHIRQ,“dm9000”, dev);
  /* 设置寄存器,启动设备 */
  ...... ...... ...... ......
  /*启动发送队列*/
  netif_start_queue(dev);
}

数据发送

当核心需要发送一个数据包时,它调用hard_start_transmit函数,该函数将最终调用到net_device结构中的hard_start_xmit函数指针。

数据接收

网络接口驱动可以实现两种方式的报文接收:
中断查询,Linux中驱动多采用中断方式。

接收流程

1、分配Skb
  skb = dev_alloc_skb(pkt->datalen + 2)
2、从硬件中读取数据到Skb
3、调用netif_rx将数据交给协议栈
  netif_rx(skb)

中断处理

网络接口通常支持3种类型的中断: 新报文到达中断、报文发送完成中断和出错中断。中断处理程序可通过查看网卡中的中断状态寄存器,来分辨出中断类型。

(五)DM9000网卡驱动分析

芯片介绍

DM9000是开发板经常采用的网络芯片,是一种高度集成而且功耗很低的高速网络控制器,可以和CPU直连,支持10/100M以太网连接,芯片内部自带16K的SRAM(3KB用来发送,13KB用来接收)
Dm9000在收到由上层发来的以太网帧后,开始侦听网络线路,如果线路忙,就等到线路空闲为止,否则立即发送该数据帧。接收时,它将从以太网收到的数据包在经过解码、去掉帧头和地址检验等步骤后缓存在片内。在CRC校验通过后, 它会通知CPU收到了数据帧

おすすめ

転載: www.cnblogs.com/WenLee/p/12116369.html