Fix BUG#11400 - don't corrupt existing pbuf chain when enqueuing multiple pbufs to a pending ARP request

This commit is contained in:
goldsimon 2007-03-04 12:12:42 +00:00
parent e1b6a4cb21
commit 1f544e087b
6 changed files with 93 additions and 28 deletions

View File

@ -42,6 +42,10 @@ HISTORY
++ Bug fixes: ++ Bug fixes:
2007-03-04 Simon Goldschmidt
* etharp.c, etharp.h, memp.c, memp.h, opt.h: Fix BUG#11400 - don't corrupt
existing pbuf chain when enqueuing multiple pbufs to a pending ARP request
2007-03-03 Frédéric Bernon 2007-03-03 Frédéric Bernon
* udp.c: remove obsolete line "static struct udp_pcb *pcb_cache = NULL;" * udp.c: remove obsolete line "static struct udp_pcb *pcb_cache = NULL;"
Its is static, and never used in udp.c except udp_init(). Its is static, and never used in udp.c except udp_init().

View File

@ -45,6 +45,10 @@
#include "lwip/sys.h" #include "lwip/sys.h"
#include "lwip/stats.h" #include "lwip/stats.h"
#if ARP_QUEUEING
#include "netif/etharp.h"
#endif
struct memp { struct memp {
struct memp *next; struct memp *next;
}; };
@ -63,6 +67,9 @@ static const u16_t memp_sizes[MEMP_MAX] = {
MEM_ALIGN_SIZE(sizeof(struct netbuf)), MEM_ALIGN_SIZE(sizeof(struct netbuf)),
MEM_ALIGN_SIZE(sizeof(struct netconn)), MEM_ALIGN_SIZE(sizeof(struct netconn)),
MEM_ALIGN_SIZE(sizeof(struct tcpip_msg)), MEM_ALIGN_SIZE(sizeof(struct tcpip_msg)),
#if ARP_QUEUEING
MEM_ALIGN_SIZE(sizeof(struct etharp_q_entry)),
#endif
MEM_ALIGN_SIZE(sizeof(struct sys_timeo)) MEM_ALIGN_SIZE(sizeof(struct sys_timeo))
}; };
@ -76,6 +83,9 @@ static const u16_t memp_num[MEMP_MAX] = {
MEMP_NUM_NETBUF, MEMP_NUM_NETBUF,
MEMP_NUM_NETCONN, MEMP_NUM_NETCONN,
MEMP_NUM_TCPIP_MSG, MEMP_NUM_TCPIP_MSG,
#if ARP_QUEUEING
MEMP_NUM_ARP_QUEUE,
#endif
MEMP_NUM_SYS_TIMEOUT MEMP_NUM_SYS_TIMEOUT
}; };
@ -92,6 +102,9 @@ static u8_t memp_memory[MEM_ALIGNMENT - 1 +
MEMP_TYPE_SIZE(MEMP_NUM_NETBUF, struct netbuf) + MEMP_TYPE_SIZE(MEMP_NUM_NETBUF, struct netbuf) +
MEMP_TYPE_SIZE(MEMP_NUM_NETCONN, struct netconn) + MEMP_TYPE_SIZE(MEMP_NUM_NETCONN, struct netconn) +
MEMP_TYPE_SIZE(MEMP_NUM_TCPIP_MSG, struct tcpip_msg) + MEMP_TYPE_SIZE(MEMP_NUM_TCPIP_MSG, struct tcpip_msg) +
#if ARP_QUEUEING
MEMP_TYPE_SIZE(MEMP_NUM_TCPIP_MSG, struct etharp_q_entry) +
#endif
MEMP_TYPE_SIZE(MEMP_NUM_SYS_TIMEOUT, struct sys_timeo)]; MEMP_TYPE_SIZE(MEMP_NUM_SYS_TIMEOUT, struct sys_timeo)];
#if !SYS_LIGHTWEIGHT_PROT #if !SYS_LIGHTWEIGHT_PROT

View File

@ -46,7 +46,9 @@ typedef enum {
MEMP_NETBUF, MEMP_NETBUF,
MEMP_NETCONN, MEMP_NETCONN,
MEMP_TCPIP_MSG, MEMP_TCPIP_MSG,
#if ARP_QUEUEING
MEMP_ARP_QUEUE,
#endif
MEMP_SYS_TIMEOUT, MEMP_SYS_TIMEOUT,
MEMP_MAX MEMP_MAX

View File

@ -107,6 +107,12 @@ a lot of data that needs to be copied, this should be set high. */
#ifndef MEMP_NUM_TCP_SEG #ifndef MEMP_NUM_TCP_SEG
#define MEMP_NUM_TCP_SEG 16 #define MEMP_NUM_TCP_SEG 16
#endif #endif
/* MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing
packets (pbufs) that are waiting for an ARP request (to resolve
their destination address) to finish. */
#ifndef MEMP_NUM_ARP_QUEUE
#define MEMP_NUM_ARP_QUEUE 30
#endif
/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active /* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active
timeouts. */ timeouts. */
#ifndef MEMP_NUM_SYS_TIMEOUT #ifndef MEMP_NUM_SYS_TIMEOUT

View File

@ -113,6 +113,15 @@ PACK_STRUCT_END
#define ETHTYPE_ARP 0x0806 #define ETHTYPE_ARP 0x0806
#define ETHTYPE_IP 0x0800 #define ETHTYPE_IP 0x0800
#if ARP_QUEUEING
/** struct for queueing outgoing packets for unknown address
* defined here to be accessed by memp.h
*/
struct etharp_q_entry {
struct etharp_q_entry *next;
struct pbuf *p;
};
#endif
void etharp_init(void); void etharp_init(void);
void etharp_tmr(void); void etharp_tmr(void);

View File

@ -93,7 +93,7 @@ struct etharp_entry {
/** /**
* Pointer to queue of pending outgoing packets on this ARP entry. * Pointer to queue of pending outgoing packets on this ARP entry.
*/ */
struct pbuf *p; struct etharp_q_entry *q;
#endif #endif
struct ip_addr ipaddr; struct ip_addr ipaddr;
struct eth_addr ethaddr; struct eth_addr ethaddr;
@ -123,13 +123,29 @@ etharp_init(void)
for(i = 0; i < ARP_TABLE_SIZE; ++i) { for(i = 0; i < ARP_TABLE_SIZE; ++i) {
arp_table[i].state = ETHARP_STATE_EMPTY; arp_table[i].state = ETHARP_STATE_EMPTY;
#if ARP_QUEUEING #if ARP_QUEUEING
arp_table[i].p = NULL; arp_table[i].q = NULL;
#endif #endif
arp_table[i].ctime = 0; arp_table[i].ctime = 0;
arp_table[i].netif = NULL; arp_table[i].netif = NULL;
} }
} }
#if ARP_QUEUEING
/** Free a complete queue of etharp entrys */
static void free_etharp_q(struct etharp_q_entry *q)
{
struct etharp_q_entry *r;
LWIP_ASSERT("q != NULL", q != NULL);
LWIP_ASSERT("q->p != NULL", q->p != NULL);
while(q) {
r = q;
q = q->next;
pbuf_free(r->p);
memp_free(MEMP_ARP_QUEUE, r);
}
}
#endif
/** /**
* Clears expired entries in the ARP table. * Clears expired entries in the ARP table.
* *
@ -158,7 +174,7 @@ etharp_tmr(void)
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired pending entry %"U16_F".\n", (u16_t)i)); LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired pending entry %"U16_F".\n", (u16_t)i));
arp_table[i].state = ETHARP_STATE_EXPIRED; arp_table[i].state = ETHARP_STATE_EXPIRED;
#if ARP_QUEUEING #if ARP_QUEUEING
} else if (arp_table[i].p != NULL) { } else if (arp_table[i].q != NULL) {
/* resend an ARP query here */ /* resend an ARP query here */
#endif #endif
} }
@ -169,11 +185,11 @@ etharp_tmr(void)
snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr); snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr);
#if ARP_QUEUEING #if ARP_QUEUEING
/* and empty packet queue */ /* and empty packet queue */
if (arp_table[i].p != NULL) { if (arp_table[i].q != NULL) {
/* remove all queued packets */ /* remove all queued packets */
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].p))); LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q)));
pbuf_free(arp_table[i].p); free_etharp_q(arp_table[i].q);
arp_table[i].p = NULL; arp_table[i].q = NULL;
} }
#endif #endif
/* recycle entry for re-use */ /* recycle entry for re-use */
@ -247,7 +263,7 @@ static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags)
return i; return i;
#if ARP_QUEUEING #if ARP_QUEUEING
/* pending with queued packets? */ /* pending with queued packets? */
} else if (arp_table[i].p != NULL) { } else if (arp_table[i].q != NULL) {
if (arp_table[i].ctime >= age_queue) { if (arp_table[i].ctime >= age_queue) {
old_queue = i; old_queue = i;
age_queue = arp_table[i].ctime; age_queue = arp_table[i].ctime;
@ -304,7 +320,7 @@ static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags)
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i)); LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i));
#if ARP_QUEUEING #if ARP_QUEUEING
/* no queued packets should exist on stable entries */ /* no queued packets should exist on stable entries */
LWIP_ASSERT("arp_table[i].p == NULL", arp_table[i].p == NULL); LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL);
#endif #endif
/* 3) found recyclable pending entry without queued packets? */ /* 3) found recyclable pending entry without queued packets? */
} else if (old_pending < ARP_TABLE_SIZE) { } else if (old_pending < ARP_TABLE_SIZE) {
@ -316,9 +332,9 @@ static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags)
} else if (old_queue < ARP_TABLE_SIZE) { } else if (old_queue < ARP_TABLE_SIZE) {
/* recycle oldest pending */ /* recycle oldest pending */
i = old_queue; i = old_queue;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].p))); LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q)));
pbuf_free(arp_table[i].p); free_etharp_q(arp_table[i].q);
arp_table[i].p = NULL; arp_table[i].q = NULL;
#endif #endif
/* no empty or recyclable entries found */ /* no empty or recyclable entries found */
} else { } else {
@ -405,14 +421,19 @@ update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *e
arp_table[i].ctime = 0; arp_table[i].ctime = 0;
/* this is where we will send out queued packets! */ /* this is where we will send out queued packets! */
#if ARP_QUEUEING #if ARP_QUEUEING
while (arp_table[i].p != NULL) { while (arp_table[i].q != NULL) {
/* get the first packet on the queue */ struct pbuf *p;
struct pbuf *p = arp_table[i].p; struct eth_hdr *ethhdr;
/* remember remainder of queue */
struct etharp_q_entry *q = arp_table[i].q;
/* pop first item off the queue */
arp_table[i].q = q->next;
/* get the packet pointer */
p = q->p;
/* now queue entry can be freed */
memp_free(MEMP_ARP_QUEUE, q);
/* Ethernet header */ /* Ethernet header */
struct eth_hdr *ethhdr = p->payload; ethhdr = p->payload;
/* remember (and reference) remainder of queue */
/* note: this will also terminate the p pbuf chain */
arp_table[i].p = pbuf_dequeue(p);
/* fill-in Ethernet header */ /* fill-in Ethernet header */
k = netif->hwaddr_len; k = netif->hwaddr_len;
while(k > 0) { while(k > 0) {
@ -810,19 +831,29 @@ err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
/* copy any PBUF_REF referenced payloads into PBUF_RAM */ /* copy any PBUF_REF referenced payloads into PBUF_RAM */
/* (the caller of lwIP assumes the referenced payload can be /* (the caller of lwIP assumes the referenced payload can be
* freed after it returns from the lwIP call that brought us here) */ * freed after it returns from the lwIP call that brought us here) */
/* @todo: if q->type == PBUF_REF, do we have a memory leak (since we call pbuf_ref(p) later)? */
p = pbuf_take(q); p = pbuf_take(q);
/* packet could be taken over? */ /* packet could be taken over? */
if (p != NULL) { if (p != NULL) {
/* queue packet ... */ /* queue packet ... */
if (arp_table[i].p == NULL) { struct etharp_q_entry *newEntry;
/* ... in the empty queue */ /* allocate a new arp queue entry */
newEntry = memp_malloc(MEMP_ARP_QUEUE);
LWIP_ASSERT("newEntry != NULL", newEntry != NULL);
newEntry->next = 0;
newEntry->p = p;
pbuf_ref(p); pbuf_ref(p);
arp_table[i].p = p; if(arp_table[i].q != NULL) {
#if 0 /* multi-packet-queueing disabled, see bug #11400 */ /* queue was already existent, append the new entry to the end */
struct etharp_q_entry *r;
r = arp_table[i].q;
while(r->next != NULL) {
r = r->next;
}
r->next = newEntry;
} else { } else {
/* ... at tail of non-empty queue */ /* queue did not exist, first item in queue */
pbuf_queue(arp_table[i].p, p); arp_table[i].q = newEntry;
#endif
} }
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
result = ERR_OK; result = ERR_OK;