企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
通过前面的学习,我们知道每个netif接口都需要一个底层接口文件提供访问硬件的支持,而LwIP作者将这种支持做成一个框架供我们参考,如ethernetif.c文件就是实现为一个框架的形式,我们在移植的时候只需要根据实际的网卡特性完善这里面的函数即可,该文件在后文会讲解。框架中的函数名、参数等都已经实现,我们只需往里面填充完善即可,当然,网卡的驱动与这些函数名字我们也可以进行修改,只要LwIP内核能正确识别网卡中的功能即可,为了方便,我们还是使用LwIP作者提供的框架进行移植操作,当一个设备使用了多个网卡的时候,那就需要编写多个不同的网卡驱动。与网卡驱动密切相关的函数有三个,分别是: ``` 1 static void low_level_init(struct netif *netif); 2 static err_t low_level_output(struct netif *netif, struct pbuf *p); 3 static struct pbuf * low_level_input(struct netif *netif); ``` low_level_init()为网卡初始化函数,它主要完成网卡的复位及参数初始化,根据实际的网卡属性进行配置netif中与网卡相关的字段,例如网卡的MAC地址、长度,最大发送单元等。 low_level_output()函数为网卡的发送函数,它主要将内核的数据包发送出去,数据包采用pbuf数据结构进行描述,该数据结构是一个比较复杂的数据结构,后续我们会详细讲解。 low_level_input()函数为网卡的数据接收函数,该函数会接收一个数据包,为了内核易于对数据包的管理,该函数必须将接收的数据封装成pbuf的形式。 在这一章节中我们仅讲解low_level_init()函数,后面的两个函数涉及到pbuf数据结构,在后面会详细讲解。 除此之外,还有两个函数也与网卡与关系,分别是: ``` 1 err_t ethernetif_init(struct netif *netif); 2 void ethernetif_input(void *pParams); ``` ethernetif_init()函数是在上层管理网卡netif的到时候会被调用的函数,如使用netif_add()添加网卡的时候,就会调用ethernetif_init()函数对网卡进行初始化,其实该函数的最终调用的初始化函数就是low_level_init()函数,我们目前只有一个网卡,就暂时不用对该函数进行改写,直接使用即可,它内部会将网卡的name、output、linkoutput等字段进行初始化,这样子就能将内核与网卡无缝连接起来。 ethernetif_input()函数的主要作用就是调用low_level_input()函数从网卡中读取一个数据包,然后解析该数据包的类型是属于ARP数据包还是IP数据包,再将包递交给上层,在无操作系统的时候ethernetif_input()就是一个可以直接使用的函数,已经无需我们自己去修改,内核会周期性处理该接收函数。而在多线程操作系统的时候,我们一般会将其改写成一个线程的形式,可以周期性去调用low_level_input()网卡接收函数;也可以使用中断的形式去处理,当这个线程将在尚未接收到数据包的时候,处于阻塞状态,当收到数据包的时候,中断利用操作系统的IPC通信机制来唤醒线程去处理接收到的数据包,并将数据包递交上层,这样子的效率会更加高效,事实上我们也是这样子处理的。