Corrected bug #19937: ICMP assumes p_buf has space for ethernet header. Allocating new pbuf if the input pbuf isn't big enough.

This commit is contained in:
goldsimon 2007-06-03 10:48:23 +00:00
parent d5a159d7af
commit 7abfe74fa4
2 changed files with 64 additions and 13 deletions

View File

@ -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

View File

@ -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