diff --git a/CHANGELOG b/CHANGELOG index 5952c5f6..4c90d1a1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -170,7 +170,13 @@ HISTORY ++ Bug fixes: - 2007-05-22 Simon Goldschmidt + 2007-06-03 Simon Goldschmidt + * icmp.c: Corrected bug #19937: For responding to an icmp echo request, icmp + re-used the input pbuf even if that didn't have enough space to include the + link headers. Now the space is tested and a new pbuf is allocated for the + echo response packet if the echo request pbuf isn't big enough. + + 2007-06-01 Simon Goldschmidt * sockets.c: Checked in patch #5914: Moved sockopt processing into tcpip_thread. 2007-05-23 Frédéric Bernon diff --git a/src/core/ipv4/icmp.c b/src/core/ipv4/icmp.c index 349d5efa..8cbc39dc 100644 --- a/src/core/ipv4/icmp.c +++ b/src/core/ipv4/icmp.c @@ -51,7 +51,7 @@ icmp_input(struct pbuf *p, struct netif *inp) struct icmp_echo_hdr *iecho; struct ip_hdr *iphdr; struct ip_addr tmpaddr; - u16_t hlen; + s16_t hlen; ICMP_STATS_INC(icmp.recv); snmp_inc_icmpinmsgs(); @@ -59,12 +59,9 @@ icmp_input(struct pbuf *p, struct netif *inp) iphdr = p->payload; hlen = IPH_HL(iphdr) * 4; - if (pbuf_header(p, -((s16_t)hlen)) || (p->tot_len < sizeof(u16_t)*2)) { + if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len)); - pbuf_free(p); - ICMP_STATS_INC(icmp.lenerr); - snmp_inc_icmpinerrors(); - return; + goto lenerr; } type = *((u8_t *)p->payload); @@ -81,13 +78,8 @@ icmp_input(struct pbuf *p, struct netif *inp) LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n")); if (p->tot_len < sizeof(struct icmp_echo_hdr)) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n")); - pbuf_free(p); - ICMP_STATS_INC(icmp.lenerr); - snmp_inc_icmpinerrors(); - - return; + goto lenerr; } - iecho = p->payload; if (inet_chksum_pbuf(p) != 0) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n")); pbuf_free(p); @@ -95,6 +87,48 @@ icmp_input(struct pbuf *p, struct netif *inp) snmp_inc_icmpinerrors(); return; } + if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) { + /* p is not big enough to contain link headers + * allocate a new one and copy p into it + */ + struct pbuf *r; + /* switch p->payload to ip header */ + if (pbuf_header(p, hlen)) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: moving p->payload to ip header failed\n")); + goto memerr; + } + /* allocate new packet buffer with space for link headers */ + r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); + if (r == NULL) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n")); + goto memerr; + } + /* copy the whole packet including ip header */ + if (pbuf_copy(r, p) != ERR_OK) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: copying to new pbuf failed\n")); + goto memerr; + } + iphdr = r->payload; + /* switch r->payload back to icmp header */ + if (pbuf_header(r, -hlen)) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: restoring original p->payload failed\n")); + goto memerr; + } + /* free the original p */ + pbuf_free(p); + /* we now have an identical copy of p that has room for link headers */ + p = r; + } else { + /* restore p->payload to point to icmp header */ + if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: restoring original p->payload failed\n")); + goto memerr; + } + } + /* At this point, all checks are OK. */ + /* We generate an answer by switching the dest and src ip addresses, + * setting the icmp type to ECHO_RESPONSE and updating the checksum. */ + iecho = p->payload; tmpaddr.addr = iphdr->src.addr; iphdr->src.addr = iphdr->dest.addr; iphdr->dest.addr = tmpaddr.addr; @@ -123,6 +157,17 @@ icmp_input(struct pbuf *p, struct netif *inp) ICMP_STATS_INC(icmp.drop); } pbuf_free(p); + return; +lenerr: + pbuf_free(p); + ICMP_STATS_INC(icmp.lenerr); + snmp_inc_icmpinerrors(); + return; +memerr: + pbuf_free(p); + ICMP_STATS_INC(icmp.err); + snmp_inc_icmpinerrors(); + return; } void