/* 发送一个ICMP差错报文 */ static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code) { struct pbuf *q; struct ip_hdr *iphdr; /* we can use the echo header here */ /* 用回显请求的首部描述差错报文首部 */ struct icmp_echo_hdr *icmphdr; /* ICMP header + IP header + 8 bytes of data */ /* 在IP层申请一个pbuf,会自动预留IP首部和以太网帧首部, * 申请的大小是回显请求首部 + 引起差错的IP数据报首部大小 + IP数据报载荷的前8字节 */ q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE, PBUF_RAM); if (q == NULL) { /* 申请失败,则返回 */ LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n")); return; } LWIP_ASSERT("check that first pbuf can hold icmp message", (q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE))); /* 指向引起差错的IP数据报 */ iphdr = p->payload; LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from ")); ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src)); LWIP_DEBUGF(ICMP_DEBUG, (" to ")); ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest)); LWIP_DEBUGF(ICMP_DEBUG, ("\n")); /* 指向ICMP报文首部 */ icmphdr = q->payload; /* 填写类型字段 */ icmphdr->type = type; /* 填写代码字段 */ icmphdr->code = code; /* ICMP首部第4-7字节填0 */ icmphdr->id = 0; icmphdr->seqno = 0; /* copy fields from original packet */ /* 复制引起差错的IP数据报首部+8字节到ICMP数据字段 */ SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload, IP_HLEN + ICMP_DEST_UNREACH_DATASIZE); /* calculate checksum */ /* 计算并填写校验和 */ icmphdr->chksum = 0; icmphdr->chksum = inet_chksum(icmphdr, q->len); ICMP_STATS_INC(icmp.xmit); /* increase number of messages attempted to send */ snmp_inc_icmpoutmsgs(); /* increase number of destination unreachable messages attempted to send */ snmp_inc_icmpouttimeexcds(); /* 调用IP层函数输出ICMP报文 */ ip_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP); /* 发送完成,释放申请的ICMP用的pbuf */ pbuf_free(q); }
void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t) { struct pbuf *q; struct ip_hdr *iphdr; struct icmp_te_hdr *tehdr; q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM); iphdr = p->payload; LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from ")); ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src)); LWIP_DEBUGF(ICMP_DEBUG, (" to ")); ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest)); LWIP_DEBUGF(ICMP_DEBUG, ("\n")); tehdr = q->payload; ICMPH_TYPE_SET(tehdr, ICMP_TE); ICMPH_CODE_SET(tehdr, t); /* copy fields from original packet */ memcpy((u8_t *)q->payload + 8, (u8_t *)p->payload, IP_HLEN + 8); /* calculate checksum */ tehdr->chksum = 0; tehdr->chksum = inet_chksum(tehdr, q->len); ICMP_STATS_INC(icmp.xmit); /* increase number of messages attempted to send */ snmp_inc_icmpoutmsgs(); /* increase number of destination unreachable messages attempted to send */ snmp_inc_icmpouttimeexcds(); ip_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP); pbuf_free(q); }
static struct netif * ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) { struct netif *netif; PERF_START; /* Find network interface where to forward this IP packet to. */ netif = ip_route((struct ip_addr *)&(iphdr->dest)); if (netif == NULL) { LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for 0x%"X32_F" found\n", iphdr->dest.addr)); snmp_inc_ipnoroutes(); return (struct netif *)NULL; } /* Do not forward packets onto the same network interface on which * they arrived. */ if (netif == inp) { LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n")); snmp_inc_ipnoroutes(); return (struct netif *)NULL; } /* decrement TTL */ IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1); /* send ICMP if TTL == 0 */ if (IPH_TTL(iphdr) == 0) { /* Don't send ICMP messages in response to ICMP messages */ if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) { icmp_time_exceeded(p, ICMP_TE_TTL); snmp_inc_icmpouttimeexcds(); } return (struct netif *)NULL; } /* Incrementally update the IP checksum. */ if (IPH_CHKSUM(iphdr) >= htons(0xffff - 0x100)) { IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100) + 1); } else { IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100)); } LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to 0x%"X32_F"\n", iphdr->dest.addr)); IP_STATS_INC(ip.fw); IP_STATS_INC(ip.xmit); snmp_inc_ipforwdatagrams(); PERF_STOP("ip_forward"); /* transmit pbuf on chosen interface */ netif->output(netif, p, (struct ip_addr *)&(iphdr->dest)); return netif; }
/** * 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 void icmp_send_response(struct pbuf *p, u8_t type, u8_t code) { struct pbuf *q; struct ip_hdr *iphdr; /* we can use the echo header here */ struct icmp_echo_hdr *icmphdr; /* ICMP header + IP header + 8 bytes of data */ q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE, PBUF_RAM); if (q == NULL) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n")); return; } LWIP_ASSERT("check that first pbuf can hold icmp message", (q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE))); iphdr = p->payload; LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from ")); ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src)); LWIP_DEBUGF(ICMP_DEBUG, (" to ")); ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest)); LWIP_DEBUGF(ICMP_DEBUG, ("\n")); icmphdr = q->payload; icmphdr->type = type; icmphdr->code = code; icmphdr->id = 0; icmphdr->seqno = 0; /* copy fields from original packet */ SMEMCPY((u8_t *) q->payload + sizeof(struct icmp_echo_hdr), (u8_t *) p->payload, IP_HLEN + ICMP_DEST_UNREACH_DATASIZE); /* calculate checksum */ icmphdr->chksum = 0; icmphdr->chksum = inet_chksum(icmphdr, q->len); ICMP_STATS_INC(icmp.xmit); /* increase number of messages attempted to send */ snmp_inc_icmpoutmsgs(); /* increase number of destination unreachable messages attempted to send */ snmp_inc_icmpouttimeexcds(); ip_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP); pbuf_free(q); }
/** * 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 void ICACHE_FLASH_ATTR icmp_send_response(struct pbuf *p, u8_t type, u8_t code) { struct pbuf *q; struct ip_hdr *iphdr; /* we can use the echo header here */ struct icmp_echo_hdr *icmphdr; ip_addr_t iphdr_src; /* ICMP header + IP header + 8 bytes of data */ //为差错报文申请pbuf空间,pbuf中预留IP首部和以太网首部空间,pbuf数据区 //长度=差错报文首部+差错报文数据长度(IP首部长度+8) q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE, PBUF_RAM); if (q == NULL) {//失败,返回 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n")); return; } LWIP_ASSERT("check that first pbuf can hold icmp message", (q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE))); iphdr = (struct ip_hdr *)p->payload;//指向引起差错的IP数据包首部 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from ")); ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src)); LWIP_DEBUGF(ICMP_DEBUG, (" to ")); ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest)); LWIP_DEBUGF(ICMP_DEBUG, ("\n")); icmphdr = (struct icmp_echo_hdr *)q->payload;//指向差错报文首部 icmphdr->type = type;//填写类型字段 icmphdr->code = code;//填写代码字段 icmphdr->id = 0;//对于目的不可达和数据报超时 icmphdr->seqno = 0;//报文,首部剩余的4个字节都为0 /* copy fields from original packet 将引起差错的IP数据报的IP首部+8字节数据拷贝到差错报文数据区*/ SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload, IP_HLEN + ICMP_DEST_UNREACH_DATASIZE); /* calculate checksum */ icmphdr->chksum = 0;//报文校验和字段清0 icmphdr->chksum = inet_chksum(icmphdr, q->len);//计算填写校验和 ICMP_STATS_INC(icmp.xmit); /* increase number of messages attempted to send */ snmp_inc_icmpoutmsgs(); /* increase number of destination unreachable messages attempted to send */ snmp_inc_icmpouttimeexcds(); ip_addr_copy(iphdr_src, iphdr->src); ip_output(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP);//调用IP层函数输出ICMP报文 pbuf_free(q); }
/** * Send a 'time exceeded' packet, called from ip_forward() if TTL is 0. * * @param p the input packet for which the 'time exceeded' should be sent, * p->payload pointing to the IP header * @param t type of the 'time exceeded' packet */ void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t) { struct pbuf *q; struct ip_hdr *iphdr; struct icmp_te_hdr *tehdr; /* ICMP header + IP header + 8 bytes of data */ q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE, PBUF_RAM); if (q == NULL) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n")); return; } LWIP_ASSERT("check that first pbuf can hold icmp message", (q->len >= (sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE))); iphdr = (struct ip_hdr *) p->payload; LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from ")); ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src)); LWIP_DEBUGF(ICMP_DEBUG, (" to ")); ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest)); LWIP_DEBUGF(ICMP_DEBUG, ("\n")); tehdr = (struct icmp_te_hdr *) q->payload; ICMPH_TYPE_SET(tehdr, ICMP_TE); ICMPH_CODE_SET(tehdr, t); /* copy fields from original packet */ SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_dur_hdr), (u8_t *)p->payload, IP_HLEN + ICMP_DEST_UNREACH_DATASIZE); /* calculate checksum */ tehdr->chksum = 0; tehdr->chksum = inet_chksum(tehdr, q->len); ICMP_STATS_INC(icmp.xmit); /* increase number of messages attempted to send */ snmp_inc_icmpoutmsgs(); /* increase number of destination unreachable messages attempted to send */ snmp_inc_icmpouttimeexcds(); ip_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP); pbuf_free(q); }