zynq Lwip学习笔记-ip4_input函数

前言

最近在学习zynq中的lwip协议族,找不到很好的记笔记的地方,所以就用csdn记录一下自己的学习过程。现在对lwip不熟悉,只是把官方的lwip echo server例程跑了一下,能跑通就一点点的照着学了,笔记都是根据自己的理解写的,而且部分内容可能也只针对lwip echo server例程有效,笔记可以供有缘人参考,但不敢保证全对,有不对的地方也期待有高人指点一二。
————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/weixin_40356705/article/details/136824649

一、概述

  • 原型
err_t ip4_input(struct pbuf *p, struct netif *inp)
  • 参数
    struct pbuf *p : 接收到的数据包
    struct netif *inp:接收数据包的网络接口
  • 作用

二、函数体

// 错误类型定义  
err_t  
// ip4_input 函数,用于处理IPv4输入数据包  
ip4_input(struct pbuf *p, struct netif *inp)  
{  
  // 指向IP头部的常量指针  
  const struct ip_hdr *iphdr;  
  // 网络接口结构体指针  
  struct netif *netif;  
  // IP头部的长度(字节为单位)  
  u16_t iphdr_hlen;  
  // IP数据包的总长度(字节为单位)  
  u16_t iphdr_len;  
  
#if IP_ACCEPT_LINK_LAYER_ADDRESSING || LWIP_IGMP  
  // 是否需要检查IP源地址的标记,根据配置确定  
  int check_ip_src = 1;  
#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING || LWIP_IGMP */  
  
#if LWIP_RAW  
  // RAW IP输入的状态  
  raw_input_state_t raw_status;  
#endif /* LWIP_RAW */  
  
  // 断言,确保核心已锁定  
  LWIP_ASSERT_CORE_LOCKED();  
  
  // 更新IP接收的统计数据  
  IP_STATS_INC(ip.recv);  
  // 更新MIB2 IP输入接收的统计数据  
  MIB2_STATS_INC(mib2.ipinreceives);  
  
  // 识别数据包的IP头部  
  iphdr = (struct ip_hdr *)p->payload;  
  // 检查IP头部的版本号,如果不是IPv4(版本号为4),则执行以下操作  
  if (IPH_V(iphdr) != 4) {  
    // 打印警告信息,表示由于版本号错误而丢弃了数据包  
    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IP packet dropped due to bad version number %"U16_F"\n", (u16_t)IPH_V(iphdr)));  
    // 打印调试信息,显示被丢弃的数据包内容  
    ip4_debug_print(p);  
    // 释放pbuf所占用的内存  
    pbuf_free(p);  
    // 更新IP错误统计数据  
    IP_STATS_INC(ip.err);  
    // 更新IP丢弃统计数据  
    IP_STATS_INC(ip.drop);  
    // 更新MIB2 IP头部错误统计数据  
    MIB2_STATS_INC(mib2.ipinhdrerrors);  
    // 返回成功标志,即使数据包被丢弃  
    return ERR_OK;  
  }  
  
#ifdef LWIP_HOOK_IP4_INPUT  
  // 如果有定义LWIP_HOOK_IP4_INPUT钩子函数,则调用它  
  if (LWIP_HOOK_IP4_INPUT(p, inp)) {  
    // 如果钩子函数返回非零值,表示数据包已被处理  
    // 则函数返回成功标志  
    return ERR_OK;  
  }  
#endif  
  
  // 从IP头部获取头部长度(字节为单位)  
  iphdr_hlen = IPH_HL_BYTES(iphdr);  
  // 从IP头部获取IP数据包的总长度(字节为单位)  
  iphdr_len = lwip_ntohs(IPH_LEN(iphdr));  
  
  // 如果IP数据包的长度小于pbuf的总长度,则重新调整pbuf的长度  
  // 这在数据包长度小于60字节时尤为重要  
  if (iphdr_len < p->tot_len) {  
    pbuf_realloc(p, iphdr_len);  
  }  
  
  // 检查IP头部的长度是否超出pbuf的第一个缓冲区长度  
  // 或IP数据包的长度是否超出pbuf的总长度  
  // 或IP头部的长度是否小于最小长度(通常为20字节)  
  if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len) || (iphdr_hlen < IP_HLEN)) {  
    // 如果IP头部长度小于最小长度,则打印严重级别的调试信息  
    if (iphdr_hlen < IP_HLEN) {  
      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,  
                  ("ip4_input: short IP header (%"U16_F" bytes) received, IP packet dropped\n", iphdr_hlen));  
    }  
    // 如果IP头部长度超出pbuf的第一个缓冲区长度,则打印严重级别的调试信息  
    if (iphdr_hlen > p->len) {  
      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,  
                  ("IP header (len %"U16_F") does not fit in first pbuf (len %"U1
`// 释放(丢弃)当前处理的pbuf数据包  
/* free (drop) packet pbufs */  
pbuf_free(p);  
  
// 更新IP统计信息,表示由于长度错误而丢弃了一个数据包  
IP_STATS_INC(ip.lenerr);  
  
// 更新IP统计信息,表示丢弃了一个数据包  
IP_STATS_INC(ip.drop);  
  
// 更新MIB2统计信息,表示丢弃了一个IP输入数据包  
MIB2_STATS_INC(mib2.ipindiscards);  
  
// 返回处理结果,这里虽然是ERR_OK,但实际上数据包已经被丢弃  
return ERR_OK;  
  
// 代码段结束  
}  
  
// 开始进行校验和的检查,如果定义了CHECKSUM_CHECK_IP并且网络接口支持IP校验和检查  
#if CHECKSUM_CHECK_IP  
  IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_IP) {  
    // 计算IP头部的校验和  
    if (inet_chksum(iphdr, iphdr_hlen) != 0) {  
      // 如果校验和不等于0,表示校验和失败  
      // 打印调试信息,显示校验和失败,并输出校验和的值  
      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,  
                  ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen)));  
        
      // 打印IP数据包的调试信息  
      ip4_debug_print(p);  
        
      // 释放(丢弃)当前处理的pbuf数据包  
      pbuf_free(p);  
        
      // 更新IP统计信息,表示由于校验和错误而丢弃了一个数据包  
      IP_STATS_INC(ip.chkerr);  
        
      // 更新IP统计信息,表示丢弃了一个数据包  
      IP_STATS_INC(ip.drop);  
        
      // 更新MIB2统计信息,表示由于IP头部错误而丢弃了一个输入数据包  
      MIB2_STATS_INC(mib2.ipinhdrerrors);  
        
      // 返回处理结果,虽然是ERR_OK,但实际上数据包已经被丢弃  
      return ERR_OK;  
    }  
  }  
#endif  
  
// 将IPv4头部的目的地址复制到ip_data结构体的对应字段中  
/* copy IP addresses to aligned ip_addr_t */  
ip_addr_copy_from_ip4(ip_data.current_iphdr_dest, iphdr->dest);  
  
// 将IPv4头部的源地址复制到ip_data结构体的对应字段中  
ip_addr_copy_from_ip4(ip_data.current_iphdr_src, iphdr->src)
/* 匹配数据包到一个接口,即判断这个数据包是否是给我们的? */  
/* match packet against an interface, i.e. is this packet for us? */  
if (ip4_addr_ismulticast(ip4_current_dest_addr())) {  
  /* 如果目的地址是多播地址 */  
  if (LWIP_IGMP) {  
    /* 如果定义了IGMP */  
    if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, ip4_current_dest_addr()))) {  
      /* 如果当前网络接口支持IGMP,并且多播组存在于网络接口中 */  
      /* IGMP snooping switches need 0.0.0.0 to be allowed as source address (RFC 4541) */  
      ip4_addr_t allsystems;  
      IP4_ADDR(&allsystems, 224, 0, 0, 1);  
      /* 为IGMP snooping交换机定义一个特殊的源地址检查,RFC 4541允许使用0.0.0.0作为源地址 */  
      if (ip4_addr_cmp(ip4_current_dest_addr(), &allsystems) &&  
          ip4_addr_isany(ip4_current_src_addr())) {  
        /* 如果目的地址是224.0.0.1(所有系统组),并且源地址是任意地址(通常为0.0.0.0) */  
        check_ip_src = 0;  
      /* 禁用源地址检查 */  
      }  
      netif = inp;  
    /* 使用当前网络接口处理数据包 */  
    } else {  
      netif = NULL;  
    /* 没有找到合适的网络接口来处理数据包 */  
    }  
  } else /* LWIP_IGMP */ {  
    /* 如果没有定义IGMP */  
    if ((netif_is_up(inp)) && (!ip4_addr_isany_val(*netif_ip4_addr(inp)))) {  
      /* 如果当前网络接口是活动的,并且配置了非任意IP地址 */  
      netif = inp;  
    /* 使用当前网络接口处理数据包 */  
    } else {  
      netif = NULL;  
    /* 没有找到合适的网络接口来处理数据包 */  
    }  
  }  
#endif /* LWIP_IGMP */  
} else {  
  /* 如果目的地址不是多播地址 */  
  /* start trying with inp. if that's not acceptable, start walking the  
     list of configured netifs. */  
  /* 首先尝试使用inp。如果inp不可接受,则遍历配置的网络接口列表。 */  
  if (ip4_input_accept(inp)) {  
    /* 如果inp接口接受这个数据包 */  
    netif = inp;  
  /* 使用inp接口处理数据包 */  
  } else {  
    netif = NULL;  
  /* 没有找到合适的网络接口来处理数据包 */  
#if !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF  
    /* 如果没有定义LWIP_NETIF_LOOPBACK或者定义了LWIP_HAVE_LOOPIF */  
    /* Packets sent to the loopback address must not be accepted on an  
       interface that does not have the loopback address assigned to it,  
       unless a non-loopback interface is used for loopback traffic. */  
    /* 除非使用非回环接口处理回环流量,否则发送到回环地址的数据包不能在未分配回环地址的接口上被接受。 */  
    if (!ip4_addr_isloopback(ip4_current_dest_addr()))  
#endif /* !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF */  
    {  
#if !LWIP_SINGLE_NETIF  
      /* 如果没有定义LWIP_SINGLE_NETIF,意味着有多个网络接口 */  
      NETIF_FOREACH(netif) {  
        /* 遍历所有网络接口 */  
        if (netif == inp) {  
          /* 如果已经检查过inp接口,则跳过 */  
          continue;  
        }  
        if (ip4_input_accept(netif)) {  
          /* 如果某个接口接受这个数据包 */  
          break;  
        /* 跳出循环 */  
        }  
      }  
#endif /* !LWIP_SINGLE_NETIF */  
    }  
  }  
}
#if IP_ACCEPT_LINK_LAYER_ADDRESSING  
  /* 如果定义了IP_ACCEPT_LINK_LAYER_ADDRESSING,则允许通过链路层地址(如以太网MAC地址)传递的DHCP消息,  
   * 而不考虑其目的地址。DHCP流量使用链路层地址进行寻址,因此我们不能仅通过IP地址来过滤。  
   * 这符合RFC 1542第3.1.1节的规定,该节被RFC 2131引用。  
   *  
   * 如果您希望在网络接口关闭时接受私有广播通信,可以定义LWIP_IP_ACCEPT_UDP_PORT(dst_port),例如:  
   *  
   * #define LWIP_IP_ACCEPT_UDP_PORT(dst_port) ((dst_port) == PP_NTOHS(12345))  
   */  
  if (netif == NULL) {  
    /* 如果没有找到可用的网络接口(netif),检查是否是一个发送给DHCP服务器的UDP数据包。 */  
    if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {  
      /* 获取UDP头部指针 */  
      const struct udp_hdr *udphdr = (const struct udp_hdr *)((const u8_t *)iphdr + iphdr_hlen);  
        
      /* 调试输出,显示UDP数据包的目标端口 */  
      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip4_input: UDP packet to DHCP client port %"U16_F"\n",  
                                              lwip_ntohs(udphdr->dest)));  
        
      /* 检查UDP数据包的目标端口是否是DHCP客户端期望的端口 */  
      if (IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(udphdr->dest)) {  
        /* 调试输出,表明DHCP数据包被接受 */  
        LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip4_input: DHCP packet accepted.\n"));  
          
        /* 设置网络接口为输入接口 */  
        netif = inp;  
          
        /* 禁用源地址检查 */  
        check_ip_src = 0;  
      }  
    }  
  }  
#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */  
  
  /* 处理广播或多播数据包的源地址。符合RFC 1122: 3.2.1.3的规定 */  
#if LWIP_IGMP || IP_ACCEPT_LINK_LAYER_ADDRESSING  
  if (check_ip_src  
#if IP_ACCEPT_LINK_LAYER_ADDRESSING  
      /* 对于DHCP服务器,允许源地址为0.0.0.0(RFC 1.1.2.2: 3.2.1.3/a) */  
      && !ip4_addr_isany_val(*ip4_current_src_addr())  
#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */  
     )  
#endif /* LWIP_IGMP || IP_ACCEPT_LINK_LAYER_ADDRESSING */  
  {  
    /* 检查数据包的源地址是否是广播或多播地址 */  
    if ((ip4_addr_isbroadcast(ip4_current_src_addr(), inp)) ||  
        (ip4_addr_ismulticast(ip4_current_src_addr()))) {  
      /* 数据包源地址无效 */  
      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip4_input: packet source is not valid.\n"));  
        
      /* 释放(丢弃)数据包pbuf */  
      pbuf_free(p);  
        
      /* 增加IP丢弃统计计数 */  
      IP_STATS_INC(ip.drop);  
        
      // 增加MIB2的统计信息,表示地址错误  
      MIB2_STATS_INC(mib2.ipinaddrerrors);  
      // 增加MIB2的统计信息,表示数据包被丢弃  
      MIB2_STATS_INC(mib2.ipindiscards);  
      // 返回ERR_OK,表示函数正常结束(尽管数据包已被丢弃)  
      return ERR_OK;
    }  
  }
/* 数据包不是给我们的吗? */  
if (netif == NULL) {  
  /* 数据包不是给我们的,路由或丢弃 */  
  LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip4_input: packet not for us.\n"));  
  
#if IP_FORWARD  
  /* 非广播数据包? */  
  if (!ip4_addr_isbroadcast(ip4_current_dest_addr(), inp)) {  
    /* 尝试在其他接口上转发IP数据包 */  
    ip4_forward(p, (struct ip_hdr *)p->payload, inp);  
  } else  
#endif /* IP_FORWARD */  
  {  
    /* 增加IP层丢弃数据包的统计 */  
    IP_STATS_INC(ip.drop);  
    /* 增加MIB2的统计信息,表示地址错误 */  
    MIB2_STATS_INC(mib2.ipinaddrerrors);  
    /* 增加MIB2的统计信息,表示数据包被丢弃 */  
    MIB2_STATS_INC(mib2.ipindiscards);  
  }  
  /* 释放(丢弃)数据包pbuf */  
  pbuf_free(p);  
  /* 返回ERR_OK,表示函数正常结束(尽管数据包已被丢弃) */  
  return ERR_OK;  
}  
  
/* 数据包是由多个片段组成的吗? */  
if ((IPH_OFFSET(iphdr) & PP_HTONS(IP_OFFMASK | IP_MF)) != 0) {  
#if IP_REASSEMBLY /* 数据包分片重组代码存在吗? */  
  /* 调试输出,显示数据包的分片信息 */  
  LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip4_reass()\n",  
                           lwip_ntohs(IPH_ID(iphdr)), p->tot_len, lwip_ntohs(IPH_LEN(iphdr)), (u16_t)!!(IPH_OFFSET(iphdr) & PP_HTONS(IP_MF)), (u16_t)((lwip_ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK) * 8)));  
  
  /* 重组数据包 */  
  p = ip4_reass(p);  
  
  /* 数据包尚未完全重组吗? */  
  if (p == NULL) {  
    /* 返回ERR_OK,表示函数正常结束(尽管数据包尚未完全重组) */  
    return ERR_OK;  
  }  
  /* 重组后更新iphdr指针 */  
  iphdr = (const struct ip_hdr *)p->payload;  
#else /* IP_REASSEMBLY == 0, 没有数据包分片重组代码 */  
  /* 释放(丢弃)数据包pbuf */  
  pbuf_free(p);  
  /* 调试输出,表示因为分片且不支持重组而丢弃了数据包 */  
  LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",  
                lwip_ntohs(IPH_OFFSET(iphdr))));  
  /* 增加IP层选项错误的统计 */  
  IP_STATS_INC(ip.opterr);  
  /* 增加IP层丢弃数据包的统计 */  
  IP_STATS_INC(ip.drop);  
  /* 增加MIB2的统计信息,表示不支持的协议特性 */  
  MIB2_STATS_INC(mib2.ipinunknownprotos);  
  /* 返回ERR_OK,表示函数正常结束(尽管数据包已被丢弃) */  
  return ERR_OK;  
#endif /* IP_REASSEMBLY */  
}
#if IP_OPTIONS_ALLOWED == 0 /* 不支持IP头中的IP选项吗? */  
  
#if LWIP_IGMP  
  /* IGMP消息中有一个额外的"路由器警告"选项,我们允许它但不进行验证 */  
  if ((iphdr_hlen > IP_HLEN) &&  (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) {  
#else  
  /* 如果IP头长度大于标准的IP头长度(即存在IP选项) */  
  if (iphdr_hlen > IP_HLEN) {  
#endif /* LWIP_IGMP */  
    /* 调试输出,表示由于存在IP选项而丢弃了数据包(因为IP_OPTIONS_ALLOWED为0) */  
    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n"));  
    /* 释放数据包pbuf */  
    pbuf_free(p);  
    /* 增加IP层选项错误的统计 */  
    IP_STATS_INC(ip.opterr);  
    /* 增加IP层丢弃数据包的统计 */  
    IP_STATS_INC(ip.drop);  
    /* 增加MIB2的统计信息,表示不支持的协议特性 */  
    MIB2_STATS_INC(mib2.ipinunknownprotos);  
    /* 返回ERR_OK,表示函数正常结束(尽管数据包已被丢弃) */  
    return ERR_OK;  
  }  
#endif /* IP_OPTIONS_ALLOWED == 0 */ 
#if IP_OPTIONS_ALLOWED == 0 /* 不支持IP头部选项? */  
  
#if LWIP_IGMP  
  /* IGMP消息中有一个额外的"路由器警告"选项,我们允许但不检查它 */  
  if ((iphdr_hlen > IP_HLEN) &&  (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) {  
#else  
  /* 如果IP头部的长度大于标准的IP头部长度 */  
  if (iphdr_hlen > IP_HLEN) {  
#endif /* LWIP_IGMP */  
    /* 打印调试信息,表明因为存在IP选项而丢弃了IP数据包(尽管不支持IP选项) */  
    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP数据包被丢弃,因为存在IP选项(而IP_OPTIONS_ALLOWED设置为0)。\n"));  
    /* 释放数据包pbuf */  
    pbuf_free(p);  
    /* 增加IP层选项错误的统计 */  
    IP_STATS_INC(ip.opterr);  
    /* 增加IP层丢弃数据包的统计 */  
    IP_STATS_INC(ip.drop);  
    /* 增加MIB2的统计信息,表示不支持的协议特性 */  
    MIB2_STATS_INC(mib2.ipinunknownprotos);  
    /* 返回ERR_OK,表示函数正常结束(尽管数据包已被丢弃) */  
    return ERR_OK;  
  }  
#endif /* IP_OPTIONS_ALLOWED == 0 */  
  
  /* 将数据包发送到上层协议栈 */  
  LWIP_DEBUGF(IP_DEBUG, ("ip4_input: \n"));  
  /* 打印调试信息,显示IP数据包的内容 */  
  ip4_debug_print(p);  
  /* 打印调试信息,显示数据包长度和总长度 */  
  LWIP_DEBUGF(IP_DEBUG, ("ip4_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));  
  
  /* 设置当前网络接口和其他相关IP数据 */  
  ip_data.current_netif = netif;  
  ip_data.current_input_netif = inp;  
  ip_data.current_ip4_header = iphdr;  
  ip_data.current_ip_header_tot_len = IPH_HL_BYTES(iphdr);  
  
#if LWIP_RAW  
  /* 调用RAW协议栈的输入函数处理数据包,如果RAW协议栈没有处理该数据包 */  
  raw_status = raw_input(p, inp);  
  if (raw_status != RAW_INPUT_EATEN)  
#endif /* LWIP_RAW */
#if LWIP_RAW  
  /* 如果RAW协议栈已启用,则调用raw_input函数尝试处理数据包 */  
  raw_status = raw_input(p, inp);  
  if (raw_status != RAW_INPUT_EATEN)  
#endif /* LWIP_RAW */  
  {  
    /* 移除IP头部,将pbuf的指针移动到有效载荷(payload)开始的位置 */  
    pbuf_remove_header(p, iphdr_hlen); /* 不需要检查,因为前面已经验证了iphdr_hlen */  
  
    /* 根据IP头部的协议字段将数据包转发到相应的处理函数 */  
    switch (IPH_PROTO(iphdr)) {  
#if LWIP_UDP  
      /* 如果协议是UDP */  
      case IP_PROTO_UDP:  
#if LWIP_UDPLITE  
        /* 或者协议是UDPLite */  
      case IP_PROTO_UDPLITE:  
#endif /* LWIP_UDPLITE */  
        /* 增加MIB2的统计信息,表示有IP数据报被递送 */  
        MIB2_STATS_INC(mib2.ipindelivers);  
        /* 调用UDP处理函数 */  
        udp_input(p, inp);  
        break;  
#endif /* LWIP_UDP */  
  
#if LWIP_TCP  
      /* 如果协议是TCP */  
      case IP_PROTO_TCP:  
        /* 增加MIB2的统计信息,表示有IP数据报被递送 */  
        MIB2_STATS_INC(mib2.ipindelivers);  
        /* 调用TCP处理函数 */  
        tcp_input(p, inp);  
        break;  
#endif /* LWIP_TCP */  
  
#if LWIP_ICMP  
      /* 如果协议是ICMP */  
      case IP_PROTO_ICMP:  
        /* 增加MIB2的统计信息,表示有IP数据报被递送 */  
        MIB2_STATS_INC(mib2.ipindelivers);  
        /* 调用ICMP处理函数 */  
        icmp_input(p, inp);  
        break;  
#endif /* LWIP_ICMP */  
  
#if LWIP_IGMP  
      /* 如果协议是IGMP */  
      case IP_PROTO_IGMP:  
        /* 调用IGMP处理函数 */  
        igmp_input(p, inp, ip4_current_dest_addr());  
        break;  
#endif /* LWIP_IGMP */  
  
      default:  
        /* 对于不支持的协议类型 */  
#if LWIP_RAW  
        /* 如果RAW协议栈之前已处理过这个数据包 */  
        if (raw_status == RAW_INPUT_DELIVERED) {  
          /* 增加MIB2的统计信息,表示有IP数据报被递送 */  
          MIB2_STATS_INC(mib2.ipindelivers);  
        } else  
#endif /* LWIP_RAW */  
        {  
#if LWIP_ICMP  
          /* 如果目的地不是广播或多播地址,则发送ICMP目标协议不可达消息 */  
          if (!ip4_addr_isbroadcast(ip4_current_dest_addr(), netif) &&  
              !ip4_addr_ismulticast(ip4_current_dest_addr())) {  
            /* 将pbuf的指针重新移动到IP头部的开始位置 */  
            pbuf_header_force(p, (s16_t)iphdr_hlen); /* 不需要检查,因为前面已经验证了iphdr_hlen */  
            /* 发送ICMP目标协议不可达消息 */  
            icmp_dest_unreach(p, ICMP_DUR_PROTO);  
          }  
#endif /* LWIP_ICMP */  
  
          /* 打印调试信息,表示不支持的传输协议 */  
          LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("不支持的传输协议 %"U16_F"\n", (u16_t)IPH_PROTO(iphdr)));  
  
          /* 增加IP层协议错误统计 */  
          IP_STATS_INC(ip.proterr);  
          /* 增加IP层丢弃数据包的统计 */  
          IP_STATS_INC(ip.drop);  
          /* 增加MIB2的统计信息,表示不支持的协议特性 */  
          MIB2_STATS_INC(mib2.ipinunknownprotos);  
        }  
        /* 释放pbuf */  
        pbuf_free(p);  
        break;  
    }  
  }
  /*  
 * @todo: 这条注释表明接下来的代码可能不是必需的,需要后续审查或修改。  
 */  
/* @todo: this is not really necessary... */  
  
// 将ip_data结构体的current_netif成员设置为NULL,可能表示当前没有网络接口被选中或设置。  
ip_data.current_netif = NULL;  
  
// 将ip_data结构体的current_input_netif成员设置为NULL,可能表示当前没有输入网络接口被选中或设置。  
ip_data.current_input_netif = NULL;  
  
// 将ip_data结构体的current_ip4_header成员设置为NULL,可能表示当前没有IPv4头部信息。  
ip_data.current_ip4_header = NULL;  
  
// 将ip_data结构体的current_ip_header_tot_len成员设置为0,可能表示当前没有IPv4头部总长度信息。  
ip_data.current_ip_header_tot_len = 0;  
  
// 调用ip4_addr_set_any函数来设置当前的源IPv4地址为任意地址(通常表示未指定或无效的地址)。  
ip4_addr_set_any(ip4_current_src_addr());  
  
// 调用ip4_addr_set_any函数来设置当前的目的IPv4地址为任意地址(通常表示未指定或无效的地址)。  
ip4_addr_set_any(ip4_current_dest_addr());  
  
// 返回ERR_OK错误码,这可能表示操作成功或没有错误发生。  
return ERR_OK;
}

三、调用关系

被ethernet_input调用,调用了tcp_input,udp_input等函数。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值