2023年12月6日发(作者:)

lwip初始化流程

lwip初始化流程

lwip初始化不同平台代码可能存在微弱差异,但是大体步骤还是一致的。

lwip_tcpip_init()其中包括tcpip_init,ethernetif_init

一.tcpip_init() 包括lwip_init,sys_thread_new

_init源码如下

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);

}

2 .lwip_init,初始化各种模块/** * Initialize all modules. */voidlwip_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 */}_thread分析主要熟悉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: NULLn"));

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 %pn", (void *)msg));

msg->->function(&(msg->->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 %pn", (void *)msg));

#if LWIP_ETHERNET

if (msg->->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {

ethernet_input(msg->.p, msg->);

} else

#endif /* LWIP_ETHERNET */

ip_input(msg->.p, msg->); //直接上传给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->.p, msg->);

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 %pn", (void *)msg));

msg->pimsg->function(&(msg->pimsg->msg));

break;

#endif /* LWIP_NETIF_API */

#if LWIP_PPP_API

case TCPIP_MSG_PPPAPI: //基于ppp 点对点协议的消息

LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PPP API message %pn", (void *)msg));

msg->msg->function(&(msg->msg->msg));

break;#endif /* LWIP_PPP_API */#if LWIP_TCPIP_TIMEOUT case TCPIP_MSG_TIMEOUT: //超时消息 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %pn", (void *)msg)); sys_timeout(msg->, msg->.h, msg->); memp_free(MEMP_TCPIP_MSG_API, msg); break; case TCPIP_MSG_UNTIMEOUT: //超时消息 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %pn", (void *)msg)); sys_untimeout(msg->.h, msg->); memp_free(MEMP_TCPIP_MSG_API, msg); break;#endif /* LWIP_TCPIP_TIMEOUT */ case TCPIP_MSG_CALLBACK: //回调 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %pn", (void *)msg)); msg->on(msg->); memp_free(MEMP_TCPIP_MSG_API, msg); break; case TCPIP_MSG_CALLBACK_STATIC: //回调 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %pn", (void *)msg)); msg->on(msg->); break; case TCPIP_MSG_MODEM_DATA: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: INPKT_CMUX %pn", (void *)msg)); msg->on(msg->); memp_free(MEMP_TCPIP_MSG_INPKT, msg); break; case TCPIP_MSG_TIMER_ADD: LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip_thread: INPKT_CMUX %pn", (void *)msg)); sys_timeout_add((struct sys_timeo *)msg->); memp_free(MEMP_TCPIP_MSG_INPKT, msg); break; default: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %dn", 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-> = 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). = apimsg; //apimsg上层传递过来的,其中apimsg->function是上层的函数,与tcpip_thread中对应

#if LWIP_NETCONN_SEM_PER_THREAD

apimsg->_completed_sem = LWIP_NETCONN_THREAD_SEM_GET();

LWIP_ASSERT("netconn semaphore not initialized",

sys_sem_valid(apimsg->_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->;

}

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/%pn", (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->.p = p;

msg-> = 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 */

}

二.ethernetif_init初始化

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 failnr");

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初始化完成。