《嵌入式网络那些事-LwIP协议深度剖析与实战演练》学习
转载
http://blog.sina.com.cn/s/blog_62a85b950101am5d.html 老衲五木的博客
ethernetif.c netif.c在 LWIP 中,是通过一个叫做 netif 的网络结构体来描述一个硬件网络接口的。
结构体:
struct netif {
struct netif *next; // 指向下一个 netif 结构的指针
struct ip_addr ip_addr; // IP 地址相关配置
struct ip_addr netmask;
struct ip_addr gw;
err_t (* input)(struct pbuf *p, struct netif *inp); //调用这个函数可以从网卡上取得一个
// 数据包
err_t (* output)(struct netif *netif, struct pbuf *p, // IP 层调用这个函数可以向网卡发送
struct ip_addr *ipaddr); // 一个数据包
err_t (* linkoutput)(struct netif *netif, struct pbuf *p); // ARP 模块调用这个函数向网
// 卡发送一个数据包
void *state; // 用户可以独立发挥该指针,用于指向用户关心的网卡信息
u8_t hwaddr_len; // 硬件地址长度,对于以太网就是 MAC 地址长度,为 6 各字节
u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; //MAC 地址
u16_t mtu; // 一次可以传送的最大字节数,对于以太网一般设为 1500
u8_t flags; // 网卡状态信息标志位
char name[2]; // 网络接口使用的设备驱动类型的种类
u8_t num; // 用来标示使用同种驱动类型的不同网络接口
};
next 字段是指向下一个 netif 结构的指针。我们的一个产品可能会有多个网卡芯片, LWIP 会把所有网卡芯片的结构体链成一个链表进行管理,有一个 netif_list 的全局变量指向该链表的头部。 next 字段就是用于链表用。
ip_addr、 netmask、 gw 三个字段用于发送和处理数据包用,分别表示 IP 地址、子网掩码和网关地址。前两个字段在数据包发送时有重要作用,第三个字段似乎没什么用。 IP 地址和网卡设备必须一一对应。
input 字段指向一个函数,这个函数将网卡设备接收到的数据包提交给 IP 层,使用时将input 指针指向该函数即可,后面将详细讨论这个问题。该函数的两个参数是 pbuf 类型和 netif类型的,返回参数是 err_t 类型。其中 pbuf 代表接收到的数据包。
output 字段向一个函数,这个函数和具体网络接口设备驱动密切相关,它用于 IP 层将一个数据包发送到网络接口上。用户需要根据实际网卡编写该函数,并将 output 字段指向
该函数。该函数的三个参数是 pbuf 类型、 netif 类型和 ip_addr 类型,返回参数是 err_t 类型。其中 pbuf 代表要发送的数据包。 ipaddr 代表网卡需要将该数据包发送到的地址,该地址应该是接收实际的链路层帧的主机的 IP 地址,而不一定为数据包最终需要到达的 IP 地址。例如,当要发送 IP 信息包到一个并不在ᴀ地网络里的主机上时,链路层帧会被发送到网络里的一个路由器上。在这种情况下,给 output 函数的 IP 地址将是这个路由器的地址。
linkoutput 字段和上面的 output 基ᴀ上是起相同的作用,但是这个函数是在 ARP 模块中被调用的,这里不赘述了。注意这个函数只有两个参数。实际上 output 字段函数的实现最终还是调用 linkoutput 字段函数将数据包发送出去的。
state 字段可以指向用户关心的关于设备的一些信息,用户可以自由发挥,也可以不用。
hwaddr_len 和 hwaddr[]表示 MAC 地址长度和 MAC 地址,一般 MAC 地址长度为 6。
mtu 字段表示该网络一次可以传送的最大字节数,对于以太网一般设为 1500,不多说。
flags 字段是网卡状态信息标志位,是很重要的控制字段,它包括网卡功能使能、广播
使能、 ARP 使能等等重要控制位。
name[]字段用于保存每一个网络网络接口的名字。用两个字符的名字来标识网络接口使用的设备驱动的种类,名字由设备驱动来设置并且应该反映通过网络接口表示的硬件的种类。比如蓝牙设备( bluetooth)的网络接口名字可以是 bt,而 IEEE 802.11b WLAN 设备的名字就可以是 wl,当然设置什么名字用户是可以自由发挥的,这并不影响用户对网络接口的使用。当然,如果两个网络接口具有相同的网络名字,我们就用 num 字段来区分相同类别的不同网络接口。
Ethernetif.c文件ethernetif_init中初始使用。
这是官方移植的接收函数,不过是有缺陷的。
void ethernetif_input( void * pvParameters )
{
struct pbuf *p;
for( ;; )
{
if (xSemaphoreTake( s_xSemaphore, emacBLOCK_TIME_WAITING_FOR_INPUT)==pdTRUE)
{
p = low_level_input( s_pxNetIf );
if (ERR_OK != s_pxNetIf->input( p, s_pxNetIf))
{
pbuf_free(p);
p=NULL;
}
}
}
}