[LWIP学习]--tcpip_input,tcpip_inpkt,tcpip_thread函数分析(协议栈入口)
来源:互联网 发布:削下颌骨 知乎 编辑:程序博客网 时间:2024/05/22 08:25
索引:
(*input)().->.tcpip_input().->.ethernet_input()
........................................->.ip_input()
调用流程:
当网卡收到数据后,调用数据帧接收函数进行数据帧的接收,最后通过(*input)()函数传至协议栈(实际是netif->input,有一层封装)。
在添加网络接口时将netif->input()指向tcpip_input函数,即:网络协议栈入口为tcpip_input()函数
tcpip_input()函数并不直接进行数据处理,通过tcpip_inpkt()函数将数据传递到tcpip_thread()函数进行处理。
(可能挺绕的,流程就是:(*input)() -> tcpip_input() -> tcpip_inpkt() -> tcpip_thread())
函数简析:
在注册网络接口netif_add()时,将netif->input指向tcpip_input()函数,通过调用netif->input()执行到该处。
将收到的数据包传递到tcpip_thread(),用于进行ethernet_input()或ip_input()的输入处理(不直接调用)
具体分析: (在源码中有详细注释)
1.收到数据后,先经过一层回调函数(SylixOS 添加的回调函数,用于数据包的过滤)
2.根据inp->flags标志位判断是否包含以太网报头(是否含有NETIF_FLAG_ETHARP或NETIF_FLAG_ETHERNET标志)
3.若包含以太网报头,调用ethernet_input();若不包含以太网报头,调用ip_input()
(注:不是直接调用,通过tcpip_inpkt()将数据传递至tcpip_thread()函数,在lwip主线程函数中调用)
4.tcpip_inpkt()函数填充tcpip_msg结构体,发送一个邮箱消息(在tcpip_thread处进行处理)
5.tcpip_thread()函数收到邮箱消息后,根据msg->type类型,进行不同操作。
(tcpip_thread()函数第一次被调用时,会初始化所有子模块,并进入while循环,等待邮箱消息)
流程图:
源码:
/** * @ingroup lwip_os * 将收到的数据包传递到tcpip_thread,用于进行ethernet_input或ip_input的输入处理(不直接调用), * 在注册网络接口netif_add()时,将netif->input指向tcpip_input()函数,通过调用netif->input()执行到该处。 * * @参数 p 接收到的数据包,p->payload指向以太网头 * 或IP报头(如果inp没有NETIF_FLAG_ETHARP或NETIF_FLAG_ETHERNET标记)。 * @参数 inp 接收数据包的网络接口 */err_ttcpip_input(struct pbuf *p, struct netif *inp){#if defined(SYLIXOS) && defined(LWIP_HOOK_LINK_INPUT) /* SylixOS 添加的回调函数(数据包过滤) */ if (LWIP_HOOK_LINK_INPUT(p, inp)) { pbuf_free(p); return ERR_OK; }#endif /* SYLIXOS && LWIP_HOOK_TCPIP_INPUT */ #if LWIP_ETHERNET if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) { return tcpip_inpkt(p, inp, ethernet_input); } else#endif /* LWIP_ETHERNET */ return tcpip_inpkt(p, inp, ip_input);}
/** * 将收到的数据包传递到tcpip_thread进行输入处理 * * @参数 p 收到的数据包 * @参数 inp 接收数据包的网络接口 * @参数 input_fn 要调用的函数(ethernet_input或ip_input) */err_ttcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn){#if LWIP_TCPIP_CORE_LOCKING_INPUT err_t ret; LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_inpkt: PACKET %p/%p\n", (void *)p, (void *)inp)); LOCK_TCPIP_CORE(); ret = input_fn(p, inp); UNLOCK_TCPIP_CORE(); return ret;#else /* LWIP_TCPIP_CORE_LOCKING_INPUT */ struct tcpip_msg *msg; LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); /* 申请一个邮箱消息结构体(tcpip_msg共用体) */ msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT); if (msg == NULL) { return ERR_MEM; } /* 填充tcpip_msg结构体,发送一个邮箱消息(在tcpip_thread处进行处理) */ msg->type = TCPIP_MSG_INPKT; msg->msg.inp.p = p; msg->msg.inp.netif = inp; msg->msg.inp.input_fn = input_fn; if (sys_mbox_trypost(&mbox, msg) != ERR_OK) { memp_free(MEMP_TCPIP_MSG_INPKT, msg); return ERR_MEM; } return ERR_OK;#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */}
/** * 主lwIP线程。该线程具有对lwIP核心函数的独占访问权(除非对它们的访问没有被锁定)。 * 其他线程使用邮箱与此线程进行通信。 * * 它还启动所有计时器,以确保它们在正确的线程上下文中运行。 * * @参数 arg 未使用 */static voidtcpip_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) { UNLOCK_TCPIP_CORE(); LWIP_TCPIP_THREAD_ALIVE(); //把它定义为触发一个看门狗的东西(目前为空)。 /* 等待消息,在等待时处理超时 */ TCPIP_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_TCPIP_CORE_LOCKING //SylixOS中此处未执行(宏配置) case TCPIP_MSG_API: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg)); msg->msg.api_msg.function(msg->msg.api_msg.msg); break; case TCPIP_MSG_API_CALL: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API CALL message %p\n", (void *)msg)); msg->msg.api_call.arg->err = msg->msg.api_call.function(msg->msg.api_call.arg); sys_sem_signal(msg->msg.api_call.sem); break;#endif /* !LWIP_TCPIP_CORE_LOCKING */#if !LWIP_TCPIP_CORE_LOCKING_INPUT /* msg->type == TCPIP_MSG_INPKT,执行input_fn函数 */ case TCPIP_MSG_INPKT: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg)); msg->msg.inp.input_fn(msg->msg.inp.p, msg->msg.inp.netif); memp_free(MEMP_TCPIP_MSG_INPKT, msg); break;#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS ////SylixOS中此处未执行(宏配置) 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 && LWIP_TIMERS */ /* msg->type == TCPIP_MSG_CALLBACK,执行function函数 */ 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; /* msg->type == TCPIP_MSG_CALLBACK_STATIC,执行function函数 */ 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; default: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type)); LWIP_ASSERT("tcpip_thread: invalid message", 0); break; } }}
- [LWIP学习]--tcpip_input,tcpip_inpkt,tcpip_thread函数分析(协议栈入口)
- [LWIP学习]--udp_input函数分析
- [LWIP学习]--pbuf_realloc函数分析
- [LWIP学习]--socket函数分析
- [LWIP学习]--bind函数分析
- [LWIP学习]--listen函数分析
- [LWIP学习]--accept函数分析
- [LWIP学习]--connect函数分析
- lwip协议栈学习---udp
- ping lwip网络协议栈 分析(一)
- ping lwip网络协议栈 分析(二)
- ping lwip网络协议栈 分析(三)
- lwIP ARP协议分析
- lwIP ARP协议分析
- lwIP ARP协议分析
- LWIP UDP 协议分析
- [LWIP学习]--recv,recvfrom,recvmsg函数分析
- [LWIP学习]--send,sendto,sendmsg函数分析
- window10 python 安装 pygame
- 记 2017年初 美国游(图海、史诗级长文预警)
- Android开发 Error(建议收藏下来以备不时之需):The number of method references in a .dex file cannot exceed 64K.
- iOS-多线程之NSOperation实例和理解
- 解决360/chrome浏览器打开Axure生成的html文件需要安装axure扩展的问题
- [LWIP学习]--tcpip_input,tcpip_inpkt,tcpip_thread函数分析(协议栈入口)
- Java入门基础值数据类型
- Js时间戳毫秒数转日期格式化
- Maven安装及环境变量配置
- Java经典算法题(二)
- 在CentOS系统中安装字体
- Oracle SQL语句整理
- 嵌入式处理器-2.2
- iOS-多线程之Pthread、NSThread实例和理解