diff --git a/CHANGELOG b/CHANGELOG index 35c69379..3ef91269 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -129,6 +129,11 @@ HISTORY ++ Bug fixes: + 2007-05-04 Simon Goldschmidt + * pbuf.c, pbuf.h, etharp.c: Further update to ARP queueing: Changed pbuf_copy() + implementation so that it can be reused (don't allocate the target + pbuf inside pbuf_copy()). + 2007-05-04 Simon Goldschmidt * memp.c: checked in patch #5913: in memp_malloc() we can return memp as mem to save a little RAM (next pointer of memp is not used while not in pool). diff --git a/src/core/pbuf.c b/src/core/pbuf.c index 76ee2e8f..f68fd2f8 100644 --- a/src/core/pbuf.c +++ b/src/core/pbuf.c @@ -775,39 +775,73 @@ pbuf_dechain(struct pbuf *p) * * @return Pointer to head of pbuf chain */ -struct pbuf * -pbuf_copy(struct pbuf *p) +err_t +pbuf_copy(struct pbuf *p_to, struct pbuf *p_from) { - u16_t copied=0; - struct pbuf *p_copy; - LWIP_ASSERT("pbuf_copy: p != NULL\n", p != NULL); - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_copy(%p)\n", (void*)p)); + u16_t offset_to=0, offset_from=0, len; +#ifdef LWIP_DEBUG + u16_t copied=0, shouldbe; +#endif - /* allocate one pbuf to hold the complete packet */ - p_copy = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); - if(p_copy == NULL) { - /* out of memory */ - return NULL; + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_copy(%p, %p)\n", p_to, p_from)); + + /* is the target big enough to hold the source? */ + if ((p_to == NULL) || (p_from == NULL) || (p_to->tot_len < p_from->tot_len)) { + LWIP_ASSERT("pbuf_copy: p_to != NULL\n", p_to != NULL); + LWIP_ASSERT("pbuf_copy: p_from != NULL\n", p_from != NULL); + LWIP_ASSERT("pbuf_copy: p_to->tot_len >= p_from->tot_len\n", p_to->tot_len >= p_from->tot_len); + return ERR_ARG; } +#ifdef LWIP_DEBUG + shouldbe = p_from->tot_len; +#endif /* iterate through pbuf chain */ do { + LWIP_ASSERT("p_to != NULL", p_to != NULL); /* copy one part of the original chain */ - memcpy((char*)p_copy->payload + copied, p->payload, p->len); - copied += p->len; - LWIP_DEBUGF(PBUF_DEBUG, ("pbuf_copy: copied pbuf %p\n", (void *)p)); + if ((p_to->len - offset_to) >= (p_from->len - offset_from)) { + /* complete current p_from fits into current p_to */ + len = p_from->len - offset_from; + } else { + /* current p_from does not fit into current p_to */ + len = p_to->len - offset_to; + } + memcpy((u8_t*)p_to->payload + offset_to, (u8_t*)p_from->payload + offset_from, len); +#ifdef LWIP_DEBUG + copied += len; +#endif + offset_to += len; + offset_from += len; + LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len); + if (offset_to == p_to->len) { + /* on to next p_to (if any) */ + offset_to = 0; + p_to = p_to->next; + } + LWIP_ASSERT("offset_from <= p_from->len", offset_to <= p_from->len); + if (offset_from >= p_from->len) { + /* on to next p_from (if any) */ + offset_from = 0; + p_from = p_from->next; + } - if(p->len == p->tot_len) { + if((p_from != NULL) && (p_from->len == p_from->tot_len)) { /* don't copy more than one packet! */ LWIP_ASSERT("pbuf_copy() does not allow packet queues!\n", - p->next == NULL); + p_from->next == NULL); } - /* proceed to next pbuf in original chain */ - p = p->next; - } while (p); + if((p_to != NULL) && (p_to->len == p_to->tot_len)) { + /* don't copy more than one packet! */ + LWIP_ASSERT("pbuf_copy() does not allow packet queues!\n", + p_to->next == NULL); + } + } while (p_from); LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 1, ("pbuf_copy: end of chain reached.\n")); - - return p_copy; +#ifdef LWIP_DEBUG + LWIP_ASSERT("shouldbe == copied", shouldbe == copied); +#endif + return ERR_OK; } #endif /* ARP_QUEUEING */ diff --git a/src/include/lwip/pbuf.h b/src/include/lwip/pbuf.h index bd7bb8ed..06173b5a 100644 --- a/src/include/lwip/pbuf.h +++ b/src/include/lwip/pbuf.h @@ -34,7 +34,7 @@ #define __LWIP_PBUF_H__ #include "arch/cc.h" - +#include "lwip/err.h" #define PBUF_TRANSPORT_HLEN 20 #define PBUF_IP_HLEN 20 @@ -107,7 +107,7 @@ void pbuf_cat(struct pbuf *h, struct pbuf *t); void pbuf_chain(struct pbuf *h, struct pbuf *t); struct pbuf *pbuf_dechain(struct pbuf *p); #if ARP_QUEUEING -struct pbuf *pbuf_copy(struct pbuf *f); +err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from); #endif #endif /* __LWIP_PBUF_H__ */ diff --git a/src/netif/etharp.c b/src/netif/etharp.c index 87f6e17b..1980faea 100644 --- a/src/netif/etharp.c +++ b/src/netif/etharp.c @@ -864,7 +864,11 @@ err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q) } if(copy_needed) { /* copy the whole packet into new pbufs */ - p = pbuf_copy(q); + p = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); + if (pbuf_copy(p, q) != ERR_OK) { + pbuf_free(p); + p = NULL; + } } else { /* referencing the old pbuf is enough */ p = q;