首页 > 其他分享 >zynq Lwip学习笔记-ip4_input函数

zynq Lwip学习笔记-ip4_input函数

时间:2024-04-06 09:02:58浏览次数:23  
标签:Lwip IP iphdr zynq ip4 ip LWIP 数据包

这里写目录标题

前言

最近在学习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等函数。

标签:Lwip,IP,iphdr,zynq,ip4,ip,LWIP,数据包
From: https://blog.csdn.net/weixin_40356705/article/details/137360376

相关文章

  • zynq Lwip学习笔记-low_level_init函数
    这里写目录标题前言一、概述二、函数体三、调用关系前言最近在学习zynq中的lwip协议族,找不到很好的记笔记的地方,所以就用csdn记录一下自己的学习过程。现在对lwip不熟悉,只是把官方的lwipechoserver例程跑了一下,能跑通就一点点的照着学了,笔记都是根据自己的理解写的......
  • zynq Lwip学习笔记-setup_isr 函数
    这里写目录标题前言一、概述二、函数体三、调用关系前言最近在学习zynq中的lwip协议族,找不到很好的记笔记的地方,所以就用csdn记录一下自己的学习过程。现在对lwip不熟悉,只是把官方的lwipechoserver例程跑了一下,能跑通就一点点的照着学了,笔记都是根据自己的理解写的......
  • 【WCH以太网接口系列芯片】STM32+CH390+Lwip协议栈简单应用测试
    本篇文章基于STM32F103和CH390H芯片进行例程移植及相关注意事项,简单验证TCP\UDP\Ping基础功能。硬件:STM32F103开发板+沁恒CH390H的评估版图一示,SPI使用接口为:INT->PA0,RST->PA1,CS->PA2,SCK->PA5,MISO->PA6,MOSI->PA7,WOL->PA8。 图一 软件移植:采用的沁恒官方提供的CH......
  • Xilinx ZYNQ 7000+Vivado2015.2系列(十五)AXI Timer 用户定时器中断控制LED
    前面的中断学习中我们学了按键,GPIO,Timer,是时候把它们整合到一起了。今天我们混合使用PS/PL部分的资源,建立一个比较大的系统。板子:zc702。实现功能如下:1.通过串口打印信息询问你要按SW5还是SW7;2.当正确的按键被按下,定时器启动,关闭ledDS23;3.当定时器溢出后触发中断,开启DS23,......
  • Xilinx ZYNQ 7000+Vivado2015.2系列(十四)按键中断控制LED亮灭
    前面我们介绍了按键中断,其实我们稍作修改就可以用按键控制LED了。做个小实验,两个按键分别控制两个led亮灭。板子:zc702。硬件部分添加zynq核:勾选串口用于打印信息,勾选EMIO,我们控制两个led,所以需要2bitPL到PS的中断勾选上:PL时钟什么的都用不到,我们用的按键不需要时钟,EMIO......
  • Xilinx ZYNQ 7000+Vivado2015.2系列(十三)私有定时器中断
    私有定时器属于PS部分,定时器可以帮我们计数、计时,有效的控制模块的时序。这一次实验我们认识定时器并使用定时器产生中断。CPU的私有中断(PPI)CPU的私有中断(PPI),5个:全局定时器,私有看门狗定时器,私有定时器以及来自PL的FIQ/IRQ。它们的触发类型都是固定不变的,并且来自P......
  • Xilinx ZYNQ 7000+Vivado2015.2系列(九)基于AXI总线的等精度频率计(测量数字信号频率)
    上一节我们体验了一把PS和PL是怎样联合开发的,这种ARM和FPGA联合设计是ZYNQ的精华所在。这一节我们实现一个稍微复杂一点的功能——测量未知信号的频率,PS和PL通过AXI总线交互数据,实现我们希望的功能。如何测量数字信号的频率最简单的办法——在一段时间内计数在我们设定的......
  • Xilinx ZYNQ 7000+Vivado2015.2系列(十)MIO/EMIO再识,MIO的引脚“复用”,EMIO当作PS的接口
    前面我们介绍过EMIO,但是不详细。MIO是PS的IO接口,这个M代表的是Multiuse,也就是多用途,在下图中我们可以看到54个MIO连接这么多东西,必须得复用,所以当我们开发的时候需要的功能配置上,不需要的去掉,防止IO口被占用。板子用的是zc702。下面我们双击ZYNQ核:我们到MIO的配置里,把其......
  • Xilinx ZYNQ 7000+Vivado2015.2系列(八)ARM+FPGA的优势,PS控制PL产生需要的PWM波(基于AXI
    上一节我们观察了AXI总线的信号,了解了基于AXI总线读写的时序,这一节我们继续探索基于AXI总线的设计,来看一看ZYNQ系列开发板的独特优势,PS可以控制PL产生定制化的行为,而不需要去动硬件代码。这次实验是产生频率和占空比可调的PWM(PulseWidthModulation)信号,调用8次,产生8路PWM......
  • Xilinx ZYNQ 7000+Vivado2015.2系列(七)软硬件联合Debug观察AXI总线读、写时各信号的时
    前面一节我们学会了创建基于AXI总线的IP,但是对于AXI协议各信号的时序还不太了解。这个实验就是通过SDK和Vivado联合调试观察AXI总线的信号。由于我们创建的接口是基于AXI_Lite协议的,所以我们实际观察到是AXI_Lite协议的信号时序。具体做法是创建一个基于AXI总线的加法器模块,在......