lwip初始化不同平台代码可能存在微弱差异,但是大体步骤还是一致的。
void
tcpip_init(tcpip_init_done_fn initfunc, void *arg)
{
//创建一个邮箱,在freertos中,就是创建一个消息队列
if(sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) {
LWIP_ASSERT("failed to create tcpip_thread mbox", 0);
}
lwip_init(); //lwip各模块的初始化
tcpip_init_done = initfunc;
tcpip_init_done_arg = arg;
#if LWIP_TCPIP_CORE_LOCKING
//创建一个锁
if(sys_mutex_new(&lock_tcpip_core) != ERR_OK) {
LWIP_ASSERT("failed to create lock_tcpip_core", 0);
}
#endif /* LWIP_TCPIP_CORE_LOCKING */
//创建协议栈管理进程tcpip_thread
sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE / sizeof(portSTACK_TYPE), TCPIP_THREAD_PRIO);
}
/**
* Initialize all modules.
*/
void
lwip_init(void)
{
/* Modules initialization */
stats_init();
#if !NO_SYS
sys_init();
#endif /* !NO_SYS */
mem_init();
memp_init();
pbuf_init();
netif_init();
#if LWIP_IPV4
ip_init();
#if LWIP_ARP
etharp_init();
#endif /* LWIP_ARP */
#endif /* LWIP_IPV4 */
#if LWIP_RAW
raw_init();
#endif /* LWIP_RAW */
#if LWIP_UDP
udp_init();
#endif /* LWIP_UDP */
#if LWIP_TCP
tcp_init();
#endif /* LWIP_TCP */
#if LWIP_SNMP
snmp_init();
#endif /* LWIP_SNMP */
#if LWIP_AUTOIP
autoip_init();
#endif /* LWIP_AUTOIP */
#if LWIP_IGMP
igmp_init();
#endif /* LWIP_IGMP */
#if LWIP_DNS
dns_init();
#endif /* LWIP_DNS */
#if PPP_SUPPORT
ppp_init();
#endif
#if LWIP_TIMERS
sys_timeouts_init();
#endif /* LWIP_TIMERS */
}
主要熟悉tcpip_thread对api msg和接收的数据包的处理
/**
* The main lwIP thread. This thread has exclusive access to lwIP core functions
* (unless access to them is not locked). Other threads communicate with this
* thread using message boxes.
*
* It also starts all the timers to make sure they are running in the right
* thread context.
*
* @param arg unused argument
*/
static void
tcpip_thread(void *arg)
{
struct tcpip_msg *msg;
LWIP_UNUSED_ARG(arg);
if (tcpip_init_done != NULL) {
tcpip_init_done(tcpip_init_done_arg);
}
LOCK_TCPIP_CORE();
while (1) { /* MAIN Loop */
UNLOCK_TCPIP_CORE();
LWIP_TCPIP_THREAD_ALIVE();
/* wait for a message, timeouts are processed while waiting */
//阻塞等待mbox消息
sys_timeouts_mbox_fetch(&mbox, (void **)&msg);
LOCK_TCPIP_CORE();
if (msg == NULL) {
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: NULL\n"));
LWIP_ASSERT("tcpip_thread: invalid message", 0);
continue;
}
//收到消息后判断消息类型分别做处理
switch (msg->type) {
#if LWIP_NETCONN || LWIP_SOCKET
case TCPIP_MSG_API: //api消息,主要是api_msg.c中的函数接口,下面会做简要分析
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
msg->msg.apimsg->function(&(msg->msg.apimsg->msg));
break;
#endif /* LWIP_NETCONN || LWIP_SOCKET */
#if !LWIP_TCPIP_CORE_LOCKING_INPUT
case TCPIP_MSG_INPKT://收到数据帧消息,解析消息,分析给arp或者IP处理
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));
#if LWIP_ETHERNET
if (msg->msg.inp.netif->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);
} else
#endif /* LWIP_ETHERNET */
ip_input(msg->msg.inp.p, msg->msg.inp.netif); //直接上传给ip层处理
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
break;
#if PPPOS_SUPPORT && !PPP_INPROC_IRQ_SAFE
case TCPIP_MSG_INPKT_PPPOS: //收到的ppp数据包
pppos_input_sys(msg->msg.inp.p, msg->msg.inp.netif);
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
break;
#endif /* PPPOS_SUPPORT && !PPP_INPROC_IRQ_SAFE */
#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
#if LWIP_NETIF_API
case TCPIP_MSG_NETIFAPI: //netif API消息
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg));
msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg));
break;
#endif /* LWIP_NETIF_API */
#if LWIP_PPP_API
case TCPIP_MSG_PPPAPI: //基于ppp 点对点协议的消息
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PPP API message %p\n", (void *)msg));
msg->msg.pppapimsg->function(&(msg->msg.pppapimsg->msg));
break;
#endif /* LWIP_PPP_API */
#if LWIP_TCPIP_TIMEOUT
case TCPIP_MSG_TIMEOUT: //超时消息
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
memp_free(MEMP_TCPIP_MSG_API, msg);
break;
case TCPIP_MSG_UNTIMEOUT: //超时消息
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg));
sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg);
memp_free(MEMP_TCPIP_MSG_API, msg);
break;
#endif /* LWIP_TCPIP_TIMEOUT */
case TCPIP_MSG_CALLBACK: //回调
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
msg->msg.cb.function(msg->msg.cb.ctx);
memp_free(MEMP_TCPIP_MSG_API, msg);
break;
case TCPIP_MSG_CALLBACK_STATIC: //回调
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg));
msg->msg.cb.function(msg->msg.cb.ctx);
break;
case TCPIP_MSG_MODEM_DATA:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: INPKT_CMUX %p\n", (void *)msg));
msg->msg.cb.function(msg->msg.cb.ctx);
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
break;
case TCPIP_MSG_TIMER_ADD:
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip_thread: INPKT_CMUX %p\n", (void *)msg));
sys_timeout_add((struct sys_timeo *)msg->msg.cb.ctx);
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
break;
default:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type));
LWIP_ASSERT("tcpip_thread: invalid message", 0);
break;
}
}
}
注意:在这里简单介绍下应用层数据—》网络,与网卡收到数据包处理过程
应用程序数据—》tcpip_thread:
以netconn_connect函数为例,应用程序消息类型
api_lib.c中将数据封装成api_msg消息,调用TCPIP_APIMSG函数将数据传递给tcpip_apimsg处理,最终封装成tcpip_msg消息类型后交给tcpip_thread处理
err_t
tcpip_apimsg(struct api_msg *apimsg)
{
TCPIP_MSG_VAR_DECLARE(msg);
#ifdef LWIP_DEBUG
/* catch functions that don't set err */
apimsg->msg.err = ERR_VAL;
#endif
if (sys_mbox_valid_val(mbox)) {
TCPIP_MSG_VAR_ALLOC(msg);
TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API; //赋值tcpip_msg类型
TCPIP_MSG_VAR_REF(msg).msg.apimsg = apimsg; //apimsg上层传递过来的,其中apimsg->function是上层的函数,与tcpip_thread中对应
#if LWIP_NETCONN_SEM_PER_THREAD
apimsg->msg.op_completed_sem = LWIP_NETCONN_THREAD_SEM_GET();
LWIP_ASSERT("netconn semaphore not initialized",
sys_sem_valid(apimsg->msg.op_completed_sem));
#endif
sys_mbox_post(&mbox, &TCPIP_MSG_VAR_REF(msg)); //发送mbox
sys_arch_sem_wait(LWIP_API_MSG_SEM(&apimsg->msg), 0);
TCPIP_MSG_VAR_FREE(msg);
return apimsg->msg.err;
}
return ERR_VAL;
}
网卡数据–》tcpip_thread
网卡数据流向tcpip_input处理
/**
* Pass a received packet to tcpip_thread for input processing
*
* @param p the received packet, p->payload pointing to the Ethernet header or
* to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or
* NETIF_FLAG_ETHERNET flags)
* @param inp the network interface on which the packet was received
*/
err_t
tcpip_input(struct pbuf *p, struct netif *inp)
{
#if LWIP_TCPIP_CORE_LOCKING_INPUT //判断是否是active lwip,是就直接解析arp或者ip
err_t ret;
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_input: PACKET %p/%p\n", (void *)p, (void *)inp));
LOCK_TCPIP_CORE();
#if LWIP_ETHERNET
if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
ret = ethernet_input(p, inp);
} else
#endif /* LWIP_ETHERNET */
ret = ip_input(p, inp);
UNLOCK_TCPIP_CORE();
return ret;
#else /* LWIP_TCPIP_CORE_LOCKING_INPUT */ //否则传递给tcpip_thread处理
struct tcpip_msg *msg; //定义tcpip_msg消息
if (!sys_mbox_valid_val(mbox)) {
return ERR_VAL;
}
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT); //申请空间
if (msg == NULL) {
return ERR_MEM;
}
msg->type = TCPIP_MSG_INPKT; //赋值tcpip_msg消息类型
msg->msg.inp.p = p;
msg->msg.inp.netif = inp;
if (sys_mbox_trypost(&mbox, msg) != ERR_OK) { //发送mbox
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
return ERR_MEM;
}
return ERR_OK;
#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
}
void ethernetif_init(sta_ip_mode_t sta_ip_mode,
uint8_t *sta_mac_addr,
uint8_t *ap_mac_addr,
ip4_addr_t *sta_ip_addr, ip4_addr_t *sta_net_mask, ip4_addr_t *sta_gw,
ip4_addr_t *ap_ip_addr, ip4_addr_t *ap_net_mask, ip4_addr_t *ap_gw,
uint8_t opmode)
{
uint8_t sta_mac_address[6];
uint8_t ap_mac_address[6];
/* for patch and fw download */
ethernetif_init_callback();
memset(&sta_if, 0, sizeof(sta_if));
memset(&ap_if, 0, sizeof(ap_if));
// Note: *MUST* first add AP, then STA interface, to make STA the first
// interface in the link-list: STA -> AP -> NULL.
if (0 > wifi_config_get_mac_address(WIFI_PORT_STA, (uint8_t *)&sta_mac_address) ||
0 > wifi_config_get_mac_address(WIFI_PORT_AP, (uint8_t *)&ap_mac_address)) {
LOG_E(lwip, "get mac fail\n\r");
return;
}
//将网卡添加到netif_list链表中,添加后由lwip管理网卡,网卡中有数据就会调用tcpip_input处理,这里关系一个网络接口结构体netif,ethernetif_init后期单独介绍
netif_add(&ap_if, ap_ip_addr, ap_net_mask, ap_gw, NULL,
ethernetif_init2, tcpip_input);
netif_add(&sta_if, sta_ip_addr, sta_net_mask, sta_gw,
NULL, ethernetif_init1, tcpip_input);
low_level_set_mac_addr(&ap_if, ap_mac_address);
low_level_set_mac_addr(&sta_if, sta_mac_address);
//初始化缺省网络接口
//netif_set_default(&sta_if);
//使能网络接口
netif_set_up(&sta_if);
netif_set_up(&ap_if);
//install default route
switch (opmode) {
case WIFI_MODE_AP_ONLY:
netif_set_default(&ap_if);
netif_set_link_down(&sta_if);
break;
case WIFI_MODE_STA_ONLY:
netif_set_default(&sta_if);
netif_set_link_down(&ap_if);
wifi_config_set_ip_mode((uint8_t)sta_ip_mode);
if(sta_ip_mode == STA_IP_MODE_DHCP)
netif_set_wifi_callback(&sta_if, inform_ip_ready_callback);
break;
case WIFI_MODE_REPEATER:
netif_set_default(&sta_if);
break;
}
}
至此,lwip初始化完成。