/************************************************************************************html
*本文爲我的學習記錄,若有錯誤,歡迎指正。linux
* http://www.cnblogs.com/xiaojiang1025/archive/2017/03/28/6486267.html
網絡
* https://blog.csdn.net/zdy0_2004/article/details/79234386
數據結構
************************************************************************************/app
Linux網絡設備驅動程序體系結構分爲四層:網絡協議接口層、網絡設備接口層、提供實際功能的設備驅動層以及網絡設備與媒介層。框架
(1)網絡協議接口層ide
網絡協議接口層向網絡層協議提供統一的數據包收發接口,不論上層協議是ARP仍是IP,都經過dev_queue_xmit()函數發送數據,並經過netif_rx()函數接收數據。這一層的存在使得上層協議獨立於具體的設備。函數
(2)網絡設備接口層學習
網絡設備接口層向協議接口層提供的用於描述具體網絡設備屬性和操做的結構體net_device,該結構體是設備驅動功能層各函數的容器。
(3)設備驅動功能層
設備驅動功能層的各函數是網絡設備接口層net_device數據結構的具體成員,是驅使網絡設備硬件完成相應動做的程序,它經過nto_start_xmit()函數啓動發送操做,並經過網絡設備上的中斷觸發接收操做。
(4)網絡設備與媒介層
網絡設備與媒介層完成數據包發送和接收的物理實體,包括網絡適配器和具體的傳輸媒介,網絡適配器被設備驅動功能層中的函數在物理上驅動。
驅動工程師的工做:在設計具體的網絡設備驅動程序時,須要完成的主要工做是編寫設備驅動功能層的相關函數以填充net_device數據結構的內容並將net_device註冊入內核。
(1)struct sk_buff
sk_buff是網絡驅動框架中信息的載體, 是網絡分層模型中對數據進行層層打包以及層層解包的載體。
427 struct sk_buff { 428 /* These two members must be first. */ 429 struct sk_buff *next; //sk_buff是雙向鏈表,因此有前去後繼,這是指向後面的sk_buff結構體指針 430 struct sk_buff *prev; //這是指向前一個sk_buff結構體指針 432 ktime_t tstamp; 434 struct sock *sk; 435 struct net_device *dev; //對應的net_device 443 char cb[48] __aligned(8); 445 unsigned long _skb_refdst; 449 unsigned int len, //表示數據區的長度(tail-data)與分片結構體數據區的長度之和 450 data_len;//只表示分片結構體數據區的長度,因此len=(tail - data) + data_len 451 __u16 mac_len, //mac報頭的長度 452 hdr_len; 473 __be16 protocol;//包的協議類型,標識是IP包仍是ARP包仍是其餘數據包 534 __u16 inner_transport_header; 535 __u16 inner_network_header; 536 __u16 inner_mac_header; 537 __u16 transport_header; //指向傳輸包頭 538 __u16 network_header; //指向傳輸層包頭 539 __u16 mac_header; //指向鏈路層包頭 540 /* These elements must be at the end, see alloc_skb() for details. */ 541 sk_buff_data_t tail; //指向當前數據包的尾地址, 隨着各個網絡層的加工而變化 542 sk_buff_data_t end; //數據緩衝區的結束地址 543 unsigned char *head, //數據緩衝區的開始地址 544 *data; //data指向當前數據包的首地址, 隨着各個網路層的加工而變化 545 unsigned int truesize; 546 atomic_t users; 547 };
(2)struct net_device
Linux內核中使用 net_device 來描述一個網絡設備,net_device是設備接口層的核心, 也是編寫網絡驅動核心的對象。
1160 struct net_device { 1167 char name[IFNAMSIZ];//網絡設備的名稱, 網絡設備被載入後會出如今ifconfig中, 好比默認的eth0就是這個 1179 unsigned long mem_end; //網絡設備所使用的共享內存起始地址 1180 unsigned long mem_start; //網絡設備所使用的共享內存結束地址 1181 unsigned long base_addr; //表示網絡設備的IO基地址 1182 int irq; //設備使用的中斷號 1189 unsigned long state; 1190 1191 struct list_head dev_list; 1192 struct list_head napi_list; 1193 struct list_head unreg_list; 1194 struct list_head close_list; 1210 netdev_features_t features; //用戶層能夠修改的特徵 1212 netdev_features_t hw_features; //用戶層不能修改的特徵 1214 netdev_features_t wanted_features; 1243 const struct net_device_ops *netdev_ops;//網絡設備的操做方法集 1244 const struct ethtool_ops *ethtool_ops; //ethtool的方法集 1245 const struct forwarding_accel_ops *fwd_ops; 1248 const struct header_ops *header_ops; //協議頭操做集 1250 unsigned int flags; /* interface flags (a la BSD) */ 1251 unsigned int priv_flags; /* Like 'flags' but invisible to userspace. 1252 * See if.h for definitions. */ 1253 unsigned short gflags; 1254 unsigned short padded; /* How much padding added by alloc_netdev() */ 1256 unsigned char operstate; /* RFC2863 operstate */ 1257 unsigned char link_mode; /* mapping policy to operstate */ 1259 unsigned char if_port; /* Selectable AUI, TP,..*/ 1260 unsigned char dma; /* DMA channel */ 1262 unsigned int mtu; /* interface MTU value */ 1263 unsigned short type; /* interface hardware type */ 1264 unsigned short hard_header_len; /* hardware hdr length */ 1270 unsigned short needed_headroom; 1271 unsigned short needed_tailroom; 1274 unsigned char perm_addr[MAX_ADDR_LEN]; /* permanent hw address */ 1275 unsigned char addr_assign_type; /* hw address assignment type */ 1276 unsigned char addr_len; /* hardware address length */ 1289 struct kset *queues_kset; 1386 int watchdog_timeo; /* used by dev_watchdog() */ 1480 };
(3)struct net_device_ops
網絡設備的操做方法集。
1002 struct net_device_ops { 1003 int (*ndo_init)(struct net_device *dev); 1004 void (*ndo_uninit)(struct net_device *dev); 1005 int (*ndo_open)(struct net_device *dev);//打開網絡接口設備,得到設備須要的I/O地址、IRQ、DMA通道等 1006 int (*ndo_stop)(struct net_device *dev);//中止網絡接口設備,與open()函數的做用相反 1007 netdev_tx_t (*ndo_start_xmit) (struct sk_buff *skb,struct net_device *dev);//啓動數據包的發送,當系統調用驅動程序的xmit函數時,須要向其傳入一個sk_buff結構體指針,以使得驅動程序能獲取從上層傳遞下來的數據包 1013 void (*ndo_change_rx_flags)(struct net_device *dev,int flags); 1015 void (*ndo_set_rx_mode)(struct net_device *dev); 1016 int (*ndo_set_mac_address)(struct net_device *dev,void *addr);//用於設置設備的MAC地址 1018 int (*ndo_validate_addr)(struct net_device *dev); 1019 int (*ndo_do_ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd);//用於進行設備特定的I/O控制 1021 int (*ndo_set_config)(struct net_device *dev, struct ifmap *map); //用於配置接口,也可用於改變設備的I/O地址和中斷號 1023 int (*ndo_change_mtu)(struct net_device *dev, int new_mtu); 1025 int (*ndo_neigh_setup)(struct net_device *dev,struct neigh_parms *); 1027 void (*ndo_tx_timeout) (struct net_device *dev);//當數據包的發送超時時,ndo_tx_timeout()函數會被調用,該函數需採起從新啓動數據包發送過程或從新啓動硬件等措施來恢復網絡設備到正常狀態 1028 1148 };
(1)分配/釋放net_device
//linux/etherdevice.h /** * 分配及初始化net_device對象() * @sizeof_priv - 私有數據大小(單位:字節數) * 返回值:失敗:NULL, 成功:net_device對象的首地址 */ struct net_device *alloc_etherdev(int sizeof_priv); //linux/netdevice.h /** * 分配及初始化net_device對象 * @int sizeof_priv - 私有數據大小(單位:字節數) * @const char *name - 物理接口名("名稱%d") * @unsigned char name_assign_type - NET_NAME_UNKNOWN * @void (*setup)(struct net_device *) - 初始化函數 * 返回值:失敗:NULL成功:net_device對象的首地址 */ struct net_device *alloc_netdev(int sizeof_priv, const char *name,unsigned char name_assign_type,void (*setup)(struct net_device *)); //釋放 void free_netdev(struct net_device *dev);
(2)以太網的初始化
在初始化一個以太網設備的時候應該被調用, 它的主要做用就是針對以太網標準對net_device對象進行初始化。
void ether_setup(struct net_device *dev);
(3)註冊/註銷net_device
//註冊 int register_netdev(struct net_device *dev); //註銷 void unregister_netdev(struct net_device *dev);
(4)開始/中止發送隊列
//開啓發送隊列 void netif_start_queue(struct net_device *dev) //中止發送隊列 void netif_stop_queue(struct net_device *dev)
中斷處理函數
是網絡設備媒介層相設備驅動功能層發送數據的接口, 網卡接收到數據是經過中斷的方式上報的, 因此網絡驅動中的中斷處理函數就是第一時間隊接收到的數據進行處理的地方,這個函數最終必定要調用netif_rx()將收到的數據上報到協議接口層。
轉載一篇DM9000驅動分析的文章,寫得很是詳細,感謝做者的貢獻。 Linux DM9000網卡驅動程序徹底分析