[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;    }  }}


原创粉丝点击