1、驅動層:從硬件讀取數據并構造pbuf
中斷觸發后,驅動層的接收任務(或輪詢函數)會從網卡硬件讀取數據,并將其封裝為 LWIP 可識別的pbuf
結構體(LWIP 的數據緩沖區)。
關鍵函數:
- 驅動自定義的接收函數(如
eth_rx_task
):負責從網卡寄存器或 DMA 緩沖區讀取原始數據。 pbuf_alloc
:分配pbuf
緩沖區,用于存儲接收到的數據幀。
示例:
void eth_rx_task(void *arg) {struct netif *netif = (struct netif *)arg;while (1) {// 等待中斷通知(信號量)sys_sem_wait(ð_rx_sem, 0);// 從網卡讀取數據長度和內容uint8_t *data = eth_hw_read(&len);// 分配pbuf并復制數據struct pbuf *p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);if (p != NULL) {memcpy(p->payload, data, len);// 調用netif的linkoutput對應的接收回調(見步驟3)netif->input(p, netif); // 核心:將數據送入協議棧}} }
- 驅動自定義的接收函數(如
2. 調用input
函數:進入 LWIP 協議棧
驅動層構造好pbuf
后,會直接調用netif->input(p, netif)
,將數據幀送入協議棧。對于以太網,input
被賦值為ethernet_input
,其作用是解析以太網幀頭,根據協議類型(如 IP、ARP)分發到對應模塊。
ethernet_input
的核心邏輯:err_t ethernet_input(struct pbuf *p, struct netif *netif) {struct eth_hdr *ethhdr;// 提取以太網幀頭(目的MAC、源MAC、協議類型)ethhdr = (struct eth_hdr *)p->payload;// 根據協議類型分發:switch (htons(ethhdr->type)) {case ETHTYPE_IP:// 移除以太網幀頭,將IP數據報送入IP層pbuf_remove_header(p, sizeof(struct eth_hdr));return ip4_input(p, netif); // 進入IP層處理case ETHTYPE_ARP:// ARP報文交給ARP模塊處理return arp_input(p, netif);default:pbuf_free(p);return ERR_OK;} }
后續流程:
- IP 層(
ip4_input
)會解析 IP 頭,根據協議字段(如 TCP、UDP)將數據傳遞到傳輸層。 - 最終數據會通過
socket
接口或回調函數交付給應用層。
- IP 層(
3、初始化關聯:input
函數
input
函數在網絡接口初始化時被綁定,具體是在調用netif_add
時指定的,流程如下:
應用層調用
netif_add
:
第三個參數input
通常傳入ethernet_input
(以太網):struct netif eth_netif; netif_add(ð_netif, &ipaddr, &netmask, &gw, NULL, eth_init, ethernet_input);
netif_add
函數內部賦值:
在netif_add
中,將傳入的input
函數指針保存到netif
結構體:netif->input = input; // input即ethernet_input
驅動層調用
netif->input
:
如步驟 2 的eth_rx_task
所示,驅動接收數據后,通過netif->input(p, netif)
觸發協議棧處理。
4、關鍵接口總結
環節 | 核心函數 / 變量 | 作用 |
---|---|---|
硬件中斷 | eth_isr | 觸發數據接收事件,通知驅動層 |
驅動層數據讀取 | eth_rx_task (自定義) | 從硬件讀取數據,構造pbuf |
協議棧入口 | netif->input | 指向ethernet_input ,作為數據入口點 |
以太網幀解析 | ethernet_input (LWIP 提供) | 解析以太網幀,分發到 IP/ARP 模塊 |
網絡層處理 | ip4_input | 處理 IP 數據報,傳遞到傳輸層 |