核心版本:2.6.34
實現思路:
報文在網路通訊協定棧中的流動,對於接收來講,是 對報文的脫殼的過程,由於報文是已知的輸入,只要逐個解析協議號;對於發送來講,是各層發送函數的嵌套調用,由於沒有已 知的輸入,只能按事先設計好的協議進行層層構造。但無論報文怎樣的流動,核心是報文所在裝置(skb->dev)的變化,相當 於各層之間傳遞的交接棒。
按照上述思路,brcm協議接收的處理作為模組brcm_packet_type加入 到ptype_base中就可以了;brcm協議發送的處理則複雜一點,發送的嵌套調用完全是依賴於裝置來推動的,因此要有一種新建立 的裝置X,插入到vlan裝置和網卡裝置之間。
因此,至少要有brcm_packet_type來加入ptype_base和register_brcm_dev() 來向系統註冊裝置X。進一步考慮,裝置X在全域量init_net中有儲存,但我們還需要知道裝置X與vlan裝置以及網卡裝置是何種 組織關係,所以在這裡設計了brcm_group_hash來儲存這種關係。為了對裝置感興趣的事件作出響應,添加自己的notifier到 netdev_chain中。另外,為了使用者空間具有一定控制能力(如建立、刪除),還需要添加brcm相關的ioctl調用。為了讓它看起來 更完整,一種新的裝置在proc中也應有對應項,用來調試和查看裝置。
從最簡單開始
要 讓網路通訊協定棧能夠接收一種新協議是很簡單的,由於已經有報文作為輸入,我們要做的僅僅是編寫好brcm_packet_type,然後在 註冊模組時只用做一件事:dev_add_pack。
static int __init brcm_proto_init(void){ dev_add_pack(&brcm_packet_type); }static struct packet_type brcm_packet_type __read_mostly = { .type = cpu_to_be16(ETH_P_BRCM), .func = brcm_skb_recv, /* BRCM receive method */ }; int brcm_skb_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev) { struct brcm_hdr *bhdr; struct brcm_rx_stats *rx_stats; skb = skb_share_check(skb, GFP_ATOMIC); if(!skb) goto err_free; bhdr = (struct brcm_hdr *)skb->data; rcu_read_lock(); skb_pull_rcsum(skb, BRCM_HLEN); // set protocol skb->protocol = bhdr->brcm_encapsulated_proto; // reorder skb skb = brcm_check_reorder_header(skb); if (!skb) goto err_unlock; netif_rx(skb); rcu_read_unlock(); return NET_RX_SUCCESS; err_unlock: rcu_read_unlock(); err_free: kfree_skb(skb); return NET_RX_DROP; }
註冊這個模組後,協議棧就能正常接收帶brcm前序的報文的,代碼中ETH_P_BRCM是brcm的協議號,BRCM_HLEN是brcm 的前序長度。正是由於有報文作為輸入,接收變得十分簡單。
但這僅僅是能接收而已,發送的報 文還是不帶brcm前序的,而且接收的這段代碼也很粗略,沒有變更skb的裝置,沒有記錄流量,沒有對brcm前序作有意義的處理 ,下面逐一進行添加。