網絡協定棧設計(三)
本篇将給大家帶來網絡協定棧設計的資料鍊路層以太網設計。
前邊介紹過我們負責發送方代碼編寫,那麼,先看看在資料鍊路層的工業以太網中,我們發送方需要做哪些事情。
要求:
主要設計和實作一個可以通信的資料鍊路層
(1)發送資料:網卡初始化,擷取句柄,将資料幀封裝,發送。
(2)接收資料:資料幀接收,并判斷資料幀來源且完成CRC校驗等檢查最後傳資料部分給上層協定
我們将發送和接收分兩步分完成,這裡我們先讨論發送資料。
我們先來看看工業以太網幀格式:
前導碼:01111110(逢5加0, 逢5删0)
目的MAC位址:接收方的MAC位址,占6個位元組
源MAC位址:本地的MAC位址,占6個位元組
類型: ICMPv4 ,IGMP, IPv4,ARP; ICMP v4, IPv6等,占2個位元組
資料: 由上層傳遞。(46~1500個位元組)
校驗字段: 32比特位CRC校驗
注:我們在此不讨論前導碼,因為前導碼由網卡自動完成,僅僅是為了同步發送方和接收方,提醒接收方準備接受資料,并不屬于以太網MAC幀的内容。
經過分析我們可以先得到我們的發送流程圖如下:
Q&A:
看完資料流程圖,可能小夥伴就要問了,為什麼要控制資料最小為46個位元組,最長為1500個位元組?
因為在總線型網絡中資料發送存在碰撞,是以資料鍊路層采用CSMA/CD協定來保證資料的正常發送。是以,以太網規定了一個最短幀長64位元組,凡長度小于64位元組的幀都是由于沖突而異常終止的無效幀。是以,我們以太網幀首部長14位元組(這裡不算前導碼,它并不真正屬于我們的資料幀)加上4個位元組的校驗碼,資料部分最少為46位元組。關于最長1500位元組,我們知道,在IP層下面的每一種資料鍊路層協定都規定了一個資料幀中的資料字段的最大長度,這稱為最大傳送單元MTU。最常用的以太網就規定其MTU的值是1500位元組。看到這裡還是不太懂的小夥伴就需要好好去看書了。
有了上邊的資料流程圖和相關知識,我們開始設計我們以太網。
1、首先是資料結構的設計。
我們需要一個以太網首部結構:
struct ethernet_header
{
u_int8_t destination_mac[];
u_int8_t source_mac[];
u_int16_t ethernet_type;
};
封裝MAC幀資料我們需要一個數組來儲存:
u_int8_t buffer[MAX_SIZE];
2、接下來是函數設計。
封裝的過程我們簡單描述為:
1、加載MAC幀首部
2、加載MAC資料部分
3、加載CRC檢驗碼部分
我們将以上過程分别以一個函數來完成:
1、首先需要加載MAC幀首部,源MAC位址由我們定義的全局變量local_mac[6]直接得到,目的MAC位址則由上層傳遞,上層協定也由上層傳遞,傳回值為空。
void load_ethernet_header(u_int8_t *destination_mac,u_int16_t ethernet_type)
2、加載資料部分,加載的資料由上層協定提供,上層也提供一個傳遞的資料長度,傳回值為int,加載失敗傳回-1。
int load_ethernet_data(u_int8_t *buffer, u_int8_t *upper_buffer, int len)
在此函數中,我們要檢查若len的長度大于1500位元組,則直接丢棄,傳回-1,否則若少于46個位元組,則在資料部分填充0至最少46位元組。
3、加載CRC校驗碼。
這裡我們将計算CRC校驗碼獨立作為一個函數,傳回4個位元組的校驗碼。然後将傳回值複制到我們的資料部分末尾。然後調用和複制包含在加載資料函數中。
u_int32_t calculate_crc(u_int8_t *buffer, int len)
至此,我們的資料幀就算封裝完成了,我們将上邊三個函數整合為上層協定直接調用的發送函數:
那麼上層需要提供的有:一個目的MAC位址,以太網上層協定類型,以及需要發送的資料。待發送的資料長度我們可以用前邊全局變量定義中的ethernet_upper_len來得到。
發送函數設計為:
int ethernet_send_packet(u_int8_t *upper_buffer,u_int8_t *destination_mac,u_int16_t ethernet_type)
{
加載首部;
加載資料,如果加載資料失敗傳回-;
調用winpcap的發送函數pcap_sendpacket()發送;
}
好了,關于以太網發送資料的分析我們就做這些,下一篇為大家帶來設計的細節完善和代碼的具體實作。