Linux網絡子系統
系統調用接口層:
爲應用程序提供訪問網絡子系統的統一方法。
協議無關層:
提供通用的方法來使用傳輸層協議,對不同的協議有統一的接口。
協議棧的實現:
實現具體的網絡協議。
設備無關層:
協議與設備驅動之前通信的通用接口,對於不同的網絡通信設備有統一的接口。
重要的數據結構
網卡描述結構:
在Linux內核中,每個網卡都由一個 net_device結構 來描述,其中的一些重要成員有:
網卡操作集合:
類似於字符設備驅動中的file_operations結構, net_device_ops結構 記錄了網卡所支持的操作。
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,
};
網絡數據包:
Linux內核中的每個網絡數據包都由一個套接字緩衝區結構 struct sk_buff 描述,即一個 sk _ buff 結構就是一個網絡包,指向sk_buff 的指針通常被稱做skb 。
網卡驅動模型
網卡初始化:
數據發送:
數據接收:
迴環網卡驅動設計
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/if_ether.h> /* For the statistics structure. */
unsigned long bytes = 0;
unsigned long packets = 0;
static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
//數據發送函數,skb是數據包
{
//對於迴環網卡,不需要暫停和重啓協議棧發送數據,也不需要寫入和釋放skb
skb->protocol = eth_type_trans(skb,dev);//標明協議
bytes += skb->len;//數據量
packets++; //包的數目
netif_rx(skb); //將包發走
return 0;
}
static struct net_device_stats *loopback_get_stats(struct net_device *dev)
//獲取網卡狀態信息
{
struct net_device_stats *stats = &dev->stats;
stats->rx_packets = packets;
stats->tx_packets = packets;
stats->rx_bytes = bytes;
stats->tx_bytes = bytes;
return stats;
}
//定義ops結構
static const struct net_device_ops loopback_ops = {
.ndo_start_xmit= loopback_xmit, //發送函數
.ndo_get_stats = loopback_get_stats, //獲取網卡狀態
};
static void loopback_setup(struct net_device *dev)
//2、初始化net_device結構
{
dev->mtu = (16 * 1024) + 20 + 20 + 12; //網卡能接受的包的最大尺寸,16K數據+tcp頭+ip頭+以太網頭
dev->flags = IFF_LOOPBACK; //迴環網卡專有標誌
dev->header_ops = ð_header_ops; //構造頭的函數,系統已經提供
dev->netdev_ops = &loopback_ops; //迴環網卡的操作集
}
/* Setup and register the loopback device. */
static __net_init int loopback_net_init(struct net *net) //入口函數
{
struct net_device *dev;
//1、分配 net_device 結構 2、初始化 net_device 結構
dev = alloc_netdev(0, "lo", loopback_setup);
//3、迴環網卡沒有硬件結構,不需要初始化硬件
//4、註冊網卡驅動
register_netdev(dev);
net->loopback_dev = dev;
return 0;
}
static __net_exit void loopback_net_exit(struct net *net)//出口函數
{
struct net_device *dev = net->loopback_dev;
unregister_netdev(dev); //註銷 dev 結構
}
/* Registered in net/core/dev.c */
struct pernet_operations __net_initdata loopback_net_ops =
{
.init = loopback_net_init,
.exit = loopback_net_exit,
};
DM9000網卡驅動設計
參考內核源代碼:linux-ok6410\drivers\net\dm9000.c
和 linux-ok6410\drivers\net\dm9000.h
DM9000網卡 數據發送 代碼:
//dm9000芯片的發送數據代碼
static int dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
board_info_t *db = netdev_priv(dev);
//1、通知協議棧,暫停向驅動發送數據
netif_stop_queue(dev);
//2、將skb中的數據寫入寄存器
iow(db, DM9000_TXPLL, skb -> len);
iow(db, DM9000_TXPLH, skb -> len >> 8);
writeb(DM9000_MWCMD, db->io_addr);
(db->outblk)(db->io_data, skb->data, skb->len);
iow(db, DM9000_TCR, TCR_TXREQ);
//3、釋放skb
dev_kfree_skb(skb);
//4、通知協議棧繼續發送數據,在中斷處理函數中寫,不在這個函數中
return 0;
}