ethernet_input到应用层处理简单分析
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 数据报,传递到传输层 |