在LwIP_init( )中调用了netif_add(&netif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, ðernet_input);
1.netif结构体
/** Generic data structure used for all lwIP network interfaces.
* The following fields should be filled in by the initialization
* function for the device driver: hwaddr_len, hwaddr[], mtu, flags */
struct netif {
struct netif *next;
struct ip_addr ip_addr;
struct ip_addr netmask;
struct ip_addr gw;
err_t (* input)(struct pbuf *p, struct netif *inp); 由网络驱动程序调用,向TCP/IP层发送一个数据包
"input 字段指向一个函数,这个函数将网卡设备接收到的数据包提交给IP层,使用时将
nput指针指向该函数即可,后面将详细讨论这个问题。该函数的两个参数是pbuf类型和netif
类型的,返回参数是err_t类型。其中pbuf代表接收到的数据包。"
err_t (* output)(struct netif *netif, struct pbuf *p, IP层调用这个函数向网卡发送一个数据包
struct ip_addr *ipaddr);
"output字段向一个函数,这个函数和具体网络接口设备驱动密切相关,它用于IP 层将
一个数据包发送到网络接口上。用户需要根据实际网卡编写该函数,并将output 字段指向
该函数。该函数的三个参数是pbuf类型、netif类型和ip_addr类型,返回参数是err_t类型。
其中pbuf代表要发送的数据包。ipaddr 代表网卡需要将该数据包发送到的地址,该地址应
该是接收实际的链路层帧的主机的 IP 地址,而不一定为数据包最终需要到达的IP 地址。"
err_t (* linkoutput)(struct netif *netif, struct pbuf *p); ARP模块调用这个函数向网卡发送一个数据包
”linkoutput字段和上面的output基ᴀ上是起相同的作用,但是这个函数是在ARP模块中
被调用的,这里不赘述了。注意这个函数只有两个参数。实际上output 字段函数的实现最
终还是调用linkoutput字段函数将数据包发送出去的。 “
...........
char* hostname; //
u8_t hwaddr_len; //硬件地址长度,对于以太网就是MAC地址长度,为6各字节
u8_t hwaddr[NETIF_MAX_HWADDR_LEN];
u16_t mtu;
u8_t flags; //网卡状态信息标志位 ,
char name[2]; // 网络接口使用的设备驱动类型的种类
u8_t num; // 用来标示使用同种驱动类型的不同网络接口
#if LWIP_SNMP
u8_t link_type;
u32_t link_speed;
u32_t ts;
...
...
}
2.struct netif *
netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,struct ip_addr *gw, void *state,
err_t (* init)(struct netif *netif), //@param init callback function that initializes the interface
err_t (* input)(struct pbuf *p, struct netif *netif)) //@param input callback function that is called to pass
init-->ethernetif_init(struct netif *netif) //底层初始化函数,函数里实际调用low_level_init()对硬件进行设置
input-->ethernet_input(struct pbuf *p, struct netif *netif) //处理从底层接收来的以太网帧,P指向接收到的数据包,p->payload指向以太网帧头
3.在netif_add中
netif->input = input; //即netif结构体中的input指向ethernet_input
/* call user specified initialization function for netif */
if (init(netif) != ERR_OK) { //这里就是初始化,进入ethernet_init
return NULL;
}
4.ethernet_init( )中几个重要的点
netif->output = etharp_output; //netif结构体中的output指向etharp_out(struct netif *netif, struct pbuf *q, struct ip_addr //*ipaddr),
netif->linkoutput = low_level_output;
low_level_init(netif);
5.Low_level_init( struct netif *netif),
a.对netif结构体中的相关参数赋值,
b.Initialize Tx and Rx Descriptors list: Chain Mode
c.Enable Ethernet Rx interrrupt
d.Enable MAC and DMA transmission and reception-->ETH_Start();
6.etharp_output后面调用etharp_send_ip();这个函数有调用了return netif->linkoutput(netif, p);也就是这里的low_level_output().
7.low_level_output()
a.ETH_GetCurrentTxBuffer( ) //return Buffer address
b.memcpy((u8_t*)&buffer[l], q->payload, q->len);
c.ETH_TxPkt_ChainMode(FrameLength); //Transmits a packet, from application buffer, pointed by ppkt.FrameLength: //Tx Packet size.传递从应用层数据包,长度为FrameLength
8.最后ethernet_input( )
调用ip_input( ) //This function is called by the network interface device driver when
// an IP packet is received. Finally, the packet is sent to the upper layer protocol input function.
参考了 老衲五木 的《LwIP协议栈源码详解 》,最近看到他出了《嵌入式网络那些事:LwIP协议深度剖析与实战演练》,膜拜。