# 802.3 - Ethernet Frame
[TOC]
## 課程影片
### 第 2E 講 IEEE 802.3 乙太網路 (Ethernet) L02
{%youtube 6TV9UBGwISE %}
### [Python Network Packet Sniffer Tutorial - 1 - Introduction](https://youtu.be/WGJC5vT5YJo)
{%youtube WGJC5vT5YJo %}
### [Python Network Packet Sniffer Tutorial - 2 - Formatting MAC Address](https://youtu.be/jVwvOZfAGNk)
{%youtube jVwvOZfAGNk %}
### [Python Network Packet Sniffer Tutorial - 3 - Capturing Traffic](https://youtu.be/dM9grWOdTBI)
{%youtube dM9grWOdTBI %}
## Ethernet Frame

當中各個欄位的定義,除了紀錄在 802.3 的規格中之外,一個實際出現的地方是 *Linux* 核心中 [`include/uapi/linux/if_ether.h`](https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/if_ether.h#L32) 定義的各個常數:
```c
#define ETH_ALEN 6 /* Octets in one ethernet addr */
#define ETH_TLEN 2 /* Octets in ethernet type field */
#define ETH_HLEN 14 /* Total octets in header. */
#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */
#define ETH_DATA_LEN 1500 /* Max. octets in payload */
#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */
#define ETH_FCS_LEN 4 /* Octets in the FCS */
```
而 DA、SA 與 Type 三者合起來又稱為 *ethernet header*,*Linux* 核心對應的結構體則是 `struct ethhdr`:
```c
struct ethhdr {
unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
unsigned char h_source[ETH_ALEN]; /* source ether addr */
__be16 h_proto; /* packet type ID field */
} __attribute__((packed));
```
## Preamble (56 位元)
「前奏」的意思。前 56 個位元。這 56 個位元是 0 與 1 交錯。這是用來做提示與校正,當看到 *bus* 上出現不斷交錯的 0 與 1 時,就會知道可能有傳輸會發生。除此之外,由 0 與 1 的變化速度,也可以作為傳輸速度的同步。
## SFD (8 位元)
*Start frame delimeter*,區隔 *preamble* 與接下來的內容,表示傳輸即將開始。
## DA 與 SA (48 + 48 位元)
接收端與發送端的 **MAC Address**。*MAC address* 是一個 48 位元的位址,一張網路卡(*adaptor*)會有唯一的 *MAC address*。這 48 位元的表示法通常每 8 個位元以分號區隔,並且用 16 進位表示。而這 48 個位元的前 24 個位元,用來識別這個網卡的供應商。比如說 AMD 是 `8:0:20`。
### Unicast
要注意的是:傳輸一個 *frame* 傳遞到 *bus* 上時會使用廣播的機制,因此所有與這個 *bus* 連接的設備都看得到這個 *frame*。而這些設備看到這個 *frame* 之後,就看其中的 DA 來決定是否讀取這個 *frame*。這種傳輸稱為 *unicast*。
### Broadcast
特別地,`ff:ff:ff:ff:ff:ff` 這個 *MAC address* 是用來表示「廣播」(*broadcast*)。當 DA 為這個數值時,表示這個 *frame* 發送給所有與這個 *bus* 連接的設備。
### Multicast
除了 *unicast* 與 *broadcast*,還有介於兩者之間的 *multicast*,表示這個 *frame* 要同時傳送給 *bus* 上的多個裝置。不同設備之間可以形成群組,而不同的群組則是以一個 47 位元的數值作為識別。當 DA 的第一個位元為 `1` 時,就表示「要傳送給剩下 47 個位元所代表的群組中的所有設備」。而一個網卡最多可以加入 32 個群組。
> 因此,一張網卡在看到有 *frame* 出現在 *bus* 上面時,如果有下面三種狀況的其中任一,這個網卡就會把這個 *frame* 收下來:
>
> 1. 當這個 *frame* 的 DA 恰好為自己的 *MAC address* 時。
> 2. 當這個 *frame* 的 DA 為 `ff:ff:ff:ff:ff:ff` 時。
> 3. 當這個 *frame* 的 DA 的第一個位元為 `1`,而且自己恰好在 DA 剩下的 47 位元所代表的群組中的時候。
## Type (16 位元)
表示 *payload* 是哪一個類型的資訊,比如說使用 L3 的哪種協定。
## LLC + PAD (最大 1500 位元組)
真正的資料。這個欄位有範圍限制:
$$
46 \leq LLC + PAD \leq 1500
$$
因此,連同後面的 FCS 算進去,一個乙太網路的 *frame* 至多只會到 1518 個 *byte*,而最短則是 64 *byte*。
## FCS (32 位元)
*frame check sequence*,檢查碼。比如說 CRC 校驗碼等等。