Index: src/core/pbuf.c
===================================================================
RCS file: /sources/lwip/lwip/src/core/pbuf.c,v
retrieving revision 1.88
diff -u -r1.88 pbuf.c
--- src/core/pbuf.c	30 Mar 2007 08:47:04 -0000	1.88
+++ src/core/pbuf.c	2 Apr 2007 19:57:33 -0000
@@ -115,7 +115,7 @@
   p = pbuf_pool;
 
   for(i = 0; i < PBUF_POOL_SIZE; ++i) {
-    p->next = (struct pbuf *)((u8_t *)p + PBUF_POOL_BUFSIZE + sizeof(struct pbuf));
+    p->next = (struct pbuf *)MEM_ALIGN((u8_t *)p + PBUF_POOL_BUFSIZE + sizeof(struct pbuf));
     p->len = p->tot_len = PBUF_POOL_BUFSIZE;
     p->payload = MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf)));
     p->flags = PBUF_FLAG_POOL;
@@ -740,251 +740,114 @@
   LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_FRESH | 2, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));
 }
 
-/* For packet queueing. Note that queued packets MUST be dequeued first
- * using pbuf_dequeue() before calling other pbuf_() functions. */
-#if ARP_QUEUEING
 /**
- * Add a packet to the end of a queue.
- *
- * @param q pointer to first packet on the queue
- * @param n packet to be queued
- *
- * Both packets MUST be given, and must be different.
- */
-void
-pbuf_queue(struct pbuf *p, struct pbuf *n)
-{
-#if PBUF_DEBUG /* remember head of queue */
-  struct pbuf *q = p;
-#endif
-  /* programmer stupidity checks */
-  LWIP_ASSERT("p == NULL in pbuf_queue: this indicates a programmer error\n", p != NULL);
-  LWIP_ASSERT("n == NULL in pbuf_queue: this indicates a programmer error\n", n != NULL);
-  LWIP_ASSERT("p == n in pbuf_queue: this indicates a programmer error\n", p != n);
-  if ((p == NULL) || (n == NULL) || (p == n)){
-    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_HALT | 3, ("pbuf_queue: programmer argument error\n"));
-    return;
-  }
-
-  /* iterate through all packets on queue */
-  while (p->next != NULL) {
-/* be very picky about pbuf chain correctness */
-#if PBUF_DEBUG
-    /* iterate through all pbufs in packet */
-    while (p->tot_len != p->len) {
-      /* make sure invariant condition holds */
-      LWIP_ASSERT("p->len < p->tot_len", p->len < p->tot_len);
-      /* make sure each packet is complete */
-      LWIP_ASSERT("p->next != NULL", p->next != NULL);
-      p = p->next;
-      /* { p->tot_len == p->len => p is last pbuf of a packet } */
-    }
-    /* { p is last pbuf of a packet } */
-    /* proceed to next packet on queue */
-#endif
-    /* proceed to next pbuf */
-    if (p->next != NULL) p = p->next;
-  }
-  /* { p->tot_len == p->len and p->next == NULL } ==>
-   * { p is last pbuf of last packet on queue } */
-  /* chain last pbuf of queue with n */
-  p->next = n;
-  /* n is now referenced to by the (packet p in the) queue */
-  pbuf_ref(n);
-#if PBUF_DEBUG
-  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_FRESH | 2,
-    ("pbuf_queue: newly queued packet %p sits after packet %p in queue %p\n",
-    (void *)n, (void *)p, (void *)q));
-#endif
-}
-
-/**
- * Remove a packet from the head of a queue.
- *
- * The caller MUST reference the remainder of the queue (as returned). The
- * caller MUST NOT call pbuf_ref() as it implicitly takes over the reference
- * from p.
- * 
- * @param p pointer to first packet on the queue which will be dequeued.
- * @return first packet on the remaining queue (NULL if no further packets).
+ * Dechains the first pbuf from its succeeding pbufs in the chain.
  *
+ * Makes p->tot_len field equal to p->len.
+ * @param p pbuf to dechain
+ * @return remainder of the pbuf chain, or NULL if it was de-allocated.
+ * @note May not be called on a packet queue.
  */
 struct pbuf *
-pbuf_dequeue(struct pbuf *p)
+pbuf_dechain(struct pbuf *p)
 {
   struct pbuf *q;
-  LWIP_ASSERT("p != NULL", p != NULL);
-
-  /* iterate through all pbufs in packet p */
-  while (p->tot_len != p->len) {
-    /* make sure invariant condition holds */
-    LWIP_ASSERT("p->len < p->tot_len", p->len < p->tot_len);
-    /* make sure each packet is complete */
-    LWIP_ASSERT("p->next != NULL", p->next != NULL);
-    p = p->next;
-  }
-  /* { p->tot_len == p->len } => p is the last pbuf of the first packet */
-  /* remember next packet on queue in q */
+  u8_t tail_gone = 1;
+  /* tail */
   q = p->next;
-  /* dequeue packet p from queue */
-  p->next = NULL;
-  /* any next packet on queue? */
+  /* pbuf has successor in chain? */
   if (q != NULL) {
-    /* although q is no longer referenced by p, it MUST be referenced by
-     * the caller, who is maintaining this packet queue. So, we do not call
-     * pbuf_free(q) here, resulting in an implicit pbuf_ref(q) for the caller. */
-    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_FRESH | 2, ("pbuf_dequeue: first remaining packet on queue is %p\n", (void *)q));
-  } else {
-    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_FRESH | 2, ("pbuf_dequeue: no further packets on queue\n"));
+    /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
+    LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len);
+    /* enforce invariant if assertion is disabled */
+    q->tot_len = p->tot_len - p->len;
+    /* decouple pbuf from remainder */
+    p->next = NULL;
+    /* total length of pbuf p is its own length only */
+    p->tot_len = p->len;
+    /* q is no longer referenced by p, free it */
+    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_STATE, ("pbuf_dechain: unreferencing %p\n", (void *)q));
+    tail_gone = pbuf_free(q);
+    if (tail_gone > 0) {
+      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_STATE,
+                  ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));
+    }
+    /* return remaining tail or NULL if deallocated */
   }
-  return q;
+  /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
+  LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len);
+  return (tail_gone > 0? NULL: q);
 }
-#endif
 
+#if ARP_QUEUEING
 /**
  *
- * Create PBUF_POOL (or PBUF_RAM) copies of PBUF_REF pbufs.
+ * Create PBUF_RAM copies of pbufs.
  *
  * Used to queue packets on behalf of the lwIP stack, such as
  * ARP based queueing.
  *
- * Go through a pbuf chain and replace any PBUF_REF buffers
- * with PBUF_POOL (or PBUF_RAM) pbufs, each taking a copy of
- * the referenced data.
- *
  * @note You MUST explicitly use p = pbuf_take(p);
- * The pbuf you give as argument, may have been replaced
- * by a (differently located) copy through pbuf_take()!
  *
- * @note Any replaced pbufs will be freed through pbuf_free().
- * This may deallocate them if they become no longer referenced.
+ * @note Only one packet is copied, no packet queue!
  *
  * @param p Head of pbuf chain to process
  *
  * @return Pointer to head of pbuf chain
  */
 struct pbuf *
-pbuf_take(struct pbuf *p)
+pbuf_copy(struct pbuf *p)
 {
-  struct pbuf *q , *prev, *head;
-  LWIP_ASSERT("pbuf_take: p != NULL\n", p != NULL);
-  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_take(%p)\n", (void*)p));
+  u16_t count=0;
+  struct pbuf *q, *r;
+  u16_t rem_len=0;
+  LWIP_ASSERT("pbuf_copy: p != NULL\n", p != NULL);
+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_copy(%p)\n", (void*)p));
+
+  /* allocate one pbuf to hold the complete packet */
+  q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_POOL);
+  if(q == NULL) {
+    /* out of memory */
+    return NULL;
+  }
 
-  prev = NULL;
-  head = p;
   /* iterate through pbuf chain */
+  rem_len = q->len;
+  r = q;
   do
   {
-    /* pbuf is of type PBUF_REF? */
-    if (p->flags == PBUF_FLAG_REF) {
-      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_take: encountered PBUF_REF %p\n", (void *)p));
-      /* allocate a pbuf (w/ payload) fully in RAM */
-      /* PBUF_POOL buffers are faster if we can use them */
-      if (p->len <= PBUF_POOL_BUFSIZE) {
-        q = pbuf_alloc(PBUF_RAW, p->len, PBUF_POOL);
-        if (q == NULL) {
-          LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_POOL\n"));
-        }
-      } else {
-        /* no replacement pbuf yet */
-        q = NULL;
-        LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 2, ("pbuf_take: PBUF_POOL too small to replace PBUF_REF\n"));
-      }
-      /* no (large enough) PBUF_POOL was available? retry with PBUF_RAM */
-      if (q == NULL) {
-        q = pbuf_alloc(PBUF_RAW, p->len, PBUF_RAM);
-        if (q == NULL) {
-          LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_RAM\n"));
-        }
-      }
-      /* replacement pbuf could be allocated? */
-      if (q != NULL)
-      {
-        /* copy p to q */
-        /* copy successor */
-        q->next = p->next;
-        /* remove linkage from original pbuf */
-        p->next = NULL;
-        /* remove linkage to original pbuf */
-        if (prev != NULL) {
-          /* prev->next == p at this point */
-          LWIP_ASSERT("prev->next == p", prev->next == p);
-          /* break chain and insert new pbuf instead */
-          prev->next = q;
-        /* prev == NULL, so we replaced the head pbuf of the chain */
-        } else {
-          head = q;
-        }
-        /* copy pbuf payload */
-        memcpy(q->payload, p->payload, p->len);
-        q->tot_len = p->tot_len;
-        q->len = p->len;
-        /* in case p was the first pbuf, it is no longer refered to by
-         * our caller, as the caller MUST do p = pbuf_take(p);
-         * in case p was not the first pbuf, it is no longer refered to
-         * by prev. we can safely free the pbuf here.
-         * (note that we have set p->next to NULL already so that
-         * we will not free the rest of the chain by accident.)
-         */
-        pbuf_free(p);
-        /* do not copy ref, since someone else might be using the old buffer */
-        LWIP_DEBUGF(PBUF_DEBUG, ("pbuf_take: replaced PBUF_REF %p with %p\n", (void *)p, (void *)q));
-        p = q;
-      } else {
-        /* deallocate chain */
-        pbuf_free(head);
-        LWIP_DEBUGF(PBUF_DEBUG | 2, ("pbuf_take: failed to allocate replacement pbuf for %p\n", (void *)p));
+    if(p->len > rem_len) {
+      u16_t old_len = rem_len;
+      /* copy pbuf payload partial to old q */
+      memcpy((char*)q->payload + count, p->payload, rem_len);
+      /* copy rest of pbuf payload to next q */
+      q = q->next;
+      if(q == NULL) {
+        /* this should not happen! */
+        pbuf_free(q);
         return NULL;
       }
-    /* p->flags != PBUF_FLAG_REF */
+      count = 0;
+      memcpy((char*)q->payload, (char*)p->payload + old_len, p->len - old_len);
+      //rem_len = q->len - sadfsadf;
+      count += old_len;
     } else {
-      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 1, ("pbuf_take: skipping pbuf not of type PBUF_REF\n"));
+      /* copy whole pbuf payload */
+      memcpy((char*)q->payload + count, p->payload, p->len);
+      rem_len -= p->len;
+      count += p->len;
     }
-    /* remember this pbuf */
-    prev = p;
+    LWIP_DEBUGF(PBUF_DEBUG, ("pbuf_copy: copied pbuf %p\n", (void *)p));
+
     /* proceed to next pbuf in original chain */
+    if(p->len == p->tot_len) {
+      /* don't copy more than one packet! */
+      break;
+    }
     p = p->next;
   } while (p);
-  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 1, ("pbuf_take: end of chain reached.\n"));
+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 1, ("pbuf_copy: end of chain reached.\n"));
 
-  return head;
-}
-
-/**
- * Dechains the first pbuf from its succeeding pbufs in the chain.
- *
- * Makes p->tot_len field equal to p->len.
- * @param p pbuf to dechain
- * @return remainder of the pbuf chain, or NULL if it was de-allocated.
- * @note May not be called on a packet queue.
- */
-struct pbuf *
-pbuf_dechain(struct pbuf *p)
-{
-  struct pbuf *q;
-  u8_t tail_gone = 1;
-  /* tail */
-  q = p->next;
-  /* pbuf has successor in chain? */
-  if (q != NULL) {
-    /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
-    LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len);
-    /* enforce invariant if assertion is disabled */
-    q->tot_len = p->tot_len - p->len;
-    /* decouple pbuf from remainder */
-    p->next = NULL;
-    /* total length of pbuf p is its own length only */
-    p->tot_len = p->len;
-    /* q is no longer referenced by p, free it */
-    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_STATE, ("pbuf_dechain: unreferencing %p\n", (void *)q));
-    tail_gone = pbuf_free(q);
-    if (tail_gone > 0) {
-      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_STATE,
-                  ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));
-    }
-    /* return remaining tail or NULL if deallocated */
-  }
-  /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
-  LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len);
-  return (tail_gone > 0? NULL: q);
+  return q;
 }
+#endif /* ARP_QUEUEING */
Index: src/include/lwip/pbuf.h
===================================================================
RCS file: /sources/lwip/lwip/src/include/lwip/pbuf.h,v
retrieving revision 1.19
diff -u -r1.19 pbuf.h
--- src/include/lwip/pbuf.h	5 May 2004 14:12:28 -0000	1.19
+++ src/include/lwip/pbuf.h	22 Mar 2007 21:02:42 -0000
@@ -105,9 +105,9 @@
 u8_t pbuf_clen(struct pbuf *p);  
 void pbuf_cat(struct pbuf *h, struct pbuf *t);
 void pbuf_chain(struct pbuf *h, struct pbuf *t);
-struct pbuf *pbuf_take(struct pbuf *f);
 struct pbuf *pbuf_dechain(struct pbuf *p);
-void pbuf_queue(struct pbuf *p, struct pbuf *n);
-struct pbuf * pbuf_dequeue(struct pbuf *p);
+#if ARP_QUEUEING
+struct pbuf *pbuf_copy(struct pbuf *f);
+#endif
 
 #endif /* __LWIP_PBUF_H__ */
Index: src/netif/etharp.c
===================================================================
RCS file: /sources/lwip/lwip/src/netif/etharp.c,v
retrieving revision 1.103
diff -u -r1.103 etharp.c
--- src/netif/etharp.c	30 Mar 2007 08:47:05 -0000	1.103
+++ src/netif/etharp.c	2 Apr 2007 19:20:14 -0000
@@ -756,6 +756,8 @@
  * @param q If non-NULL, a pbuf that must be delivered to the IP address.
  * q is not freed by this function.
  *
+ * @note q must only be ONE packet, not a packet queue!
+ *
  * @return
  * - ERR_BUF Could not make room for Ethernet header.
  * - ERR_MEM Hardware address unknown, and no more ARP entries available
@@ -828,21 +830,38 @@
     } else if (arp_table[i].state == ETHARP_STATE_PENDING) {
 #if ARP_QUEUEING /* queue the given q packet */
       struct pbuf *p;
-      /* copy any PBUF_REF referenced payloads into PBUF_RAM */
-      /* (the caller of lwIP assumes the referenced payload can be
-       * 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);
+      int have_ref = 0;
+      /* IF q includes a PBUF_REF, we have no choice but to copy the whole
+       * queue into PBUF_RAMs (see bug #11400) 
+       * PBUF_ROMs can be left as they are, since ROM must not get changed */
+      p = q;
+      while(p) {
+        if(p->len == p->tot_len) {
+          LWIP_ASSERT("no packet queues allowed!", p->next == 0);
+        }
+        if(p->flags == PBUF_FLAG_REF) {
+          have_ref = 1;
+          break;
+        }
+        p = p->next;
+      }
+      if(have_ref) {
+        /* copy the whole packet into new pbufs */
+        p = pbuf_copy(q);
+      } else {
+        /* referencing the old pbuf is enough */
+        p = q;
+        pbuf_ref(p);
+     }
       /* packet could be taken over? */
       if (p != NULL) {
         /* queue packet ... */
-        struct etharp_q_entry *newEntry;
+        struct etharp_q_entry *new_entry;
         /* 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);
+        new_entry = memp_malloc(MEMP_ARP_QUEUE);
+        LWIP_ASSERT("newEntry != NULL", new_entry != NULL);
+        new_entry->next = 0;
+        new_entry->p = p;
         if(arp_table[i].q != NULL) {
           /* queue was already existent, append the new entry to the end */
           struct etharp_q_entry *r;
@@ -850,10 +869,10 @@
           while(r->next != NULL) {
             r = r->next;
           }
-          r->next = newEntry;
+          r->next = new_entry;
         } else {
           /* queue did not exist, first item in queue */
-          arp_table[i].q = newEntry;
+          arp_table[i].q = new_entry;
         }
         LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
         result = ERR_OK;
