【lwip】10-ICMP协议&源码分析( 四 )

10.5.4 超时代码字段/** ICMP超时代码字段 */enum icmp_te_type {/** 生存时间超时值TTL为0 */ICMP_TE_TTL= 0,/** 分片数据报重装超时 */ICMP_TE_FRAG = 1};10.6 发送ICMP差错报告10.6.1 发送ICMP差错报文基函数icmp_send_response()函数就是发送ICMP差错报文的基函数,可以封装这个函数实现各种ICMP差错报文 。
该函数主要逻辑:

  • 检查触发ICMP差错报告的IP报文pbuf中的数据size是否符合要求 。
    • 目的不可达的ICMP差错报文一般需要IP首部+8字节数据 。
  • 申请ICMP差错报文pbuf资源 。
  • 组装ICMP数据报 。
  • 路由匹配网卡 。
  • 通过IP层输出函数发送ICMP报文 。
/** * Send an icmp packet in response to an incoming packet. * * @param p the input packet for which the 'unreachable' should be sent, *p->payload pointing to the IP header * @param type Type of the ICMP header * @param code Code of the ICMP header */static voidicmp_send_response(struct pbuf *p, u8_t type, u8_t code){struct pbuf *q; /* ICMP差错报文pbuf指针 */struct ip_hdr *iphdr; /* 触发ICMP差错报告的IP头指针 */struct icmp_echo_hdr *icmphdr; /* ICMP报文首部指针 */ip4_addr_t iphdr_src; /* 触发ICMP差错报告的IP源地址 */struct netif *netif; /* 发送ICMP差错报告的网卡 */u16_t response_pkt_len; /* ICMP数据区长度 *//* 增加试图发送的消息数 */MIB2_STATS_INC(mib2.icmpoutmsgs);/* IP头+8 */response_pkt_len = IP_HLEN + ICMP_DEST_UNREACH_DATASIZE;if (p->tot_len < response_pkt_len) { /* 如果触发ICMP差错报告的IP报文pbuf数据区不够8,就全部上传即可 。*/response_pkt_len = p->tot_len;}/* 申请ICMP差错报告的pbuf资源,长度为ICMP差错报告首部+数据区*/q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + response_pkt_len, PBUF_RAM);if (q == NULL) {LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n"));MIB2_STATS_INC(mib2.icmpouterrors);return;}LWIP_ASSERT("check that first pbuf can hold icmp message",(q->len >= (sizeof(struct icmp_echo_hdr) + response_pkt_len)));iphdr = (struct ip_hdr *)p->payload; /* 提取IP报文首部 */LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from "));ip4_addr_debug_print_val(ICMP_DEBUG, iphdr->src);LWIP_DEBUGF(ICMP_DEBUG, (" to "));ip4_addr_debug_print_val(ICMP_DEBUG, iphdr->dest);LWIP_DEBUGF(ICMP_DEBUG, ("\n"));icmphdr = (struct icmp_echo_hdr *)q->payload;icmphdr->type = type; /* 设置ICMP类型字段 */icmphdr->code = code; /* 设置ICMP代码字段 */icmphdr->id = 0; /* 设置ICMP标识字段 */icmphdr->seqno = 0; /* 设置ICMP序号字段 *//* 拷贝触发ICMP差错的IP报文首部+(<=8)字节的原数据到ICMP差错报告数据区 */SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload,response_pkt_len);ip4_addr_copy(iphdr_src, iphdr->src); /* 提取IP源地址 */#ifdef LWIP_HOOK_IP4_ROUTE_SRC{ip4_addr_t iphdr_dst;ip4_addr_copy(iphdr_dst, iphdr->dest); /* 提取IP目的地址 */netif = ip4_route_src(&iphdr_dst, &iphdr_src); /* 路由匹配网卡 */}#elsenetif = ip4_route(&iphdr_src); /* 路由匹配网卡 */#endifif (netif != NULL) { /* 匹配网卡成功 */icmphdr->chksum = 0; /* ICMP校验和字段 */#if CHECKSUM_GEN_ICMPIF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP) {icmphdr->chksum = inet_chksum(icmphdr, q->len); /* 计算ICMP校验和 */}#endifICMP_STATS_INC(icmp.xmit);/* 通过指定网卡把ICMP报文转交到IP层发送出去 */ip4_output_if(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP, netif);}/* 释放ICMP报文资源 */pbuf_free(q);}10.6.2 icmp_dest_unreach()目的不可达差错报告icmp_dest_unreach()
  • struct pbuf *p:目的不可达的pbuf包 。
  • enum icmp_dur_type t:目的不可达的原因 。
/** * Send an icmp 'destination unreachable' packet, called from ip_input() if * the transport layer protocol is unknown and from udp_input() if the local * port is not bound. * * @param p the input packet for which the 'unreachable' should be sent, *p->payload pointing to the IP header * @param t type of the 'unreachable' packet */voidicmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t){MIB2_STATS_INC(mib2.icmpoutdestunreachs);icmp_send_response(p, ICMP_DUR, t);}

经验总结扩展阅读